gvisor.dev/gvisor@v0.0.0-20240520182842-f9d4d51c7e0f/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 // TODO: b/298787679 - this test fails on 6.0+ kernels. 105 SKIP_IF(!IsRunningOnGvisor()); 106 107 FileDescriptor efd = ASSERT_NO_ERRNO_AND_VALUE(NewEventFD(0, 0)); 108 EXPECT_THAT(lseek(efd.get(), 0, SEEK_SET), SyscallFailsWithErrno(ESPIPE)); 109 } 110 111 TEST(EventfdTest, IllegalPread) { 112 FileDescriptor efd = ASSERT_NO_ERRNO_AND_VALUE(NewEventFD(0, 0)); 113 int l; 114 EXPECT_THAT(pread(efd.get(), &l, sizeof(l), 0), 115 SyscallFailsWithErrno(ESPIPE)); 116 } 117 118 TEST(EventfdTest, IllegalPwrite) { 119 FileDescriptor efd = ASSERT_NO_ERRNO_AND_VALUE(NewEventFD(0, 0)); 120 EXPECT_THAT(pwrite(efd.get(), "x", 1, 0), SyscallFailsWithErrno(ESPIPE)); 121 } 122 123 TEST(EventfdTest, BigWrite) { 124 FileDescriptor efd = 125 ASSERT_NO_ERRNO_AND_VALUE(NewEventFD(0, EFD_NONBLOCK | EFD_SEMAPHORE)); 126 127 uint64_t big[16]; 128 big[0] = 16; 129 ASSERT_THAT(write(efd.get(), big, sizeof(big)), SyscallSucceeds()); 130 } 131 132 TEST(EventfdTest, BigRead) { 133 FileDescriptor efd = 134 ASSERT_NO_ERRNO_AND_VALUE(NewEventFD(0, EFD_NONBLOCK | EFD_SEMAPHORE)); 135 136 uint64_t l = 1; 137 ASSERT_THAT(write(efd.get(), &l, sizeof(l)), SyscallSucceeds()); 138 139 uint64_t big[16]; 140 ASSERT_THAT(read(efd.get(), big, sizeof(big)), SyscallSucceeds()); 141 EXPECT_EQ(big[0], 1); 142 } 143 144 TEST(EventfdTest, BigWriteBigRead) { 145 FileDescriptor efd = 146 ASSERT_NO_ERRNO_AND_VALUE(NewEventFD(0, EFD_NONBLOCK | EFD_SEMAPHORE)); 147 148 uint64_t l[16]; 149 l[0] = 16; 150 ASSERT_THAT(write(efd.get(), l, sizeof(l)), SyscallSucceeds()); 151 ASSERT_THAT(read(efd.get(), l, sizeof(l)), SyscallSucceeds()); 152 EXPECT_EQ(l[0], 1); 153 } 154 155 TEST(EventfdTest, NotifyNonZero) { 156 // Waits will time out at 10 seconds. 157 constexpr int kEpollTimeoutMs = 10000; 158 // Create an eventfd descriptor. 159 FileDescriptor efd = 160 ASSERT_NO_ERRNO_AND_VALUE(NewEventFD(7, EFD_NONBLOCK | EFD_SEMAPHORE)); 161 // Create an epoll fd to listen to efd. 162 FileDescriptor epollfd = ASSERT_NO_ERRNO_AND_VALUE(NewEpollFD()); 163 // Add efd to epoll. 164 ASSERT_NO_ERRNO( 165 RegisterEpollFD(epollfd.get(), efd.get(), EPOLLIN | EPOLLET, efd.get())); 166 167 // Use epoll to get a value from efd. 168 struct epoll_event out_ev; 169 int wait_out = epoll_wait(epollfd.get(), &out_ev, 1, kEpollTimeoutMs); 170 EXPECT_EQ(wait_out, 1); 171 EXPECT_EQ(efd.get(), out_ev.data.fd); 172 uint64_t val = 0; 173 ASSERT_THAT(read(efd.get(), &val, sizeof(val)), SyscallSucceeds()); 174 EXPECT_EQ(val, 1); 175 176 // Start a thread that, after this thread blocks on epoll_wait, will write to 177 // efd. This is racy -- it's possible that this write will happen after 178 // epoll_wait times out. 179 ScopedThread t([&efd] { 180 sleep(5); 181 uint64_t val = 1; 182 EXPECT_THAT(write(efd.get(), &val, sizeof(val)), 183 SyscallSucceedsWithValue(sizeof(val))); 184 }); 185 186 // epoll_wait should return once the thread writes. 187 wait_out = epoll_wait(epollfd.get(), &out_ev, 1, kEpollTimeoutMs); 188 EXPECT_EQ(wait_out, 1); 189 EXPECT_EQ(efd.get(), out_ev.data.fd); 190 191 val = 0; 192 ASSERT_THAT(read(efd.get(), &val, sizeof(val)), SyscallSucceeds()); 193 EXPECT_EQ(val, 1); 194 } 195 196 TEST(EventfdTest, SpliceReturnsEINVAL) { 197 // Splicing into eventfd has been disabled in 198 // 36e2c7421f02 ("fs: don't allow splice read/write without explicit ops"). 199 SKIP_IF(!IsRunningOnGvisor()); 200 201 // Create an eventfd descriptor. 202 FileDescriptor efd = ASSERT_NO_ERRNO_AND_VALUE(NewEventFD(7, 0)); 203 204 // Create a new pipe. 205 int fds[2]; 206 ASSERT_THAT(pipe(fds), SyscallSucceeds()); 207 const FileDescriptor rfd(fds[0]); 208 const FileDescriptor wfd(fds[1]); 209 210 // Fill the pipe. 211 std::vector<char> buf(kPageSize); 212 ASSERT_THAT(write(wfd.get(), buf.data(), buf.size()), 213 SyscallSucceedsWithValue(kPageSize)); 214 215 EXPECT_THAT(splice(rfd.get(), nullptr, efd.get(), nullptr, kPageSize, 0), 216 SyscallFailsWithErrno(EINVAL)); 217 } 218 219 } // namespace 220 221 } // namespace testing 222 } // namespace gvisor