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