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