github.com/SagerNet/gvisor@v0.0.0-20210707092255-7731c139d75c/test/syscalls/linux/signalfd.cc (about) 1 // Copyright 2019 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 <poll.h> 17 #include <signal.h> 18 #include <stdio.h> 19 #include <string.h> 20 #include <sys/signalfd.h> 21 #include <unistd.h> 22 23 #include <functional> 24 #include <vector> 25 26 #include "gtest/gtest.h" 27 #include "absl/synchronization/mutex.h" 28 #include "test/util/file_descriptor.h" 29 #include "test/util/posix_error.h" 30 #include "test/util/signal_util.h" 31 #include "test/util/test_util.h" 32 #include "test/util/thread_util.h" 33 34 using ::testing::KilledBySignal; 35 36 namespace gvisor { 37 namespace testing { 38 39 namespace { 40 41 constexpr int kSigno = SIGUSR1; 42 constexpr int kSignoMax = 64; // SIGRTMAX 43 constexpr int kSignoAlt = SIGUSR2; 44 45 // Returns a new signalfd. 46 inline PosixErrorOr<FileDescriptor> NewSignalFD(sigset_t* mask, int flags = 0) { 47 int fd = signalfd(-1, mask, flags); 48 MaybeSave(); 49 if (fd < 0) { 50 return PosixError(errno, "signalfd"); 51 } 52 return FileDescriptor(fd); 53 } 54 55 class SignalfdTest : public ::testing::TestWithParam<int> {}; 56 57 TEST_P(SignalfdTest, Basic) { 58 int signo = GetParam(); 59 // Create the signalfd. 60 sigset_t mask; 61 sigemptyset(&mask); 62 sigaddset(&mask, signo); 63 FileDescriptor fd = ASSERT_NO_ERRNO_AND_VALUE(NewSignalFD(&mask, 0)); 64 65 // Deliver the blocked signal. 66 const auto scoped_sigmask = 67 ASSERT_NO_ERRNO_AND_VALUE(ScopedSignalMask(SIG_BLOCK, signo)); 68 ASSERT_THAT(tgkill(getpid(), gettid(), signo), SyscallSucceeds()); 69 70 // We should now read the signal. 71 struct signalfd_siginfo rbuf; 72 ASSERT_THAT(read(fd.get(), &rbuf, sizeof(rbuf)), 73 SyscallSucceedsWithValue(sizeof(rbuf))); 74 EXPECT_EQ(rbuf.ssi_signo, signo); 75 } 76 77 TEST_P(SignalfdTest, MaskWorks) { 78 int signo = GetParam(); 79 // Create two signalfds with different masks. 80 sigset_t mask1, mask2; 81 sigemptyset(&mask1); 82 sigemptyset(&mask2); 83 sigaddset(&mask1, signo); 84 sigaddset(&mask2, kSignoAlt); 85 FileDescriptor fd1 = ASSERT_NO_ERRNO_AND_VALUE(NewSignalFD(&mask1, 0)); 86 FileDescriptor fd2 = ASSERT_NO_ERRNO_AND_VALUE(NewSignalFD(&mask2, 0)); 87 88 // Deliver the two signals. 89 const auto scoped_sigmask1 = 90 ASSERT_NO_ERRNO_AND_VALUE(ScopedSignalMask(SIG_BLOCK, signo)); 91 const auto scoped_sigmask2 = 92 ASSERT_NO_ERRNO_AND_VALUE(ScopedSignalMask(SIG_BLOCK, kSignoAlt)); 93 ASSERT_THAT(tgkill(getpid(), gettid(), signo), SyscallSucceeds()); 94 ASSERT_THAT(tgkill(getpid(), gettid(), kSignoAlt), SyscallSucceeds()); 95 96 // We should see the signals on the appropriate signalfds. 97 // 98 // We read in the opposite order as the signals deliver above, to ensure that 99 // we don't happen to read the correct signal from the correct signalfd. 100 struct signalfd_siginfo rbuf1, rbuf2; 101 ASSERT_THAT(read(fd2.get(), &rbuf2, sizeof(rbuf2)), 102 SyscallSucceedsWithValue(sizeof(rbuf2))); 103 EXPECT_EQ(rbuf2.ssi_signo, kSignoAlt); 104 ASSERT_THAT(read(fd1.get(), &rbuf1, sizeof(rbuf1)), 105 SyscallSucceedsWithValue(sizeof(rbuf1))); 106 EXPECT_EQ(rbuf1.ssi_signo, signo); 107 } 108 109 TEST(Signalfd, Cloexec) { 110 // Exec tests confirm that O_CLOEXEC has the intended effect. We just create a 111 // signalfd with the appropriate flag here and assert that the FD has it set. 112 sigset_t mask; 113 sigemptyset(&mask); 114 FileDescriptor fd = 115 ASSERT_NO_ERRNO_AND_VALUE(NewSignalFD(&mask, SFD_CLOEXEC)); 116 EXPECT_THAT(fcntl(fd.get(), F_GETFD), SyscallSucceedsWithValue(FD_CLOEXEC)); 117 } 118 119 TEST_P(SignalfdTest, Blocking) { 120 int signo = GetParam(); 121 // Create the signalfd in blocking mode. 122 sigset_t mask; 123 sigemptyset(&mask); 124 sigaddset(&mask, signo); 125 FileDescriptor fd = ASSERT_NO_ERRNO_AND_VALUE(NewSignalFD(&mask, 0)); 126 127 // Shared tid variable. 128 absl::Mutex mu; 129 bool has_tid = false; 130 pid_t tid; 131 132 // Start a thread reading. 133 ScopedThread t([&] { 134 // Copy the tid and notify the caller. 135 { 136 absl::MutexLock ml(&mu); 137 tid = gettid(); 138 has_tid = true; 139 } 140 141 // Read the signal from the signalfd. 142 struct signalfd_siginfo rbuf; 143 ASSERT_THAT(read(fd.get(), &rbuf, sizeof(rbuf)), 144 SyscallSucceedsWithValue(sizeof(rbuf))); 145 EXPECT_EQ(rbuf.ssi_signo, signo); 146 }); 147 148 // Wait until blocked. 149 absl::MutexLock ml(&mu); 150 mu.Await(absl::Condition(&has_tid)); 151 152 // Deliver the signal to either the waiting thread, or 153 // to this thread. N.B. this is a bug in the core gVisor 154 // behavior for signalfd, and needs to be fixed. 155 // 156 // See gvisor.dev/issue/139. 157 if (IsRunningOnGvisor()) { 158 ASSERT_THAT(tgkill(getpid(), gettid(), signo), SyscallSucceeds()); 159 } else { 160 ASSERT_THAT(tgkill(getpid(), tid, signo), SyscallSucceeds()); 161 } 162 163 // Ensure that it was received. 164 t.Join(); 165 } 166 167 TEST_P(SignalfdTest, ThreadGroup) { 168 int signo = GetParam(); 169 // Create the signalfd in blocking mode. 170 sigset_t mask; 171 sigemptyset(&mask); 172 sigaddset(&mask, signo); 173 FileDescriptor fd = ASSERT_NO_ERRNO_AND_VALUE(NewSignalFD(&mask, 0)); 174 175 // Shared variable. 176 absl::Mutex mu; 177 bool first = false; 178 bool second = false; 179 180 // Start a thread reading. 181 ScopedThread t([&] { 182 // Read the signal from the signalfd. 183 struct signalfd_siginfo rbuf; 184 ASSERT_THAT(read(fd.get(), &rbuf, sizeof(rbuf)), 185 SyscallSucceedsWithValue(sizeof(rbuf))); 186 EXPECT_EQ(rbuf.ssi_signo, signo); 187 188 // Wait for the other thread. 189 absl::MutexLock ml(&mu); 190 first = true; 191 mu.Await(absl::Condition(&second)); 192 }); 193 194 // Deliver the signal to the threadgroup. 195 ASSERT_THAT(kill(getpid(), signo), SyscallSucceeds()); 196 197 // Wait for the first thread to process. 198 { 199 absl::MutexLock ml(&mu); 200 mu.Await(absl::Condition(&first)); 201 } 202 203 // Deliver to the thread group again (other thread still exists). 204 ASSERT_THAT(kill(getpid(), signo), SyscallSucceeds()); 205 206 // Ensure that we can also receive it. 207 struct signalfd_siginfo rbuf; 208 ASSERT_THAT(read(fd.get(), &rbuf, sizeof(rbuf)), 209 SyscallSucceedsWithValue(sizeof(rbuf))); 210 EXPECT_EQ(rbuf.ssi_signo, signo); 211 212 // Mark the test as done. 213 { 214 absl::MutexLock ml(&mu); 215 second = true; 216 } 217 218 // The other thread should be joinable. 219 t.Join(); 220 } 221 222 TEST_P(SignalfdTest, Nonblock) { 223 int signo = GetParam(); 224 // Create the signalfd in non-blocking mode. 225 sigset_t mask; 226 sigemptyset(&mask); 227 sigaddset(&mask, signo); 228 FileDescriptor fd = 229 ASSERT_NO_ERRNO_AND_VALUE(NewSignalFD(&mask, SFD_NONBLOCK)); 230 231 // We should return if we attempt to read. 232 struct signalfd_siginfo rbuf; 233 ASSERT_THAT(read(fd.get(), &rbuf, sizeof(rbuf)), 234 SyscallFailsWithErrno(EWOULDBLOCK)); 235 236 // Block and deliver the signal. 237 const auto scoped_sigmask = 238 ASSERT_NO_ERRNO_AND_VALUE(ScopedSignalMask(SIG_BLOCK, signo)); 239 ASSERT_THAT(tgkill(getpid(), gettid(), signo), SyscallSucceeds()); 240 241 // Ensure that a read actually works. 242 ASSERT_THAT(read(fd.get(), &rbuf, sizeof(rbuf)), 243 SyscallSucceedsWithValue(sizeof(rbuf))); 244 EXPECT_EQ(rbuf.ssi_signo, signo); 245 246 // Should block again. 247 EXPECT_THAT(read(fd.get(), &rbuf, sizeof(rbuf)), 248 SyscallFailsWithErrno(EWOULDBLOCK)); 249 } 250 251 TEST_P(SignalfdTest, SetMask) { 252 int signo = GetParam(); 253 // Create the signalfd matching nothing. 254 sigset_t mask; 255 sigemptyset(&mask); 256 FileDescriptor fd = 257 ASSERT_NO_ERRNO_AND_VALUE(NewSignalFD(&mask, SFD_NONBLOCK)); 258 259 // Block and deliver a signal. 260 const auto scoped_sigmask = 261 ASSERT_NO_ERRNO_AND_VALUE(ScopedSignalMask(SIG_BLOCK, signo)); 262 ASSERT_THAT(tgkill(getpid(), gettid(), signo), SyscallSucceeds()); 263 264 // We should have nothing. 265 struct signalfd_siginfo rbuf; 266 ASSERT_THAT(read(fd.get(), &rbuf, sizeof(rbuf)), 267 SyscallFailsWithErrno(EWOULDBLOCK)); 268 269 // Change the signal mask. 270 sigaddset(&mask, signo); 271 ASSERT_THAT(signalfd(fd.get(), &mask, 0), SyscallSucceeds()); 272 273 // We should now have the signal. 274 ASSERT_THAT(read(fd.get(), &rbuf, sizeof(rbuf)), 275 SyscallSucceedsWithValue(sizeof(rbuf))); 276 EXPECT_EQ(rbuf.ssi_signo, signo); 277 } 278 279 TEST_P(SignalfdTest, Poll) { 280 int signo = GetParam(); 281 // Create the signalfd. 282 sigset_t mask; 283 sigemptyset(&mask); 284 sigaddset(&mask, signo); 285 FileDescriptor fd = ASSERT_NO_ERRNO_AND_VALUE(NewSignalFD(&mask, 0)); 286 287 // Block the signal, and start a thread to deliver it. 288 const auto scoped_sigmask = 289 ASSERT_NO_ERRNO_AND_VALUE(ScopedSignalMask(SIG_BLOCK, signo)); 290 pid_t orig_tid = gettid(); 291 ScopedThread t([&] { 292 absl::SleepFor(absl::Seconds(5)); 293 ASSERT_THAT(tgkill(getpid(), orig_tid, signo), SyscallSucceeds()); 294 }); 295 296 // Start polling for the signal. We expect that it is not available at the 297 // outset, but then becomes available when the signal is sent. We give a 298 // timeout of 10000ms (or the delay above + 5 seconds of additional grace 299 // time). 300 struct pollfd poll_fd = {fd.get(), POLLIN, 0}; 301 EXPECT_THAT(RetryEINTR(poll)(&poll_fd, 1, 10000), 302 SyscallSucceedsWithValue(1)); 303 304 // Actually read the signal to prevent delivery. 305 struct signalfd_siginfo rbuf; 306 EXPECT_THAT(read(fd.get(), &rbuf, sizeof(rbuf)), 307 SyscallSucceedsWithValue(sizeof(rbuf))); 308 } 309 310 std::string PrintSigno(::testing::TestParamInfo<int> info) { 311 switch (info.param) { 312 case kSigno: 313 return "kSigno"; 314 case kSignoMax: 315 return "kSignoMax"; 316 default: 317 return absl::StrCat(info.param); 318 } 319 } 320 INSTANTIATE_TEST_SUITE_P(Signalfd, SignalfdTest, 321 ::testing::Values(kSigno, kSignoMax), PrintSigno); 322 323 TEST(Signalfd, Ppoll) { 324 sigset_t mask; 325 sigemptyset(&mask); 326 sigaddset(&mask, SIGKILL); 327 FileDescriptor fd = 328 ASSERT_NO_ERRNO_AND_VALUE(NewSignalFD(&mask, SFD_CLOEXEC)); 329 330 // Ensure that the given ppoll blocks. 331 struct pollfd pfd = {}; 332 pfd.fd = fd.get(); 333 pfd.events = POLLIN; 334 struct timespec timeout = {}; 335 timeout.tv_sec = 1; 336 EXPECT_THAT(RetryEINTR(ppoll)(&pfd, 1, &timeout, &mask), 337 SyscallSucceedsWithValue(0)); 338 } 339 340 TEST(Signalfd, KillStillKills) { 341 sigset_t mask; 342 sigemptyset(&mask); 343 sigaddset(&mask, SIGKILL); 344 FileDescriptor fd = 345 ASSERT_NO_ERRNO_AND_VALUE(NewSignalFD(&mask, SFD_CLOEXEC)); 346 347 // Just because there is a signalfd, we shouldn't see any change in behavior 348 // for unblockable signals. It's easier to test this with SIGKILL. 349 const auto scoped_sigmask = 350 ASSERT_NO_ERRNO_AND_VALUE(ScopedSignalMask(SIG_BLOCK, SIGKILL)); 351 EXPECT_EXIT(tgkill(getpid(), gettid(), SIGKILL), KilledBySignal(SIGKILL), ""); 352 } 353 354 } // namespace 355 356 } // namespace testing 357 } // namespace gvisor 358 359 int main(int argc, char** argv) { 360 // These tests depend on delivering signals. Block them up front so that all 361 // other threads created by TestInit will also have them blocked, and they 362 // will not interface with the rest of the test. 363 sigset_t set; 364 sigemptyset(&set); 365 sigaddset(&set, gvisor::testing::kSigno); 366 sigaddset(&set, gvisor::testing::kSignoMax); 367 sigaddset(&set, gvisor::testing::kSignoAlt); 368 TEST_PCHECK(sigprocmask(SIG_BLOCK, &set, nullptr) == 0); 369 370 gvisor::testing::TestInit(&argc, &argv); 371 372 return gvisor::testing::RunAllTests(); 373 }