gvisor.dev/gvisor@v0.0.0-20240520182842-f9d4d51c7e0f/test/syscalls/linux/semaphore.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 <signal.h> 16 #include <sys/ipc.h> 17 #include <sys/sem.h> 18 #include <sys/types.h> 19 20 #include <atomic> 21 #include <cerrno> 22 #include <ctime> 23 #include <memory> 24 #include <set> 25 26 #include "gmock/gmock.h" 27 #include "gtest/gtest.h" 28 #include "absl/base/macros.h" 29 #include "absl/memory/memory.h" 30 #include "absl/synchronization/mutex.h" 31 #include "absl/time/clock.h" 32 #include "test/util/capability_util.h" 33 #include "test/util/test_util.h" 34 #include "test/util/thread_util.h" 35 36 namespace gvisor { 37 namespace testing { 38 namespace { 39 40 constexpr int kSemMap = 1024000000; 41 constexpr int kSemMni = 32000; 42 constexpr int kSemMns = 1024000000; 43 constexpr int kSemMnu = 1024000000; 44 constexpr int kSemMsl = 32000; 45 constexpr int kSemOpm = 500; 46 constexpr int kSemUme = 500; 47 constexpr int kSemUsz = 20; 48 constexpr int kSemVmx = 32767; 49 constexpr int kSemAem = 32767; 50 51 class AutoSem { 52 public: 53 // Creates a new private semaphore. 54 AutoSem() : id_(semget(IPC_PRIVATE, 1, 0)) {} 55 56 explicit AutoSem(int id) : id_(id) {} 57 ~AutoSem() { 58 if (id_ >= 0) { 59 EXPECT_THAT(semctl(id_, 0, IPC_RMID), SyscallSucceeds()); 60 } 61 } 62 63 int release() { 64 int old = id_; 65 id_ = -1; 66 return old; 67 } 68 69 int get() { return id_; } 70 71 private: 72 int id_ = -1; 73 }; 74 75 bool operator==(struct semid_ds const& a, struct semid_ds const& b) { 76 return a.sem_perm.__key == b.sem_perm.__key && 77 a.sem_perm.uid == b.sem_perm.uid && a.sem_perm.gid == b.sem_perm.gid && 78 a.sem_perm.cuid == b.sem_perm.cuid && 79 a.sem_perm.cgid == b.sem_perm.cgid && 80 a.sem_perm.mode == b.sem_perm.mode && a.sem_otime == b.sem_otime && 81 a.sem_ctime == b.sem_ctime && a.sem_nsems == b.sem_nsems; 82 } 83 84 TEST(SemaphoreTest, SemGet) { 85 // Test creation and lookup. 86 AutoSem sem(semget(1, 10, IPC_CREAT)); 87 ASSERT_THAT(sem.get(), SyscallSucceeds()); 88 EXPECT_THAT(semget(1, 10, IPC_CREAT), SyscallSucceedsWithValue(sem.get())); 89 EXPECT_THAT(semget(1, 9, IPC_CREAT), SyscallSucceedsWithValue(sem.get())); 90 91 // Creation and lookup failure cases. 92 EXPECT_THAT(semget(1, 11, IPC_CREAT), SyscallFailsWithErrno(EINVAL)); 93 EXPECT_THAT(semget(1, -1, IPC_CREAT), SyscallFailsWithErrno(EINVAL)); 94 EXPECT_THAT(semget(1, 10, IPC_CREAT | IPC_EXCL), 95 SyscallFailsWithErrno(EEXIST)); 96 EXPECT_THAT(semget(2, 1, 0), SyscallFailsWithErrno(ENOENT)); 97 EXPECT_THAT(semget(2, 0, IPC_CREAT), SyscallFailsWithErrno(EINVAL)); 98 99 // Private semaphores never conflict. 100 AutoSem sem2(semget(IPC_PRIVATE, 1, 0)); 101 AutoSem sem3(semget(IPC_PRIVATE, 1, 0)); 102 ASSERT_THAT(sem2.get(), SyscallSucceeds()); 103 EXPECT_NE(sem.get(), sem2.get()); 104 ASSERT_THAT(sem3.get(), SyscallSucceeds()); 105 EXPECT_NE(sem3.get(), sem2.get()); 106 } 107 108 // Tests system-wide limits for semget. 109 TEST(SemaphoreTest, SemGetSystemLimits) { 110 // Disable save so that we don't trigger save/restore too many times. 111 const DisableSave ds; 112 113 // Exceed number of semaphores per set. 114 EXPECT_THAT(semget(IPC_PRIVATE, kSemMsl + 1, 0), 115 SyscallFailsWithErrno(EINVAL)); 116 117 // Exceed system-wide limit for semaphore sets by 1. 118 AutoSem sems[kSemMni]; 119 EXPECT_THAT(semget(IPC_PRIVATE, 1, 0), SyscallFailsWithErrno(ENOSPC)); 120 } 121 122 // Tests simple operations that shouldn't block in a single-thread. 123 TEST(SemaphoreTest, SemOpSingleNoBlock) { 124 AutoSem sem(semget(IPC_PRIVATE, 1, 0600 | IPC_CREAT)); 125 ASSERT_THAT(sem.get(), SyscallSucceeds()); 126 127 struct sembuf buf = {}; 128 buf.sem_op = 1; 129 ASSERT_THAT(semop(sem.get(), &buf, 1), SyscallSucceeds()); 130 131 buf.sem_op = -1; 132 ASSERT_THAT(semop(sem.get(), &buf, 1), SyscallSucceeds()); 133 134 buf.sem_op = 0; 135 ASSERT_THAT(semop(sem.get(), &buf, 1), SyscallSucceeds()); 136 137 // Error cases with invalid values. 138 ASSERT_THAT(semop(sem.get() + 1, &buf, 1), SyscallFailsWithErrno(EINVAL)); 139 140 buf.sem_num = 1; 141 ASSERT_THAT(semop(sem.get(), &buf, 1), SyscallFailsWithErrno(EFBIG)); 142 143 ASSERT_THAT(semop(sem.get(), nullptr, 0), SyscallFailsWithErrno(EINVAL)); 144 } 145 146 // Tests simple timed operations that shouldn't block in a single-thread. 147 TEST(SemaphoreTest, SemTimedOpSingleNoBlock) { 148 AutoSem sem(semget(IPC_PRIVATE, 1, 0600 | IPC_CREAT)); 149 ASSERT_THAT(sem.get(), SyscallSucceeds()); 150 151 struct sembuf buf = {}; 152 buf.sem_op = 1; 153 struct timespec timeout = {}; 154 // 50 milliseconds. 155 timeout.tv_nsec = 5e7; 156 ASSERT_THAT(semtimedop(sem.get(), &buf, 1, &timeout), SyscallSucceeds()); 157 158 buf.sem_op = -1; 159 EXPECT_THAT(semtimedop(sem.get(), &buf, 1, &timeout), SyscallSucceeds()); 160 161 buf.sem_op = 0; 162 EXPECT_THAT(semtimedop(sem.get(), &buf, 1, &timeout), SyscallSucceeds()); 163 164 // Error cases with invalid values. 165 EXPECT_THAT(semtimedop(sem.get() + 1, &buf, 1, &timeout), 166 SyscallFailsWithErrno(EINVAL)); 167 168 buf.sem_num = 1; 169 EXPECT_THAT(semtimedop(sem.get(), &buf, 1, &timeout), 170 SyscallFailsWithErrno(EFBIG)); 171 buf.sem_num = 0; 172 173 EXPECT_THAT(semtimedop(sem.get(), nullptr, 0, &timeout), 174 SyscallFailsWithErrno(EINVAL)); 175 176 timeout.tv_nsec = 1e9; 177 EXPECT_THAT(semtimedop(sem.get(), &buf, 0, &timeout), 178 SyscallFailsWithErrno(EINVAL)); 179 } 180 181 // Tests multiple operations that shouldn't block in a single-thread. 182 TEST(SemaphoreTest, SemOpMultiNoBlock) { 183 AutoSem sem(semget(IPC_PRIVATE, 4, 0600 | IPC_CREAT)); 184 ASSERT_THAT(sem.get(), SyscallSucceeds()); 185 186 struct sembuf bufs[5] = {}; 187 bufs[0].sem_num = 0; 188 bufs[0].sem_op = 10; 189 bufs[0].sem_flg = 0; 190 191 bufs[1].sem_num = 1; 192 bufs[1].sem_op = 2; 193 bufs[1].sem_flg = 0; 194 195 bufs[2].sem_num = 2; 196 bufs[2].sem_op = 3; 197 bufs[2].sem_flg = 0; 198 199 bufs[3].sem_num = 0; 200 bufs[3].sem_op = -5; 201 bufs[3].sem_flg = 0; 202 203 bufs[4].sem_num = 2; 204 bufs[4].sem_op = 2; 205 bufs[4].sem_flg = 0; 206 207 ASSERT_THAT(semop(sem.get(), bufs, ABSL_ARRAYSIZE(bufs)), SyscallSucceeds()); 208 209 ASSERT_THAT(semctl(sem.get(), 0, GETVAL), SyscallSucceedsWithValue(5)); 210 ASSERT_THAT(semctl(sem.get(), 1, GETVAL), SyscallSucceedsWithValue(2)); 211 ASSERT_THAT(semctl(sem.get(), 2, GETVAL), SyscallSucceedsWithValue(5)); 212 ASSERT_THAT(semctl(sem.get(), 3, GETVAL), SyscallSucceedsWithValue(0)); 213 214 for (auto& b : bufs) { 215 b.sem_op = -b.sem_op; 216 } 217 // 0 and 3 order must be reversed, otherwise it will block. 218 std::swap(bufs[0].sem_op, bufs[3].sem_op); 219 ASSERT_THAT(RetryEINTR(semop)(sem.get(), bufs, ABSL_ARRAYSIZE(bufs)), 220 SyscallSucceeds()); 221 222 // All semaphores should be back to 0 now. 223 for (size_t i = 0; i < 4; ++i) { 224 ASSERT_THAT(semctl(sem.get(), i, GETVAL), SyscallSucceedsWithValue(0)); 225 } 226 } 227 228 // Makes a best effort attempt to ensure that operation would block. 229 TEST(SemaphoreTest, SemOpBlock) { 230 AutoSem sem(semget(IPC_PRIVATE, 1, 0600 | IPC_CREAT)); 231 ASSERT_THAT(sem.get(), SyscallSucceeds()); 232 233 std::atomic<int> blocked(1); 234 ScopedThread th([&sem, &blocked] { 235 absl::SleepFor(absl::Milliseconds(100)); 236 ASSERT_EQ(blocked.load(), 1); 237 238 struct sembuf buf = {}; 239 buf.sem_op = 1; 240 ASSERT_THAT(RetryEINTR(semop)(sem.get(), &buf, 1), SyscallSucceeds()); 241 }); 242 243 struct sembuf buf = {}; 244 buf.sem_op = -1; 245 ASSERT_THAT(RetryEINTR(semop)(sem.get(), &buf, 1), SyscallSucceeds()); 246 blocked.store(0); 247 } 248 249 // Makes a best effort attempt to ensure that operation would be timeout when 250 // being blocked. 251 TEST(SemaphoreTest, SemTimedOpBlock) { 252 AutoSem sem(semget(IPC_PRIVATE, 1, 0600 | IPC_CREAT)); 253 ASSERT_THAT(sem.get(), SyscallSucceeds()); 254 255 struct sembuf buf = {}; 256 buf.sem_op = -1; 257 struct timespec timeout = {}; 258 timeout.tv_nsec = 5e7; 259 // semtimedop reaches the time limit, it fails with errno EAGAIN. 260 ASSERT_THAT(RetryEINTR(semtimedop)(sem.get(), &buf, 1, &timeout), 261 SyscallFailsWithErrno(EAGAIN)); 262 } 263 264 // Tests that IPC_NOWAIT returns with no wait. 265 TEST(SemaphoreTest, SemOpNoBlock) { 266 AutoSem sem(semget(IPC_PRIVATE, 1, 0600 | IPC_CREAT)); 267 ASSERT_THAT(sem.get(), SyscallSucceeds()); 268 269 struct sembuf buf = {}; 270 buf.sem_flg = IPC_NOWAIT; 271 272 buf.sem_op = -1; 273 ASSERT_THAT(semop(sem.get(), &buf, 1), SyscallFailsWithErrno(EAGAIN)); 274 275 buf.sem_op = 1; 276 ASSERT_THAT(semop(sem.get(), &buf, 1), SyscallSucceeds()); 277 278 buf.sem_op = 0; 279 ASSERT_THAT(semop(sem.get(), &buf, 1), SyscallFailsWithErrno(EAGAIN)); 280 } 281 282 // Test runs 2 threads, one signals the other waits the same number of times. 283 TEST(SemaphoreTest, SemOpSimple) { 284 AutoSem sem(semget(IPC_PRIVATE, 1, 0600 | IPC_CREAT)); 285 ASSERT_THAT(sem.get(), SyscallSucceeds()); 286 287 constexpr size_t kLoops = 100; 288 ScopedThread th([&sem] { 289 struct sembuf buf = {}; 290 buf.sem_op = 1; 291 for (size_t i = 0; i < kLoops; i++) { 292 // Sleep to prevent making all increments in one shot without letting 293 // the waiter wait. 294 absl::SleepFor(absl::Milliseconds(1)); 295 ASSERT_THAT(semop(sem.get(), &buf, 1), SyscallSucceeds()); 296 } 297 }); 298 299 struct sembuf buf = {}; 300 buf.sem_op = -1; 301 for (size_t i = 0; i < kLoops; i++) { 302 ASSERT_THAT(RetryEINTR(semop)(sem.get(), &buf, 1), SyscallSucceeds()); 303 } 304 } 305 306 // Tests that semaphore can be removed while there are waiters. 307 // NoRandomSave: Test relies on timing that random save throws off. 308 TEST(SemaphoreTest, SemOpRemoveWithWaiter) { 309 AutoSem sem(semget(IPC_PRIVATE, 2, 0600 | IPC_CREAT)); 310 ASSERT_THAT(sem.get(), SyscallSucceeds()); 311 312 ScopedThread th([&sem] { 313 absl::SleepFor(absl::Milliseconds(250)); 314 ASSERT_THAT(semctl(sem.release(), 0, IPC_RMID), SyscallSucceeds()); 315 }); 316 317 // This must happen before IPC_RMID runs above. Otherwise it fails with EINVAL 318 // instead because the semaphore has already been removed. 319 struct sembuf buf = {}; 320 buf.sem_op = -1; 321 ASSERT_THAT(RetryEINTR(semop)(sem.get(), &buf, 1), 322 SyscallFailsWithErrno(EIDRM)); 323 } 324 325 // Semaphore isn't fair. It will execute any waiter that can satisfy the 326 // request even if it gets in front of other waiters. 327 TEST(SemaphoreTest, SemOpBestFitExecution) { 328 AutoSem sem(semget(IPC_PRIVATE, 1, 0600 | IPC_CREAT)); 329 ASSERT_THAT(sem.get(), SyscallSucceeds()); 330 331 ScopedThread th([&sem] { 332 struct sembuf buf = {}; 333 buf.sem_op = -2; 334 ASSERT_THAT(RetryEINTR(semop)(sem.get(), &buf, 1), SyscallFails()); 335 // Ensure that wait will only unblock when the semaphore is removed. On 336 // EINTR retry it may race with deletion and return EINVAL. 337 ASSERT_TRUE(errno == EIDRM || errno == EINVAL) << "errno=" << errno; 338 }); 339 340 // Ensures that '-1' below will unblock even though '-10' above is waiting 341 // for the same semaphore. 342 for (size_t i = 0; i < 10; ++i) { 343 struct sembuf buf = {}; 344 buf.sem_op = 1; 345 ASSERT_THAT(RetryEINTR(semop)(sem.get(), &buf, 1), SyscallSucceeds()); 346 347 absl::SleepFor(absl::Milliseconds(10)); 348 349 buf.sem_op = -1; 350 ASSERT_THAT(RetryEINTR(semop)(sem.get(), &buf, 1), SyscallSucceeds()); 351 } 352 353 ASSERT_THAT(semctl(sem.release(), 0, IPC_RMID), SyscallSucceeds()); 354 } 355 356 // Executes random operations in multiple threads and verify correctness. 357 TEST(SemaphoreTest, SemOpRandom) { 358 // Don't do cooperative S/R tests because there are too many syscalls in 359 // this test, 360 const DisableSave ds; 361 362 AutoSem sem(semget(IPC_PRIVATE, 1, 0600 | IPC_CREAT)); 363 ASSERT_THAT(sem.get(), SyscallSucceeds()); 364 365 // Protects the seed below. 366 absl::Mutex mutex; 367 uint32_t seed = time(nullptr); 368 369 int count = 0; // Tracks semaphore value. 370 bool done = false; // Tells waiters to stop after signal threads are done. 371 372 // These threads will wait in a loop. 373 std::unique_ptr<ScopedThread> decs[5]; 374 for (auto& dec : decs) { 375 dec = std::make_unique<ScopedThread>([&sem, &mutex, &count, &seed, &done] { 376 for (size_t i = 0; i < 500; ++i) { 377 int16_t val; 378 { 379 absl::MutexLock l(&mutex); 380 if (done) { 381 return; 382 } 383 val = (rand_r(&seed) % 10 + 1); // Rand between 1 and 10. 384 count -= val; 385 } 386 struct sembuf buf = {}; 387 buf.sem_op = -val; 388 ASSERT_THAT(RetryEINTR(semop)(sem.get(), &buf, 1), SyscallSucceeds()); 389 absl::SleepFor(absl::Milliseconds(val * 2)); 390 } 391 }); 392 } 393 394 // These threads will wait for zero in a loop. 395 std::unique_ptr<ScopedThread> zeros[5]; 396 for (auto& zero : zeros) { 397 zero = std::make_unique<ScopedThread>([&sem, &mutex, &done] { 398 for (size_t i = 0; i < 500; ++i) { 399 { 400 absl::MutexLock l(&mutex); 401 if (done) { 402 return; 403 } 404 } 405 struct sembuf buf = {}; 406 buf.sem_op = 0; 407 ASSERT_THAT(RetryEINTR(semop)(sem.get(), &buf, 1), SyscallSucceeds()); 408 absl::SleepFor(absl::Milliseconds(10)); 409 } 410 }); 411 } 412 413 // These threads will signal in a loop. 414 std::unique_ptr<ScopedThread> incs[5]; 415 for (auto& inc : incs) { 416 inc = std::make_unique<ScopedThread>([&sem, &mutex, &count, &seed] { 417 for (size_t i = 0; i < 500; ++i) { 418 int16_t val; 419 { 420 absl::MutexLock l(&mutex); 421 val = (rand_r(&seed) % 10 + 1); // Rand between 1 and 10. 422 count += val; 423 } 424 struct sembuf buf = {}; 425 buf.sem_op = val; 426 ASSERT_THAT(semop(sem.get(), &buf, 1), SyscallSucceeds()); 427 absl::SleepFor(absl::Milliseconds(val * 2)); 428 } 429 }); 430 } 431 432 // First wait for signal threads to be done. 433 for (auto& inc : incs) { 434 inc->Join(); 435 } 436 437 // Now there could be waiters blocked (remember operations are random). 438 // Notify waiters that we're done and signal semaphore just the right amount. 439 { 440 absl::MutexLock l(&mutex); 441 done = true; 442 struct sembuf buf = {}; 443 buf.sem_op = -count; 444 ASSERT_THAT(semop(sem.get(), &buf, 1), SyscallSucceeds()); 445 } 446 447 // Now all waiters should unblock and exit. 448 for (auto& dec : decs) { 449 dec->Join(); 450 } 451 for (auto& zero : zeros) { 452 zero->Join(); 453 } 454 } 455 456 TEST(SemaphoreTest, SemOpNamespace) { 457 SKIP_IF(!ASSERT_NO_ERRNO_AND_VALUE(HaveCapability(CAP_SYS_ADMIN))); 458 459 AutoSem sem(semget(123, 1, 0600 | IPC_CREAT | IPC_EXCL)); 460 ASSERT_THAT(sem.get(), SyscallSucceeds()); 461 462 ScopedThread([]() { 463 EXPECT_THAT(unshare(CLONE_NEWIPC), SyscallSucceeds()); 464 AutoSem sem(semget(123, 1, 0600 | IPC_CREAT | IPC_EXCL)); 465 ASSERT_THAT(sem.get(), SyscallSucceeds()); 466 }); 467 } 468 469 TEST(SemaphoreTest, SemCtlVal) { 470 AutoSem sem(semget(IPC_PRIVATE, 1, 0600 | IPC_CREAT)); 471 ASSERT_THAT(sem.get(), SyscallSucceeds()); 472 473 // Semaphore must start with 0. 474 EXPECT_THAT(semctl(sem.get(), 0, GETVAL), SyscallSucceedsWithValue(0)); 475 476 // Increase value and ensure waiters are woken up. 477 ScopedThread th([&sem] { 478 struct sembuf buf = {}; 479 buf.sem_op = -10; 480 ASSERT_THAT(RetryEINTR(semop)(sem.get(), &buf, 1), SyscallSucceeds()); 481 }); 482 483 ASSERT_THAT(semctl(sem.get(), 0, SETVAL, 9), SyscallSucceeds()); 484 EXPECT_THAT(semctl(sem.get(), 0, GETVAL), SyscallSucceedsWithValue(9)); 485 486 ASSERT_THAT(semctl(sem.get(), 0, SETVAL, 20), SyscallSucceeds()); 487 const int value = semctl(sem.get(), 0, GETVAL); 488 // 10 or 20 because it could have raced with waiter above. 489 EXPECT_TRUE(value == 10 || value == 20) << "value=" << value; 490 th.Join(); 491 492 // Set it back to 0 and ensure that waiters are woken up. 493 ScopedThread thZero([&sem] { 494 struct sembuf buf = {}; 495 buf.sem_op = 0; 496 ASSERT_THAT(RetryEINTR(semop)(sem.get(), &buf, 1), SyscallSucceeds()); 497 }); 498 ASSERT_THAT(semctl(sem.get(), 0, SETVAL, 0), SyscallSucceeds()); 499 EXPECT_THAT(semctl(sem.get(), 0, GETVAL), SyscallSucceedsWithValue(0)); 500 thZero.Join(); 501 } 502 503 TEST(SemaphoreTest, SemCtlValAll) { 504 AutoSem sem(semget(IPC_PRIVATE, 3, 0600 | IPC_CREAT)); 505 ASSERT_THAT(sem.get(), SyscallSucceeds()); 506 507 // Semaphores must start with 0. 508 uint16_t get[3] = {10, 10, 10}; 509 EXPECT_THAT(semctl(sem.get(), 1, GETALL, get), SyscallSucceedsWithValue(0)); 510 for (auto v : get) { 511 EXPECT_EQ(v, 0); 512 } 513 514 // SetAll and check that they were set. 515 uint16_t vals[3] = {0, 10, 20}; 516 EXPECT_THAT(semctl(sem.get(), 1, SETALL, vals), SyscallSucceedsWithValue(0)); 517 EXPECT_THAT(semctl(sem.get(), 1, GETALL, get), SyscallSucceedsWithValue(0)); 518 for (size_t i = 0; i < ABSL_ARRAYSIZE(vals); ++i) { 519 EXPECT_EQ(get[i], vals[i]); 520 } 521 522 EXPECT_THAT(semctl(sem.get(), 1, SETALL, nullptr), 523 SyscallFailsWithErrno(EFAULT)); 524 } 525 526 TEST(SemaphoreTest, SemCtlGetPid) { 527 AutoSem sem(semget(IPC_PRIVATE, 1, 0600 | IPC_CREAT)); 528 ASSERT_THAT(sem.get(), SyscallSucceeds()); 529 530 ASSERT_THAT(semctl(sem.get(), 0, SETVAL, 1), SyscallSucceeds()); 531 EXPECT_THAT(semctl(sem.get(), 0, GETPID), SyscallSucceedsWithValue(getpid())); 532 } 533 534 TEST(SemaphoreTest, SemCtlGetPidFork) { 535 AutoSem sem(semget(IPC_PRIVATE, 1, 0600 | IPC_CREAT)); 536 ASSERT_THAT(sem.get(), SyscallSucceeds()); 537 538 const pid_t child_pid = fork(); 539 if (child_pid == 0) { 540 TEST_PCHECK(semctl(sem.get(), 0, SETVAL, 1) == 0); 541 TEST_PCHECK(semctl(sem.get(), 0, GETPID) == getpid()); 542 543 _exit(0); 544 } 545 ASSERT_THAT(child_pid, SyscallSucceeds()); 546 547 int status; 548 ASSERT_THAT(RetryEINTR(waitpid)(child_pid, &status, 0), 549 SyscallSucceedsWithValue(child_pid)); 550 EXPECT_TRUE(WIFEXITED(status) && WEXITSTATUS(status) == 0) 551 << " status " << status; 552 } 553 554 TEST(SemaphoreTest, SemIpcSet) { 555 // Drop CAP_IPC_OWNER which allows us to bypass semaphore permissions. 556 AutoCapability cap(CAP_IPC_OWNER, false); 557 558 AutoSem sem(semget(IPC_PRIVATE, 1, 0600 | IPC_CREAT)); 559 ASSERT_THAT(sem.get(), SyscallSucceeds()); 560 561 struct semid_ds semid = {}; 562 semid.sem_perm.uid = getuid(); 563 semid.sem_perm.gid = getgid(); 564 565 // Make semaphore readonly and check that signal fails. 566 semid.sem_perm.mode = 0400; 567 EXPECT_THAT(semctl(sem.get(), 0, IPC_SET, &semid), SyscallSucceeds()); 568 struct sembuf buf = {}; 569 buf.sem_op = 1; 570 ASSERT_THAT(semop(sem.get(), &buf, 1), SyscallFailsWithErrno(EACCES)); 571 572 // Make semaphore writeonly and check that wait for zero fails. 573 semid.sem_perm.mode = 0200; 574 EXPECT_THAT(semctl(sem.get(), 0, IPC_SET, &semid), SyscallSucceeds()); 575 buf.sem_op = 0; 576 ASSERT_THAT(semop(sem.get(), &buf, 1), SyscallFailsWithErrno(EACCES)); 577 } 578 579 TEST(SemaphoreTest, SemCtlIpcStat) { 580 // Drop CAP_IPC_OWNER which allows us to bypass semaphore permissions. 581 AutoCapability cap(CAP_IPC_OWNER, false); 582 const uid_t kUid = getuid(); 583 const gid_t kGid = getgid(); 584 time_t start_time = time(nullptr); 585 586 AutoSem sem(semget(IPC_PRIVATE, 10, 0600 | IPC_CREAT)); 587 ASSERT_THAT(sem.get(), SyscallSucceeds()); 588 589 struct semid_ds ds; 590 EXPECT_THAT(semctl(sem.get(), 0, IPC_STAT, &ds), SyscallSucceeds()); 591 592 EXPECT_EQ(ds.sem_perm.__key, IPC_PRIVATE); 593 EXPECT_EQ(ds.sem_perm.uid, kUid); 594 EXPECT_EQ(ds.sem_perm.gid, kGid); 595 EXPECT_EQ(ds.sem_perm.cuid, kUid); 596 EXPECT_EQ(ds.sem_perm.cgid, kGid); 597 EXPECT_EQ(ds.sem_perm.mode, 0600); 598 // Last semop time is not set on creation. 599 EXPECT_EQ(ds.sem_otime, 0); 600 EXPECT_GE(ds.sem_ctime, start_time); 601 EXPECT_EQ(ds.sem_nsems, 10); 602 603 // The timestamps only have a resolution of seconds; slow down so we actually 604 // see the timestamps change. 605 absl::SleepFor(absl::Seconds(1)); 606 607 // Set semid_ds structure of the set. 608 auto last_ctime = ds.sem_ctime; 609 start_time = time(nullptr); 610 struct semid_ds semid_to_set = {}; 611 semid_to_set.sem_perm.uid = kUid; 612 semid_to_set.sem_perm.gid = kGid; 613 semid_to_set.sem_perm.mode = 0666; 614 ASSERT_THAT(semctl(sem.get(), 0, IPC_SET, &semid_to_set), SyscallSucceeds()); 615 struct sembuf buf = {}; 616 buf.sem_op = 1; 617 ASSERT_THAT(semop(sem.get(), &buf, 1), SyscallSucceeds()); 618 619 EXPECT_THAT(semctl(sem.get(), 0, IPC_STAT, &ds), SyscallSucceeds()); 620 EXPECT_EQ(ds.sem_perm.mode, 0666); 621 EXPECT_GE(ds.sem_otime, start_time); 622 EXPECT_GT(ds.sem_ctime, last_ctime); 623 624 // An invalid semid fails the syscall with errno EINVAL. 625 EXPECT_THAT(semctl(sem.get() + 1, 0, IPC_STAT, &ds), 626 SyscallFailsWithErrno(EINVAL)); 627 628 // Make semaphore not readable and check the signal fails. 629 semid_to_set.sem_perm.mode = 0200; 630 ASSERT_THAT(semctl(sem.get(), 0, IPC_SET, &semid_to_set), SyscallSucceeds()); 631 EXPECT_THAT(semctl(sem.get(), 0, IPC_STAT, &ds), 632 SyscallFailsWithErrno(EACCES)); 633 } 634 635 // Calls semctl(semid, 0, cmd) until the returned value is >= target, an 636 // internal timeout expires, or semctl returns an error. 637 PosixErrorOr<int> WaitSemctl(int semid, int target, int cmd) { 638 constexpr absl::Duration timeout = absl::Seconds(10); 639 const auto deadline = absl::Now() + timeout; 640 int semcnt = 0; 641 while (absl::Now() < deadline) { 642 semcnt = semctl(semid, 0, cmd); 643 if (semcnt < 0) { 644 return PosixError(errno, "semctl(GETZCNT) failed"); 645 } 646 if (semcnt >= target) { 647 break; 648 } 649 absl::SleepFor(absl::Milliseconds(10)); 650 } 651 return semcnt; 652 } 653 654 TEST(SemaphoreTest, SemopGetzcnt) { 655 // Drop CAP_IPC_OWNER which allows us to bypass semaphore permissions. 656 AutoCapability cap(CAP_IPC_OWNER, false); 657 // Create a write only semaphore set. 658 AutoSem sem(semget(IPC_PRIVATE, 1, 0200 | IPC_CREAT)); 659 ASSERT_THAT(sem.get(), SyscallSucceeds()); 660 661 // No read permission to retrieve semzcnt. 662 EXPECT_THAT(semctl(sem.get(), 0, GETZCNT), SyscallFailsWithErrno(EACCES)); 663 664 // Remove the calling thread's read permission. 665 struct semid_ds ds = {}; 666 ds.sem_perm.uid = getuid(); 667 ds.sem_perm.gid = getgid(); 668 ds.sem_perm.mode = 0600; 669 ASSERT_THAT(semctl(sem.get(), 0, IPC_SET, &ds), SyscallSucceeds()); 670 671 std::vector<pid_t> children; 672 ASSERT_THAT(semctl(sem.get(), 0, SETVAL, 1), SyscallSucceeds()); 673 674 struct sembuf buf = {}; 675 buf.sem_num = 0; 676 buf.sem_op = 0; 677 constexpr size_t kLoops = 10; 678 for (size_t i = 0; i < kLoops; i++) { 679 auto child_pid = fork(); 680 if (child_pid == 0) { 681 TEST_PCHECK(RetryEINTR(semop)(sem.get(), &buf, 1) == 0); 682 _exit(0); 683 } 684 children.push_back(child_pid); 685 } 686 687 EXPECT_THAT(WaitSemctl(sem.get(), kLoops, GETZCNT), 688 IsPosixErrorOkAndHolds(kLoops)); 689 // Set semval to 0, which wakes up children that sleep on the semop. 690 ASSERT_THAT(semctl(sem.get(), 0, SETVAL, 0), SyscallSucceeds()); 691 for (const auto& child_pid : children) { 692 int status; 693 ASSERT_THAT(RetryEINTR(waitpid)(child_pid, &status, 0), 694 SyscallSucceedsWithValue(child_pid)); 695 EXPECT_TRUE(WIFEXITED(status) && WEXITSTATUS(status) == 0); 696 } 697 EXPECT_EQ(semctl(sem.get(), 0, GETZCNT), 0); 698 } 699 700 TEST(SemaphoreTest, SemopGetzcntOnSetRemoval) { 701 auto semid = semget(IPC_PRIVATE, 1, 0600 | IPC_CREAT); 702 ASSERT_THAT(semid, SyscallSucceeds()); 703 ASSERT_THAT(semctl(semid, 0, SETVAL, 1), SyscallSucceeds()); 704 ASSERT_EQ(semctl(semid, 0, GETZCNT), 0); 705 706 auto child_pid = fork(); 707 if (child_pid == 0) { 708 struct sembuf buf = {}; 709 buf.sem_num = 0; 710 buf.sem_op = 0; 711 712 // Ensure that wait will only unblock when the semaphore is removed. On 713 // EINTR retry it may race with deletion and return EINVAL. 714 TEST_PCHECK(RetryEINTR(semop)(semid, &buf, 1) < 0 && 715 (errno == EIDRM || errno == EINVAL)); 716 _exit(0); 717 } 718 719 EXPECT_THAT(WaitSemctl(semid, 1, GETZCNT), IsPosixErrorOkAndHolds(1)); 720 // Remove the semaphore set, which fails the sleep semop. 721 ASSERT_THAT(semctl(semid, 0, IPC_RMID), SyscallSucceeds()); 722 int status; 723 ASSERT_THAT(RetryEINTR(waitpid)(child_pid, &status, 0), 724 SyscallSucceedsWithValue(child_pid)); 725 EXPECT_TRUE(WIFEXITED(status) && WEXITSTATUS(status) == 0); 726 EXPECT_THAT(semctl(semid, 0, GETZCNT), SyscallFailsWithErrno(EINVAL)); 727 } 728 729 TEST(SemaphoreTest, SemopGetzcntOnSignal) { 730 AutoSem sem(semget(IPC_PRIVATE, 1, 0600 | IPC_CREAT)); 731 ASSERT_THAT(sem.get(), SyscallSucceeds()); 732 ASSERT_THAT(semctl(sem.get(), 0, SETVAL, 1), SyscallSucceeds()); 733 ASSERT_EQ(semctl(sem.get(), 0, GETZCNT), 0); 734 735 // Saving will cause semop() to be spuriously interrupted. 736 DisableSave ds; 737 738 auto child_pid = fork(); 739 if (child_pid == 0) { 740 TEST_PCHECK(signal(SIGHUP, [](int sig) -> void {}) != SIG_ERR); 741 struct sembuf buf = {}; 742 buf.sem_num = 0; 743 buf.sem_op = 0; 744 745 TEST_PCHECK(semop(sem.get(), &buf, 1) < 0 && errno == EINTR); 746 _exit(0); 747 } 748 749 EXPECT_THAT(WaitSemctl(sem.get(), 1, GETZCNT), IsPosixErrorOkAndHolds(1)); 750 // Send a signal to the child, which fails the sleep semop. 751 ASSERT_EQ(kill(child_pid, SIGHUP), 0); 752 753 ds.reset(); 754 755 int status; 756 ASSERT_THAT(RetryEINTR(waitpid)(child_pid, &status, 0), 757 SyscallSucceedsWithValue(child_pid)); 758 EXPECT_TRUE(WIFEXITED(status) && WEXITSTATUS(status) == 0); 759 EXPECT_EQ(semctl(sem.get(), 0, GETZCNT), 0); 760 } 761 762 TEST(SemaphoreTest, SemopGetncnt) { 763 // Drop CAP_IPC_OWNER which allows us to bypass semaphore permissions. 764 AutoCapability cap(CAP_IPC_OWNER, false); 765 // Create a write only semaphore set. 766 AutoSem sem(semget(IPC_PRIVATE, 1, 0200 | IPC_CREAT)); 767 ASSERT_THAT(sem.get(), SyscallSucceeds()); 768 769 // No read permission to retrieve semzcnt. 770 EXPECT_THAT(semctl(sem.get(), 0, GETNCNT), SyscallFailsWithErrno(EACCES)); 771 772 // Remove the calling thread's read permission. 773 struct semid_ds ds = {}; 774 ds.sem_perm.uid = getuid(); 775 ds.sem_perm.gid = getgid(); 776 ds.sem_perm.mode = 0600; 777 ASSERT_THAT(semctl(sem.get(), 0, IPC_SET, &ds), SyscallSucceeds()); 778 779 std::vector<pid_t> children; 780 781 struct sembuf buf = {}; 782 buf.sem_num = 0; 783 buf.sem_op = -1; 784 constexpr size_t kLoops = 10; 785 for (size_t i = 0; i < kLoops; i++) { 786 auto child_pid = fork(); 787 if (child_pid == 0) { 788 TEST_PCHECK(RetryEINTR(semop)(sem.get(), &buf, 1) == 0); 789 _exit(0); 790 } 791 children.push_back(child_pid); 792 } 793 EXPECT_THAT(WaitSemctl(sem.get(), kLoops, GETNCNT), 794 IsPosixErrorOkAndHolds(kLoops)); 795 // Set semval to 1, which wakes up children that sleep on the semop. 796 ASSERT_THAT(semctl(sem.get(), 0, SETVAL, kLoops), SyscallSucceeds()); 797 for (const auto& child_pid : children) { 798 int status; 799 ASSERT_THAT(RetryEINTR(waitpid)(child_pid, &status, 0), 800 SyscallSucceedsWithValue(child_pid)); 801 EXPECT_TRUE(WIFEXITED(status) && WEXITSTATUS(status) == 0); 802 } 803 EXPECT_EQ(semctl(sem.get(), 0, GETNCNT), 0); 804 } 805 806 TEST(SemaphoreTest, SemopGetncntOnSetRemoval) { 807 auto semid = semget(IPC_PRIVATE, 1, 0600 | IPC_CREAT); 808 ASSERT_THAT(semid, SyscallSucceeds()); 809 ASSERT_EQ(semctl(semid, 0, GETNCNT), 0); 810 811 auto child_pid = fork(); 812 if (child_pid == 0) { 813 struct sembuf buf = {}; 814 buf.sem_num = 0; 815 buf.sem_op = -1; 816 817 // Ensure that wait will only unblock when the semaphore is removed. On 818 // EINTR retry it may race with deletion and return EINVAL 819 TEST_PCHECK(RetryEINTR(semop)(semid, &buf, 1) < 0 && 820 (errno == EIDRM || errno == EINVAL)); 821 _exit(0); 822 } 823 824 EXPECT_THAT(WaitSemctl(semid, 1, GETNCNT), IsPosixErrorOkAndHolds(1)); 825 // Remove the semaphore set, which fails the sleep semop. 826 ASSERT_THAT(semctl(semid, 0, IPC_RMID), SyscallSucceeds()); 827 int status; 828 ASSERT_THAT(RetryEINTR(waitpid)(child_pid, &status, 0), 829 SyscallSucceedsWithValue(child_pid)); 830 EXPECT_TRUE(WIFEXITED(status) && WEXITSTATUS(status) == 0); 831 EXPECT_THAT(semctl(semid, 0, GETNCNT), SyscallFailsWithErrno(EINVAL)); 832 } 833 834 TEST(SemaphoreTest, SemopGetncntOnSignal) { 835 AutoSem sem(semget(IPC_PRIVATE, 1, 0600 | IPC_CREAT)); 836 ASSERT_THAT(sem.get(), SyscallSucceeds()); 837 ASSERT_EQ(semctl(sem.get(), 0, GETNCNT), 0); 838 839 // Saving will cause semop() to be spuriously interrupted. 840 DisableSave ds; 841 842 auto child_pid = fork(); 843 if (child_pid == 0) { 844 TEST_PCHECK(signal(SIGHUP, [](int sig) -> void {}) != SIG_ERR); 845 struct sembuf buf = {}; 846 buf.sem_num = 0; 847 buf.sem_op = -1; 848 849 TEST_PCHECK(semop(sem.get(), &buf, 1) < 0 && errno == EINTR); 850 _exit(0); 851 } 852 EXPECT_THAT(WaitSemctl(sem.get(), 1, GETNCNT), IsPosixErrorOkAndHolds(1)); 853 // Send a signal to the child, which fails the sleep semop. 854 ASSERT_EQ(kill(child_pid, SIGHUP), 0); 855 856 ds.reset(); 857 858 int status; 859 ASSERT_THAT(RetryEINTR(waitpid)(child_pid, &status, 0), 860 SyscallSucceedsWithValue(child_pid)); 861 EXPECT_TRUE(WIFEXITED(status) && WEXITSTATUS(status) == 0); 862 EXPECT_EQ(semctl(sem.get(), 0, GETNCNT), 0); 863 } 864 865 #ifndef SEM_STAT_ANY 866 #define SEM_STAT_ANY 20 867 #endif // SEM_STAT_ANY 868 869 TEST(SemaphoreTest, IpcInfo) { 870 constexpr int kLoops = 5; 871 std::set<int> sem_ids; 872 struct seminfo info; 873 // Drop CAP_IPC_OWNER which allows us to bypass semaphore permissions. 874 AutoCapability cap(CAP_IPC_OWNER, false); 875 for (int i = 0; i < kLoops; i++) { 876 AutoSem sem(semget(IPC_PRIVATE, 1, 0600 | IPC_CREAT)); 877 ASSERT_THAT(sem.get(), SyscallSucceeds()); 878 sem_ids.insert(sem.release()); 879 } 880 ASSERT_EQ(sem_ids.size(), kLoops); 881 882 int max_used_index = 0; 883 EXPECT_THAT(max_used_index = semctl(0, 0, IPC_INFO, &info), 884 SyscallSucceeds()); 885 886 std::set<int> sem_ids_before_max_index; 887 for (int i = 0; i <= max_used_index; i++) { 888 struct semid_ds ds = {}; 889 int sem_id = semctl(i, 0, SEM_STAT, &ds); 890 // Only if index i is used within the registry. 891 if (sem_ids.find(sem_id) != sem_ids.end()) { 892 struct semid_ds ipc_stat_ds; 893 ASSERT_THAT(semctl(sem_id, 0, IPC_STAT, &ipc_stat_ds), SyscallSucceeds()); 894 EXPECT_TRUE(ds == ipc_stat_ds); 895 896 // Remove the semaphore set's read permission. 897 struct semid_ds ipc_set_ds; 898 ipc_set_ds.sem_perm.uid = getuid(); 899 ipc_set_ds.sem_perm.gid = getgid(); 900 // Keep the semaphore set's write permission so that it could be removed. 901 ipc_set_ds.sem_perm.mode = 0200; 902 // IPC_SET command here updates sem_ctime member of the sem. 903 ASSERT_THAT(semctl(sem_id, 0, IPC_SET, &ipc_set_ds), SyscallSucceeds()); 904 ASSERT_THAT(semctl(i, 0, SEM_STAT, &ds), SyscallFailsWithErrno(EACCES)); 905 int val = semctl(i, 0, SEM_STAT_ANY, &ds); 906 if (val == -1) { 907 // Only if the kernel doesn't support the command SEM_STAT_ANY. 908 EXPECT_TRUE(errno == EINVAL || errno == EFAULT); 909 } else { 910 EXPECT_EQ(sem_id, val); 911 EXPECT_LE(ipc_stat_ds.sem_ctime, ds.sem_ctime); 912 ipc_stat_ds.sem_ctime = 0; 913 ipc_stat_ds.sem_perm.mode = 0200; 914 ds.sem_ctime = 0; 915 EXPECT_TRUE(ipc_stat_ds == ds); 916 } 917 sem_ids_before_max_index.insert(sem_id); 918 } 919 } 920 EXPECT_EQ(sem_ids_before_max_index.size(), kLoops); 921 for (const int sem_id : sem_ids) { 922 ASSERT_THAT(semctl(sem_id, 0, IPC_RMID), SyscallSucceeds()); 923 } 924 925 ASSERT_THAT(semctl(0, 0, IPC_INFO, &info), SyscallSucceeds()); 926 EXPECT_EQ(info.semmap, kSemMap); 927 EXPECT_EQ(info.semmni, kSemMni); 928 EXPECT_EQ(info.semmns, kSemMns); 929 EXPECT_EQ(info.semmnu, kSemMnu); 930 EXPECT_EQ(info.semmsl, kSemMsl); 931 EXPECT_EQ(info.semopm, kSemOpm); 932 EXPECT_EQ(info.semume, kSemUme); 933 EXPECT_EQ(info.semusz, kSemUsz); 934 EXPECT_EQ(info.semvmx, kSemVmx); 935 EXPECT_EQ(info.semaem, kSemAem); 936 } 937 938 TEST(SemaphoreTest, SemInfo) { 939 constexpr int kLoops = 5; 940 constexpr int kSemSetSize = 3; 941 std::set<int> sem_ids; 942 struct seminfo info; 943 // Drop CAP_IPC_OWNER which allows us to bypass semaphore permissions. 944 AutoCapability cap(CAP_IPC_OWNER, false); 945 for (int i = 0; i < kLoops; i++) { 946 AutoSem sem(semget(IPC_PRIVATE, kSemSetSize, 0600 | IPC_CREAT)); 947 ASSERT_THAT(sem.get(), SyscallSucceeds()); 948 sem_ids.insert(sem.release()); 949 } 950 ASSERT_EQ(sem_ids.size(), kLoops); 951 int max_used_index = 0; 952 EXPECT_THAT(max_used_index = semctl(0, 0, SEM_INFO, &info), 953 SyscallSucceeds()); 954 EXPECT_EQ(info.semmap, kSemMap); 955 EXPECT_EQ(info.semmni, kSemMni); 956 EXPECT_EQ(info.semmns, kSemMns); 957 EXPECT_EQ(info.semmnu, kSemMnu); 958 EXPECT_EQ(info.semmsl, kSemMsl); 959 EXPECT_EQ(info.semopm, kSemOpm); 960 EXPECT_EQ(info.semume, kSemUme); 961 // There could be semaphores existing in the system during the test, which 962 // prevents the test from getting a exact number, but the test could expect at 963 // least the number of sempahroes it creates in the begining of the test. 964 EXPECT_GE(info.semusz, sem_ids.size()); 965 EXPECT_EQ(info.semvmx, kSemVmx); 966 EXPECT_GE(info.semaem, sem_ids.size() * kSemSetSize); 967 968 std::set<int> sem_ids_before_max_index; 969 for (int i = 0; i <= max_used_index; i++) { 970 struct semid_ds ds = {}; 971 int sem_id = semctl(i, 0, SEM_STAT, &ds); 972 // Only if index i is used within the registry. 973 if (sem_ids.find(sem_id) != sem_ids.end()) { 974 struct semid_ds ipc_stat_ds; 975 ASSERT_THAT(semctl(sem_id, 0, IPC_STAT, &ipc_stat_ds), SyscallSucceeds()); 976 EXPECT_TRUE(ds == ipc_stat_ds); 977 978 // Remove the semaphore set's read permission. 979 struct semid_ds ipc_set_ds; 980 ipc_set_ds.sem_perm.uid = getuid(); 981 ipc_set_ds.sem_perm.gid = getgid(); 982 // Keep the semaphore set's write permission so that it could be removed. 983 ipc_set_ds.sem_perm.mode = 0200; 984 // IPC_SET command here updates sem_ctime member of the sem. 985 ASSERT_THAT(semctl(sem_id, 0, IPC_SET, &ipc_set_ds), SyscallSucceeds()); 986 ASSERT_THAT(semctl(i, 0, SEM_STAT, &ds), SyscallFailsWithErrno(EACCES)); 987 int val = semctl(i, 0, SEM_STAT_ANY, &ds); 988 989 if (val == -1) { 990 // Only if the kernel doesn't support the command SEM_STAT_ANY. 991 EXPECT_TRUE(errno == EINVAL || errno == EFAULT); 992 } else { 993 EXPECT_EQ(val, sem_id); 994 EXPECT_LE(ipc_stat_ds.sem_ctime, ds.sem_ctime); 995 ipc_stat_ds.sem_ctime = 0; 996 ipc_stat_ds.sem_perm.mode = 0200; 997 ds.sem_ctime = 0; 998 EXPECT_TRUE(ipc_stat_ds == ds); 999 } 1000 sem_ids_before_max_index.insert(sem_id); 1001 } 1002 } 1003 EXPECT_EQ(sem_ids_before_max_index.size(), kLoops); 1004 for (const int sem_id : sem_ids) { 1005 ASSERT_THAT(semctl(sem_id, 0, IPC_RMID), SyscallSucceeds()); 1006 } 1007 1008 ASSERT_THAT(semctl(0, 0, SEM_INFO, &info), SyscallSucceeds()); 1009 EXPECT_EQ(info.semmap, kSemMap); 1010 EXPECT_EQ(info.semmni, kSemMni); 1011 EXPECT_EQ(info.semmns, kSemMns); 1012 EXPECT_EQ(info.semmnu, kSemMnu); 1013 EXPECT_EQ(info.semmsl, kSemMsl); 1014 EXPECT_EQ(info.semopm, kSemOpm); 1015 EXPECT_EQ(info.semume, kSemUme); 1016 // Apart from semapahores that are not created by the test, we can't determine 1017 // the exact number of semaphore sets and semaphores, as a result, semusz and 1018 // semaem range from 0 to a random number. Since the numbers are always 1019 // non-negative, the test will not check the reslts of semusz and semaem. 1020 EXPECT_EQ(info.semvmx, kSemVmx); 1021 } 1022 1023 TEST(SempahoreTest, RemoveNonExistentSemaphore) { 1024 EXPECT_THAT(semctl(-1, 0, IPC_RMID), SyscallFailsWithErrno(EINVAL)); 1025 } 1026 1027 TEST(SempahoreTest, RemoveDeletedSemaphore) { 1028 int id; 1029 EXPECT_THAT(id = semget(IPC_PRIVATE, 1, 0), SyscallSucceeds()); 1030 EXPECT_THAT(semctl(id, 0, IPC_RMID), SyscallSucceeds()); 1031 EXPECT_THAT(semctl(id, 0, IPC_RMID), SyscallFailsWithErrno(EINVAL)); 1032 } 1033 1034 } // namespace 1035 } // namespace testing 1036 } // namespace gvisor