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