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