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