github.com/SagerNet/gvisor@v0.0.0-20210707092255-7731c139d75c/test/syscalls/linux/eventfd.cc (about)

     1  // Copyright 2018 The gVisor Authors.
     2  //
     3  // Licensed under the Apache License, Version 2.0 (the "License");
     4  // you may not use this file except in compliance with the License.
     5  // You may obtain a copy of the License at
     6  //
     7  //     http://www.apache.org/licenses/LICENSE-2.0
     8  //
     9  // Unless required by applicable law or agreed to in writing, software
    10  // distributed under the License is distributed on an "AS IS" BASIS,
    11  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    12  // See the License for the specific language governing permissions and
    13  // limitations under the License.
    14  
    15  #include <errno.h>
    16  #include <pthread.h>
    17  #include <stdio.h>
    18  #include <stdlib.h>
    19  #include <string.h>
    20  #include <sys/epoll.h>
    21  #include <sys/stat.h>
    22  #include <sys/types.h>
    23  #include <unistd.h>
    24  
    25  #include "gtest/gtest.h"
    26  #include "test/util/epoll_util.h"
    27  #include "test/util/eventfd_util.h"
    28  #include "test/util/test_util.h"
    29  #include "test/util/thread_util.h"
    30  
    31  namespace gvisor {
    32  namespace testing {
    33  
    34  namespace {
    35  
    36  TEST(EventfdTest, Nonblock) {
    37    FileDescriptor efd =
    38        ASSERT_NO_ERRNO_AND_VALUE(NewEventFD(0, EFD_NONBLOCK | EFD_SEMAPHORE));
    39  
    40    uint64_t l;
    41    ASSERT_THAT(read(efd.get(), &l, sizeof(l)), SyscallFailsWithErrno(EAGAIN));
    42  
    43    l = 1;
    44    ASSERT_THAT(write(efd.get(), &l, sizeof(l)), SyscallSucceeds());
    45  
    46    l = 0;
    47    ASSERT_THAT(read(efd.get(), &l, sizeof(l)), SyscallSucceeds());
    48    EXPECT_EQ(l, 1);
    49  
    50    ASSERT_THAT(read(efd.get(), &l, sizeof(l)), SyscallFailsWithErrno(EAGAIN));
    51  }
    52  
    53  void* read_three_times(void* arg) {
    54    int efd = *reinterpret_cast<int*>(arg);
    55    uint64_t l;
    56    EXPECT_THAT(read(efd, &l, sizeof(l)), SyscallSucceedsWithValue(sizeof(l)));
    57    EXPECT_THAT(read(efd, &l, sizeof(l)), SyscallSucceedsWithValue(sizeof(l)));
    58    EXPECT_THAT(read(efd, &l, sizeof(l)), SyscallSucceedsWithValue(sizeof(l)));
    59    return nullptr;
    60  }
    61  
    62  TEST(EventfdTest, BlockingWrite) {
    63    FileDescriptor fd = ASSERT_NO_ERRNO_AND_VALUE(NewEventFD(0, EFD_SEMAPHORE));
    64    int efd = fd.get();
    65  
    66    pthread_t p;
    67    ASSERT_THAT(pthread_create(&p, nullptr, read_three_times,
    68                               reinterpret_cast<void*>(&efd)),
    69                SyscallSucceeds());
    70  
    71    uint64_t l = 1;
    72    ASSERT_THAT(write(efd, &l, sizeof(l)), SyscallSucceeds());
    73    EXPECT_EQ(l, 1);
    74  
    75    ASSERT_THAT(write(efd, &l, sizeof(l)), SyscallSucceeds());
    76    EXPECT_EQ(l, 1);
    77  
    78    ASSERT_THAT(write(efd, &l, sizeof(l)), SyscallSucceeds());
    79    EXPECT_EQ(l, 1);
    80  
    81    ASSERT_THAT(pthread_join(p, nullptr), SyscallSucceeds());
    82  }
    83  
    84  TEST(EventfdTest, SmallWrite) {
    85    FileDescriptor efd =
    86        ASSERT_NO_ERRNO_AND_VALUE(NewEventFD(0, EFD_NONBLOCK | EFD_SEMAPHORE));
    87  
    88    uint64_t l = 16;
    89    ASSERT_THAT(write(efd.get(), &l, 4), SyscallFailsWithErrno(EINVAL));
    90  }
    91  
    92  TEST(EventfdTest, SmallRead) {
    93    FileDescriptor efd =
    94        ASSERT_NO_ERRNO_AND_VALUE(NewEventFD(0, EFD_NONBLOCK | EFD_SEMAPHORE));
    95  
    96    uint64_t l = 1;
    97    ASSERT_THAT(write(efd.get(), &l, sizeof(l)), SyscallSucceeds());
    98  
    99    l = 0;
   100    ASSERT_THAT(read(efd.get(), &l, 4), SyscallFailsWithErrno(EINVAL));
   101  }
   102  
   103  TEST(EventfdTest, IllegalSeek) {
   104    FileDescriptor efd = ASSERT_NO_ERRNO_AND_VALUE(NewEventFD(0, 0));
   105    EXPECT_THAT(lseek(efd.get(), 0, SEEK_SET), SyscallFailsWithErrno(ESPIPE));
   106  }
   107  
   108  TEST(EventfdTest, IllegalPread) {
   109    FileDescriptor efd = ASSERT_NO_ERRNO_AND_VALUE(NewEventFD(0, 0));
   110    int l;
   111    EXPECT_THAT(pread(efd.get(), &l, sizeof(l), 0),
   112                SyscallFailsWithErrno(ESPIPE));
   113  }
   114  
   115  TEST(EventfdTest, IllegalPwrite) {
   116    FileDescriptor efd = ASSERT_NO_ERRNO_AND_VALUE(NewEventFD(0, 0));
   117    EXPECT_THAT(pwrite(efd.get(), "x", 1, 0), SyscallFailsWithErrno(ESPIPE));
   118  }
   119  
   120  TEST(EventfdTest, BigWrite) {
   121    FileDescriptor efd =
   122        ASSERT_NO_ERRNO_AND_VALUE(NewEventFD(0, EFD_NONBLOCK | EFD_SEMAPHORE));
   123  
   124    uint64_t big[16];
   125    big[0] = 16;
   126    ASSERT_THAT(write(efd.get(), big, sizeof(big)), SyscallSucceeds());
   127  }
   128  
   129  TEST(EventfdTest, BigRead) {
   130    FileDescriptor efd =
   131        ASSERT_NO_ERRNO_AND_VALUE(NewEventFD(0, EFD_NONBLOCK | EFD_SEMAPHORE));
   132  
   133    uint64_t l = 1;
   134    ASSERT_THAT(write(efd.get(), &l, sizeof(l)), SyscallSucceeds());
   135  
   136    uint64_t big[16];
   137    ASSERT_THAT(read(efd.get(), big, sizeof(big)), SyscallSucceeds());
   138    EXPECT_EQ(big[0], 1);
   139  }
   140  
   141  TEST(EventfdTest, BigWriteBigRead) {
   142    FileDescriptor efd =
   143        ASSERT_NO_ERRNO_AND_VALUE(NewEventFD(0, EFD_NONBLOCK | EFD_SEMAPHORE));
   144  
   145    uint64_t l[16];
   146    l[0] = 16;
   147    ASSERT_THAT(write(efd.get(), l, sizeof(l)), SyscallSucceeds());
   148    ASSERT_THAT(read(efd.get(), l, sizeof(l)), SyscallSucceeds());
   149    EXPECT_EQ(l[0], 1);
   150  }
   151  
   152  TEST(EventfdTest, SpliceFromPipePartialSucceeds) {
   153    int pipes[2];
   154    ASSERT_THAT(pipe2(pipes, O_NONBLOCK), SyscallSucceeds());
   155    const FileDescriptor pipe_rfd(pipes[0]);
   156    const FileDescriptor pipe_wfd(pipes[1]);
   157    constexpr uint64_t kVal{1};
   158  
   159    FileDescriptor efd = ASSERT_NO_ERRNO_AND_VALUE(NewEventFD(0, EFD_NONBLOCK));
   160  
   161    uint64_t event_array[2];
   162    event_array[0] = kVal;
   163    event_array[1] = kVal;
   164    ASSERT_THAT(write(pipe_wfd.get(), event_array, sizeof(event_array)),
   165                SyscallSucceedsWithValue(sizeof(event_array)));
   166    EXPECT_THAT(splice(pipe_rfd.get(), /*__offin=*/nullptr, efd.get(),
   167                       /*__offout=*/nullptr, sizeof(event_array[0]) + 1,
   168                       SPLICE_F_NONBLOCK),
   169                SyscallSucceedsWithValue(sizeof(event_array[0])));
   170  
   171    uint64_t val;
   172    ASSERT_THAT(read(efd.get(), &val, sizeof(val)),
   173                SyscallSucceedsWithValue(sizeof(val)));
   174    EXPECT_EQ(val, kVal);
   175  }
   176  
   177  // NotifyNonZero is inherently racy, so random save is disabled.
   178  TEST(EventfdTest, NotifyNonZero) {
   179    // Waits will time out at 10 seconds.
   180    constexpr int kEpollTimeoutMs = 10000;
   181    // Create an eventfd descriptor.
   182    FileDescriptor efd =
   183        ASSERT_NO_ERRNO_AND_VALUE(NewEventFD(7, EFD_NONBLOCK | EFD_SEMAPHORE));
   184    // Create an epoll fd to listen to efd.
   185    FileDescriptor epollfd = ASSERT_NO_ERRNO_AND_VALUE(NewEpollFD());
   186    // Add efd to epoll.
   187    ASSERT_NO_ERRNO(
   188        RegisterEpollFD(epollfd.get(), efd.get(), EPOLLIN | EPOLLET, efd.get()));
   189  
   190    // Use epoll to get a value from efd.
   191    struct epoll_event out_ev;
   192    int wait_out = epoll_wait(epollfd.get(), &out_ev, 1, kEpollTimeoutMs);
   193    EXPECT_EQ(wait_out, 1);
   194    EXPECT_EQ(efd.get(), out_ev.data.fd);
   195    uint64_t val = 0;
   196    ASSERT_THAT(read(efd.get(), &val, sizeof(val)), SyscallSucceeds());
   197    EXPECT_EQ(val, 1);
   198  
   199    // Start a thread that, after this thread blocks on epoll_wait, will write to
   200    // efd. This is racy -- it's possible that this write will happen after
   201    // epoll_wait times out.
   202    ScopedThread t([&efd] {
   203      sleep(5);
   204      uint64_t val = 1;
   205      EXPECT_THAT(write(efd.get(), &val, sizeof(val)),
   206                  SyscallSucceedsWithValue(sizeof(val)));
   207    });
   208  
   209    // epoll_wait should return once the thread writes.
   210    wait_out = epoll_wait(epollfd.get(), &out_ev, 1, kEpollTimeoutMs);
   211    EXPECT_EQ(wait_out, 1);
   212    EXPECT_EQ(efd.get(), out_ev.data.fd);
   213  
   214    val = 0;
   215    ASSERT_THAT(read(efd.get(), &val, sizeof(val)), SyscallSucceeds());
   216    EXPECT_EQ(val, 1);
   217  }
   218  
   219  }  // namespace
   220  
   221  }  // namespace testing
   222  }  // namespace gvisor