xref: /llvm-project/libc/test/integration/src/pthread/pthread_rwlock_test.cpp (revision 03841e7ab847b279d65be707a8e0f2799fd69f50)
141fecca9SSchrodinger ZHU Yifan //===-- Tests for pthread_rwlock ------------------------------------------===//
241fecca9SSchrodinger ZHU Yifan //
341fecca9SSchrodinger ZHU Yifan // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
441fecca9SSchrodinger ZHU Yifan // See https://llvm.org/LICENSE.txt for license information.
541fecca9SSchrodinger ZHU Yifan // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
641fecca9SSchrodinger ZHU Yifan //
741fecca9SSchrodinger ZHU Yifan //===----------------------------------------------------------------------===//
841fecca9SSchrodinger ZHU Yifan 
9*03841e7aSSchrodinger ZHU Yifan #include "hdr/errno_macros.h"
10*03841e7aSSchrodinger ZHU Yifan #include "hdr/time_macros.h"
1141fecca9SSchrodinger ZHU Yifan #include "src/__support/CPP/atomic.h"
12c091dd48SSchrodinger ZHU Yifan #include "src/__support/CPP/new.h"
1341fecca9SSchrodinger ZHU Yifan #include "src/__support/OSUtil/syscall.h"
145ff3ff33SPetr Hosek #include "src/__support/macros/config.h"
1541fecca9SSchrodinger ZHU Yifan #include "src/__support/threads/linux/raw_mutex.h"
1641fecca9SSchrodinger ZHU Yifan #include "src/__support/threads/linux/rwlock.h"
1741fecca9SSchrodinger ZHU Yifan #include "src/__support/threads/sleep.h"
1841fecca9SSchrodinger ZHU Yifan #include "src/pthread/pthread_create.h"
1941fecca9SSchrodinger ZHU Yifan #include "src/pthread/pthread_join.h"
2044df89ccSEric977 #include "src/pthread/pthread_rwlock_clockrdlock.h"
2144df89ccSEric977 #include "src/pthread/pthread_rwlock_clockwrlock.h"
2241fecca9SSchrodinger ZHU Yifan #include "src/pthread/pthread_rwlock_destroy.h"
2341fecca9SSchrodinger ZHU Yifan #include "src/pthread/pthread_rwlock_init.h"
2441fecca9SSchrodinger ZHU Yifan #include "src/pthread/pthread_rwlock_rdlock.h"
2541fecca9SSchrodinger ZHU Yifan #include "src/pthread/pthread_rwlock_timedrdlock.h"
2641fecca9SSchrodinger ZHU Yifan #include "src/pthread/pthread_rwlock_timedwrlock.h"
2741fecca9SSchrodinger ZHU Yifan #include "src/pthread/pthread_rwlock_tryrdlock.h"
2841fecca9SSchrodinger ZHU Yifan #include "src/pthread/pthread_rwlock_trywrlock.h"
2941fecca9SSchrodinger ZHU Yifan #include "src/pthread/pthread_rwlock_unlock.h"
3041fecca9SSchrodinger ZHU Yifan #include "src/pthread/pthread_rwlock_wrlock.h"
3141fecca9SSchrodinger ZHU Yifan #include "src/pthread/pthread_rwlockattr_destroy.h"
3241fecca9SSchrodinger ZHU Yifan #include "src/pthread/pthread_rwlockattr_init.h"
3341fecca9SSchrodinger ZHU Yifan #include "src/pthread/pthread_rwlockattr_setkind_np.h"
3441fecca9SSchrodinger ZHU Yifan #include "src/pthread/pthread_rwlockattr_setpshared.h"
3541fecca9SSchrodinger ZHU Yifan #include "src/stdio/printf.h"
3641fecca9SSchrodinger ZHU Yifan #include "src/stdlib/exit.h"
3741fecca9SSchrodinger ZHU Yifan #include "src/stdlib/getenv.h"
3841fecca9SSchrodinger ZHU Yifan #include "src/sys/mman/mmap.h"
3941fecca9SSchrodinger ZHU Yifan #include "src/sys/mman/munmap.h"
4041fecca9SSchrodinger ZHU Yifan #include "src/sys/random/getrandom.h"
4141fecca9SSchrodinger ZHU Yifan #include "src/sys/wait/waitpid.h"
4241fecca9SSchrodinger ZHU Yifan #include "src/time/clock_gettime.h"
4341fecca9SSchrodinger ZHU Yifan #include "src/unistd/fork.h"
4441fecca9SSchrodinger ZHU Yifan #include "test/IntegrationTest/test.h"
4541fecca9SSchrodinger ZHU Yifan #include <pthread.h>
4641fecca9SSchrodinger ZHU Yifan 
475ff3ff33SPetr Hosek namespace LIBC_NAMESPACE_DECL {
485ff3ff33SPetr Hosek namespace rwlock {
4941fecca9SSchrodinger ZHU Yifan class RwLockTester {
5041fecca9SSchrodinger ZHU Yifan public:
5141fecca9SSchrodinger ZHU Yifan   static constexpr int full_reader_state() {
5241fecca9SSchrodinger ZHU Yifan     return (~0) & (~RwState::PENDING_MASK) & (~RwState::ACTIVE_WRITER_BIT);
5341fecca9SSchrodinger ZHU Yifan   }
5441fecca9SSchrodinger ZHU Yifan };
555ff3ff33SPetr Hosek } // namespace rwlock
565ff3ff33SPetr Hosek } // namespace LIBC_NAMESPACE_DECL
5741fecca9SSchrodinger ZHU Yifan 
5841fecca9SSchrodinger ZHU Yifan static void smoke_test() {
5941fecca9SSchrodinger ZHU Yifan   pthread_rwlock_t rwlock = PTHREAD_RWLOCK_INITIALIZER;
6041fecca9SSchrodinger ZHU Yifan   ASSERT_EQ(LIBC_NAMESPACE::pthread_rwlock_init(&rwlock, nullptr), 0);
6141fecca9SSchrodinger ZHU Yifan   ASSERT_EQ(LIBC_NAMESPACE::pthread_rwlock_rdlock(&rwlock), 0);
6241fecca9SSchrodinger ZHU Yifan   ASSERT_EQ(LIBC_NAMESPACE::pthread_rwlock_tryrdlock(&rwlock), 0);
6341fecca9SSchrodinger ZHU Yifan   ASSERT_EQ(LIBC_NAMESPACE::pthread_rwlock_trywrlock(&rwlock), EBUSY);
6441fecca9SSchrodinger ZHU Yifan   ASSERT_EQ(LIBC_NAMESPACE::pthread_rwlock_unlock(&rwlock), 0);
6541fecca9SSchrodinger ZHU Yifan   ASSERT_EQ(LIBC_NAMESPACE::pthread_rwlock_unlock(&rwlock), 0);
6641fecca9SSchrodinger ZHU Yifan   ASSERT_EQ(LIBC_NAMESPACE::pthread_rwlock_wrlock(&rwlock), 0);
6741fecca9SSchrodinger ZHU Yifan   ASSERT_EQ(LIBC_NAMESPACE::pthread_rwlock_rdlock(&rwlock), EDEADLK);
6841fecca9SSchrodinger ZHU Yifan   ASSERT_EQ(LIBC_NAMESPACE::pthread_rwlock_wrlock(&rwlock), EDEADLK);
6941fecca9SSchrodinger ZHU Yifan   ASSERT_EQ(LIBC_NAMESPACE::pthread_rwlock_tryrdlock(&rwlock), EBUSY);
7041fecca9SSchrodinger ZHU Yifan   ASSERT_EQ(LIBC_NAMESPACE::pthread_rwlock_trywrlock(&rwlock), EBUSY);
7141fecca9SSchrodinger ZHU Yifan   ASSERT_EQ(LIBC_NAMESPACE::pthread_rwlock_unlock(&rwlock), 0);
7241fecca9SSchrodinger ZHU Yifan   ASSERT_EQ(LIBC_NAMESPACE::pthread_rwlock_destroy(&rwlock), 0);
7341fecca9SSchrodinger ZHU Yifan }
7441fecca9SSchrodinger ZHU Yifan 
7541fecca9SSchrodinger ZHU Yifan static void deadlock_detection_test() {
7641fecca9SSchrodinger ZHU Yifan   pthread_rwlock_t rwlock = PTHREAD_RWLOCK_INITIALIZER;
7741fecca9SSchrodinger ZHU Yifan   ASSERT_EQ(LIBC_NAMESPACE::pthread_rwlock_init(&rwlock, nullptr), 0);
7841fecca9SSchrodinger ZHU Yifan   // We only detect RAW, WAW deadlocks.
7941fecca9SSchrodinger ZHU Yifan   ASSERT_EQ(LIBC_NAMESPACE::pthread_rwlock_wrlock(&rwlock), 0);
8041fecca9SSchrodinger ZHU Yifan   ASSERT_EQ(LIBC_NAMESPACE::pthread_rwlock_wrlock(&rwlock), EDEADLK);
8141fecca9SSchrodinger ZHU Yifan   ASSERT_EQ(LIBC_NAMESPACE::pthread_rwlock_unlock(&rwlock), 0);
8241fecca9SSchrodinger ZHU Yifan   ASSERT_EQ(LIBC_NAMESPACE::pthread_rwlock_destroy(&rwlock), 0);
8341fecca9SSchrodinger ZHU Yifan }
8441fecca9SSchrodinger ZHU Yifan 
8541fecca9SSchrodinger ZHU Yifan static void try_lock_test() {
8641fecca9SSchrodinger ZHU Yifan   pthread_rwlock_t rwlock = PTHREAD_RWLOCK_INITIALIZER;
8741fecca9SSchrodinger ZHU Yifan   ASSERT_EQ(LIBC_NAMESPACE::pthread_rwlock_init(&rwlock, nullptr), 0);
8841fecca9SSchrodinger ZHU Yifan   ASSERT_EQ(LIBC_NAMESPACE::pthread_rwlock_wrlock(&rwlock), 0);
8941fecca9SSchrodinger ZHU Yifan   ASSERT_EQ(LIBC_NAMESPACE::pthread_rwlock_trywrlock(&rwlock), EBUSY);
9041fecca9SSchrodinger ZHU Yifan   ASSERT_EQ(LIBC_NAMESPACE::pthread_rwlock_tryrdlock(&rwlock), EBUSY);
9141fecca9SSchrodinger ZHU Yifan   ASSERT_EQ(LIBC_NAMESPACE::pthread_rwlock_unlock(&rwlock), 0);
9241fecca9SSchrodinger ZHU Yifan   ASSERT_EQ(LIBC_NAMESPACE::pthread_rwlock_tryrdlock(&rwlock), 0);
9341fecca9SSchrodinger ZHU Yifan   ASSERT_EQ(LIBC_NAMESPACE::pthread_rwlock_rdlock(&rwlock), 0);
9441fecca9SSchrodinger ZHU Yifan   ASSERT_EQ(LIBC_NAMESPACE::pthread_rwlock_tryrdlock(&rwlock), 0);
9541fecca9SSchrodinger ZHU Yifan   ASSERT_EQ(LIBC_NAMESPACE::pthread_rwlock_trywrlock(&rwlock), EBUSY);
9641fecca9SSchrodinger ZHU Yifan   ASSERT_EQ(LIBC_NAMESPACE::pthread_rwlock_unlock(&rwlock), 0);
9741fecca9SSchrodinger ZHU Yifan   ASSERT_EQ(LIBC_NAMESPACE::pthread_rwlock_unlock(&rwlock), 0);
9841fecca9SSchrodinger ZHU Yifan   ASSERT_EQ(LIBC_NAMESPACE::pthread_rwlock_unlock(&rwlock), 0);
9941fecca9SSchrodinger ZHU Yifan   ASSERT_EQ(LIBC_NAMESPACE::pthread_rwlock_destroy(&rwlock), 0);
10041fecca9SSchrodinger ZHU Yifan }
10141fecca9SSchrodinger ZHU Yifan 
10241fecca9SSchrodinger ZHU Yifan static void destroy_before_unlock_test() {
10341fecca9SSchrodinger ZHU Yifan   pthread_rwlock_t rwlock = PTHREAD_RWLOCK_INITIALIZER;
10441fecca9SSchrodinger ZHU Yifan   ASSERT_EQ(LIBC_NAMESPACE::pthread_rwlock_init(&rwlock, nullptr), 0);
10541fecca9SSchrodinger ZHU Yifan   ASSERT_EQ(LIBC_NAMESPACE::pthread_rwlock_wrlock(&rwlock), 0);
10641fecca9SSchrodinger ZHU Yifan   ASSERT_EQ(LIBC_NAMESPACE::pthread_rwlock_destroy(&rwlock), EBUSY);
10741fecca9SSchrodinger ZHU Yifan   ASSERT_EQ(LIBC_NAMESPACE::pthread_rwlock_unlock(&rwlock), 0);
10841fecca9SSchrodinger ZHU Yifan   ASSERT_EQ(LIBC_NAMESPACE::pthread_rwlock_destroy(&rwlock), 0);
10941fecca9SSchrodinger ZHU Yifan }
11041fecca9SSchrodinger ZHU Yifan 
11141fecca9SSchrodinger ZHU Yifan static void nullptr_test() {
11241fecca9SSchrodinger ZHU Yifan   timespec ts = {};
11341fecca9SSchrodinger ZHU Yifan   ASSERT_EQ(LIBC_NAMESPACE::pthread_rwlock_rdlock(nullptr), EINVAL);
11441fecca9SSchrodinger ZHU Yifan   ASSERT_EQ(LIBC_NAMESPACE::pthread_rwlock_wrlock(nullptr), EINVAL);
11541fecca9SSchrodinger ZHU Yifan   ASSERT_EQ(LIBC_NAMESPACE::pthread_rwlock_timedrdlock(nullptr, &ts), EINVAL);
11641fecca9SSchrodinger ZHU Yifan   ASSERT_EQ(LIBC_NAMESPACE::pthread_rwlock_timedwrlock(nullptr, &ts), EINVAL);
11744df89ccSEric977   ASSERT_EQ(
11844df89ccSEric977       LIBC_NAMESPACE::pthread_rwlock_clockrdlock(nullptr, CLOCK_MONOTONIC, &ts),
11944df89ccSEric977       EINVAL);
12044df89ccSEric977   ASSERT_EQ(
12144df89ccSEric977       LIBC_NAMESPACE::pthread_rwlock_clockwrlock(nullptr, CLOCK_MONOTONIC, &ts),
12244df89ccSEric977       EINVAL);
12341fecca9SSchrodinger ZHU Yifan   ASSERT_EQ(LIBC_NAMESPACE::pthread_rwlock_tryrdlock(nullptr), EINVAL);
12441fecca9SSchrodinger ZHU Yifan   ASSERT_EQ(LIBC_NAMESPACE::pthread_rwlock_trywrlock(nullptr), EINVAL);
12541fecca9SSchrodinger ZHU Yifan   ASSERT_EQ(LIBC_NAMESPACE::pthread_rwlock_unlock(nullptr), EINVAL);
12641fecca9SSchrodinger ZHU Yifan   ASSERT_EQ(LIBC_NAMESPACE::pthread_rwlock_destroy(nullptr), EINVAL);
12741fecca9SSchrodinger ZHU Yifan }
12841fecca9SSchrodinger ZHU Yifan 
12941fecca9SSchrodinger ZHU Yifan // If you are a user reading this code, please do not do something like this.
13041fecca9SSchrodinger ZHU Yifan // We manually modify the internal state of the rwlock to test high reader
13141fecca9SSchrodinger ZHU Yifan // counts.
13241fecca9SSchrodinger ZHU Yifan static void high_reader_count_test() {
13341fecca9SSchrodinger ZHU Yifan   pthread_rwlock_t rwlock = PTHREAD_RWLOCK_INITIALIZER;
13441fecca9SSchrodinger ZHU Yifan   rwlock.__state = LIBC_NAMESPACE::rwlock::RwLockTester::full_reader_state();
13541fecca9SSchrodinger ZHU Yifan   ASSERT_EQ(LIBC_NAMESPACE::pthread_rwlock_rdlock(&rwlock), EAGAIN);
13641fecca9SSchrodinger ZHU Yifan   ASSERT_EQ(LIBC_NAMESPACE::pthread_rwlock_tryrdlock(&rwlock), EAGAIN);
13741fecca9SSchrodinger ZHU Yifan   // allocate 4 reader slots.
13841fecca9SSchrodinger ZHU Yifan   ASSERT_EQ(LIBC_NAMESPACE::pthread_rwlock_unlock(&rwlock), 0);
13941fecca9SSchrodinger ZHU Yifan   ASSERT_EQ(LIBC_NAMESPACE::pthread_rwlock_unlock(&rwlock), 0);
14041fecca9SSchrodinger ZHU Yifan   ASSERT_EQ(LIBC_NAMESPACE::pthread_rwlock_unlock(&rwlock), 0);
14141fecca9SSchrodinger ZHU Yifan   ASSERT_EQ(LIBC_NAMESPACE::pthread_rwlock_unlock(&rwlock), 0);
14241fecca9SSchrodinger ZHU Yifan 
14341fecca9SSchrodinger ZHU Yifan   pthread_t threads[20];
14441fecca9SSchrodinger ZHU Yifan   for (auto &i : threads)
14541fecca9SSchrodinger ZHU Yifan     ASSERT_EQ(LIBC_NAMESPACE::pthread_create(
14641fecca9SSchrodinger ZHU Yifan                   &i, nullptr,
14741fecca9SSchrodinger ZHU Yifan                   [](void *arg) -> void * {
14841fecca9SSchrodinger ZHU Yifan                     pthread_rwlock_t *rwlock =
14941fecca9SSchrodinger ZHU Yifan                         reinterpret_cast<pthread_rwlock_t *>(arg);
15041fecca9SSchrodinger ZHU Yifan                     ASSERT_EQ(LIBC_NAMESPACE::pthread_rwlock_trywrlock(rwlock),
15141fecca9SSchrodinger ZHU Yifan                               EBUSY);
15241fecca9SSchrodinger ZHU Yifan                     while (LIBC_NAMESPACE::pthread_rwlock_rdlock(rwlock) ==
15341fecca9SSchrodinger ZHU Yifan                            EAGAIN)
15441fecca9SSchrodinger ZHU Yifan                       LIBC_NAMESPACE::sleep_briefly();
15541fecca9SSchrodinger ZHU Yifan                     ASSERT_EQ(LIBC_NAMESPACE::pthread_rwlock_unlock(rwlock), 0);
15641fecca9SSchrodinger ZHU Yifan                     return nullptr;
15741fecca9SSchrodinger ZHU Yifan                   },
15841fecca9SSchrodinger ZHU Yifan                   &rwlock),
15941fecca9SSchrodinger ZHU Yifan               0);
16041fecca9SSchrodinger ZHU Yifan 
16141fecca9SSchrodinger ZHU Yifan   for (auto &i : threads)
16241fecca9SSchrodinger ZHU Yifan     ASSERT_EQ(LIBC_NAMESPACE::pthread_join(i, nullptr), 0);
16341fecca9SSchrodinger ZHU Yifan }
16441fecca9SSchrodinger ZHU Yifan 
16541fecca9SSchrodinger ZHU Yifan static void unusual_timespec_test() {
16641fecca9SSchrodinger ZHU Yifan   pthread_rwlock_t rwlock = PTHREAD_RWLOCK_INITIALIZER;
16741fecca9SSchrodinger ZHU Yifan   timespec ts = {0, -1};
16841fecca9SSchrodinger ZHU Yifan   ASSERT_EQ(LIBC_NAMESPACE::pthread_rwlock_timedrdlock(&rwlock, &ts), EINVAL);
16941fecca9SSchrodinger ZHU Yifan   ASSERT_EQ(LIBC_NAMESPACE::pthread_rwlock_timedwrlock(&rwlock, &ts), EINVAL);
17044df89ccSEric977   ASSERT_EQ(
17144df89ccSEric977       LIBC_NAMESPACE::pthread_rwlock_clockrdlock(&rwlock, CLOCK_MONOTONIC, &ts),
17244df89ccSEric977       EINVAL);
17344df89ccSEric977   ASSERT_EQ(
17444df89ccSEric977       LIBC_NAMESPACE::pthread_rwlock_clockwrlock(&rwlock, CLOCK_MONOTONIC, &ts),
17544df89ccSEric977       EINVAL);
17641fecca9SSchrodinger ZHU Yifan   ts.tv_nsec = 1'000'000'000;
17741fecca9SSchrodinger ZHU Yifan   ASSERT_EQ(LIBC_NAMESPACE::pthread_rwlock_timedrdlock(&rwlock, &ts), EINVAL);
17844df89ccSEric977   ASSERT_EQ(
17944df89ccSEric977       LIBC_NAMESPACE::pthread_rwlock_clockrdlock(&rwlock, CLOCK_MONOTONIC, &ts),
18044df89ccSEric977       EINVAL);
18144df89ccSEric977   ASSERT_EQ(
18244df89ccSEric977       LIBC_NAMESPACE::pthread_rwlock_clockwrlock(&rwlock, CLOCK_MONOTONIC, &ts),
18344df89ccSEric977       EINVAL);
18441fecca9SSchrodinger ZHU Yifan   ts.tv_nsec += 1;
18541fecca9SSchrodinger ZHU Yifan   ASSERT_EQ(LIBC_NAMESPACE::pthread_rwlock_timedwrlock(&rwlock, &ts), EINVAL);
18644df89ccSEric977   ASSERT_EQ(
18744df89ccSEric977       LIBC_NAMESPACE::pthread_rwlock_clockrdlock(&rwlock, CLOCK_MONOTONIC, &ts),
18844df89ccSEric977       EINVAL);
18944df89ccSEric977   ASSERT_EQ(
19044df89ccSEric977       LIBC_NAMESPACE::pthread_rwlock_clockwrlock(&rwlock, CLOCK_MONOTONIC, &ts),
19144df89ccSEric977       EINVAL);
19241fecca9SSchrodinger ZHU Yifan   ts.tv_nsec = 0;
19341fecca9SSchrodinger ZHU Yifan   ts.tv_sec = -1;
19441fecca9SSchrodinger ZHU Yifan   ASSERT_EQ(LIBC_NAMESPACE::pthread_rwlock_timedrdlock(&rwlock, &ts),
19541fecca9SSchrodinger ZHU Yifan             ETIMEDOUT);
19641fecca9SSchrodinger ZHU Yifan   ASSERT_EQ(LIBC_NAMESPACE::pthread_rwlock_timedwrlock(&rwlock, &ts),
19741fecca9SSchrodinger ZHU Yifan             ETIMEDOUT);
19844df89ccSEric977   ASSERT_EQ(
19944df89ccSEric977       LIBC_NAMESPACE::pthread_rwlock_clockrdlock(&rwlock, CLOCK_MONOTONIC, &ts),
20044df89ccSEric977       ETIMEDOUT);
20144df89ccSEric977   ASSERT_EQ(
20244df89ccSEric977       LIBC_NAMESPACE::pthread_rwlock_clockwrlock(&rwlock, CLOCK_MONOTONIC, &ts),
20344df89ccSEric977       ETIMEDOUT);
20441fecca9SSchrodinger ZHU Yifan }
20541fecca9SSchrodinger ZHU Yifan 
20641fecca9SSchrodinger ZHU Yifan static void timedlock_with_deadlock_test() {
20741fecca9SSchrodinger ZHU Yifan   pthread_rwlock_t rwlock = PTHREAD_RWLOCK_INITIALIZER;
20841fecca9SSchrodinger ZHU Yifan   timespec ts{};
20941fecca9SSchrodinger ZHU Yifan   ASSERT_EQ(LIBC_NAMESPACE::pthread_rwlock_rdlock(&rwlock), 0);
21041fecca9SSchrodinger ZHU Yifan   LIBC_NAMESPACE::clock_gettime(CLOCK_REALTIME, &ts);
21141fecca9SSchrodinger ZHU Yifan   ts.tv_nsec += 50'000;
21241fecca9SSchrodinger ZHU Yifan   if (ts.tv_nsec >= 1'000'000'000) {
21341fecca9SSchrodinger ZHU Yifan     ts.tv_nsec -= 1'000'000'000;
21441fecca9SSchrodinger ZHU Yifan     ts.tv_sec += 1;
21541fecca9SSchrodinger ZHU Yifan   }
21641fecca9SSchrodinger ZHU Yifan   ASSERT_EQ(LIBC_NAMESPACE::pthread_rwlock_timedwrlock(&rwlock, &ts),
21741fecca9SSchrodinger ZHU Yifan             ETIMEDOUT);
21841fecca9SSchrodinger ZHU Yifan   ASSERT_EQ(LIBC_NAMESPACE::pthread_rwlock_timedrdlock(&rwlock, &ts), 0);
21944df89ccSEric977   ASSERT_EQ(
2205cddc314SSchrodinger ZHU Yifan       LIBC_NAMESPACE::pthread_rwlock_clockwrlock(&rwlock, CLOCK_REALTIME, &ts),
22144df89ccSEric977       ETIMEDOUT);
22244df89ccSEric977   ASSERT_EQ(
2235cddc314SSchrodinger ZHU Yifan       LIBC_NAMESPACE::pthread_rwlock_clockrdlock(&rwlock, CLOCK_REALTIME, &ts),
22444df89ccSEric977       0);
22541fecca9SSchrodinger ZHU Yifan   ASSERT_EQ(LIBC_NAMESPACE::pthread_rwlock_unlock(&rwlock), 0);
22641fecca9SSchrodinger ZHU Yifan   ASSERT_EQ(LIBC_NAMESPACE::pthread_rwlock_unlock(&rwlock), 0);
2275cddc314SSchrodinger ZHU Yifan   ASSERT_EQ(LIBC_NAMESPACE::pthread_rwlock_unlock(&rwlock), 0);
22841fecca9SSchrodinger ZHU Yifan   // notice that ts is already expired, but the following should still succeed.
22941fecca9SSchrodinger ZHU Yifan   ASSERT_EQ(LIBC_NAMESPACE::pthread_rwlock_tryrdlock(&rwlock), 0);
23041fecca9SSchrodinger ZHU Yifan   ASSERT_EQ(LIBC_NAMESPACE::pthread_rwlock_unlock(&rwlock), 0);
23141fecca9SSchrodinger ZHU Yifan   ASSERT_EQ(LIBC_NAMESPACE::pthread_rwlock_trywrlock(&rwlock), 0);
23241fecca9SSchrodinger ZHU Yifan   ASSERT_EQ(LIBC_NAMESPACE::pthread_rwlock_unlock(&rwlock), 0);
23341fecca9SSchrodinger ZHU Yifan   ASSERT_EQ(LIBC_NAMESPACE::pthread_rwlock_rdlock(&rwlock), 0);
23441fecca9SSchrodinger ZHU Yifan   ASSERT_EQ(LIBC_NAMESPACE::pthread_rwlock_unlock(&rwlock), 0);
23541fecca9SSchrodinger ZHU Yifan   ASSERT_EQ(LIBC_NAMESPACE::pthread_rwlock_wrlock(&rwlock), 0);
23641fecca9SSchrodinger ZHU Yifan   ASSERT_EQ(LIBC_NAMESPACE::pthread_rwlock_unlock(&rwlock), 0);
23741fecca9SSchrodinger ZHU Yifan   ASSERT_EQ(LIBC_NAMESPACE::pthread_rwlock_destroy(&rwlock), 0);
23841fecca9SSchrodinger ZHU Yifan }
23941fecca9SSchrodinger ZHU Yifan 
24041fecca9SSchrodinger ZHU Yifan static void attributed_initialization_test() {
24141fecca9SSchrodinger ZHU Yifan   pthread_rwlockattr_t attr{};
24241fecca9SSchrodinger ZHU Yifan   ASSERT_EQ(LIBC_NAMESPACE::pthread_rwlockattr_init(&attr), 0);
24341fecca9SSchrodinger ZHU Yifan   ASSERT_EQ(LIBC_NAMESPACE::pthread_rwlockattr_setkind_np(
24441fecca9SSchrodinger ZHU Yifan                 &attr, PTHREAD_RWLOCK_PREFER_READER_NP),
24541fecca9SSchrodinger ZHU Yifan             0);
24641fecca9SSchrodinger ZHU Yifan   {
24741fecca9SSchrodinger ZHU Yifan     pthread_rwlock_t rwlock{};
24841fecca9SSchrodinger ZHU Yifan     ASSERT_EQ(LIBC_NAMESPACE::pthread_rwlock_init(&rwlock, &attr), 0);
24941fecca9SSchrodinger ZHU Yifan     ASSERT_EQ(LIBC_NAMESPACE::pthread_rwlock_destroy(&rwlock), 0);
25041fecca9SSchrodinger ZHU Yifan   }
25141fecca9SSchrodinger ZHU Yifan   ASSERT_EQ(LIBC_NAMESPACE::pthread_rwlockattr_setkind_np(
25241fecca9SSchrodinger ZHU Yifan                 &attr, PTHREAD_RWLOCK_PREFER_WRITER_NONRECURSIVE_NP),
25341fecca9SSchrodinger ZHU Yifan             0);
25441fecca9SSchrodinger ZHU Yifan   {
25541fecca9SSchrodinger ZHU Yifan     pthread_rwlock_t rwlock{};
25641fecca9SSchrodinger ZHU Yifan     ASSERT_EQ(LIBC_NAMESPACE::pthread_rwlock_init(&rwlock, &attr), 0);
25741fecca9SSchrodinger ZHU Yifan     ASSERT_EQ(LIBC_NAMESPACE::pthread_rwlock_destroy(&rwlock), 0);
25841fecca9SSchrodinger ZHU Yifan   }
25941fecca9SSchrodinger ZHU Yifan   ASSERT_EQ(LIBC_NAMESPACE::pthread_rwlockattr_setkind_np(
26041fecca9SSchrodinger ZHU Yifan                 &attr, PTHREAD_RWLOCK_PREFER_WRITER_NP),
26141fecca9SSchrodinger ZHU Yifan             0);
26241fecca9SSchrodinger ZHU Yifan   {
26341fecca9SSchrodinger ZHU Yifan     pthread_rwlock_t rwlock{};
26441fecca9SSchrodinger ZHU Yifan     ASSERT_EQ(LIBC_NAMESPACE::pthread_rwlock_init(&rwlock, &attr), EINVAL);
26541fecca9SSchrodinger ZHU Yifan   }
26641fecca9SSchrodinger ZHU Yifan   ASSERT_EQ(LIBC_NAMESPACE::pthread_rwlockattr_setkind_np(
26741fecca9SSchrodinger ZHU Yifan                 &attr, PTHREAD_RWLOCK_PREFER_READER_NP),
26841fecca9SSchrodinger ZHU Yifan             0);
26941fecca9SSchrodinger ZHU Yifan   ASSERT_EQ(LIBC_NAMESPACE::pthread_rwlockattr_setpshared(
27041fecca9SSchrodinger ZHU Yifan                 &attr, PTHREAD_PROCESS_PRIVATE),
27141fecca9SSchrodinger ZHU Yifan             0);
27241fecca9SSchrodinger ZHU Yifan   {
27341fecca9SSchrodinger ZHU Yifan     pthread_rwlock_t rwlock{};
27441fecca9SSchrodinger ZHU Yifan     ASSERT_EQ(LIBC_NAMESPACE::pthread_rwlock_init(&rwlock, &attr), 0);
27541fecca9SSchrodinger ZHU Yifan     ASSERT_EQ(LIBC_NAMESPACE::pthread_rwlock_destroy(&rwlock), 0);
27641fecca9SSchrodinger ZHU Yifan   }
27741fecca9SSchrodinger ZHU Yifan   ASSERT_EQ(LIBC_NAMESPACE::pthread_rwlockattr_setpshared(
27841fecca9SSchrodinger ZHU Yifan                 &attr, PTHREAD_PROCESS_SHARED),
27941fecca9SSchrodinger ZHU Yifan             0);
28041fecca9SSchrodinger ZHU Yifan   {
28141fecca9SSchrodinger ZHU Yifan     pthread_rwlock_t rwlock{};
28241fecca9SSchrodinger ZHU Yifan     ASSERT_EQ(LIBC_NAMESPACE::pthread_rwlock_init(&rwlock, &attr), 0);
28341fecca9SSchrodinger ZHU Yifan     ASSERT_EQ(LIBC_NAMESPACE::pthread_rwlock_destroy(&rwlock), 0);
28441fecca9SSchrodinger ZHU Yifan   }
28541fecca9SSchrodinger ZHU Yifan   attr.pref = -1;
28641fecca9SSchrodinger ZHU Yifan   {
28741fecca9SSchrodinger ZHU Yifan     pthread_rwlock_t rwlock{};
28841fecca9SSchrodinger ZHU Yifan     ASSERT_EQ(LIBC_NAMESPACE::pthread_rwlock_init(&rwlock, &attr), EINVAL);
28941fecca9SSchrodinger ZHU Yifan   }
29041fecca9SSchrodinger ZHU Yifan   attr.pref = PTHREAD_RWLOCK_PREFER_READER_NP;
29141fecca9SSchrodinger ZHU Yifan   attr.pshared = -1;
29241fecca9SSchrodinger ZHU Yifan   {
29341fecca9SSchrodinger ZHU Yifan     pthread_rwlock_t rwlock{};
29441fecca9SSchrodinger ZHU Yifan     ASSERT_EQ(LIBC_NAMESPACE::pthread_rwlock_init(&rwlock, &attr), EINVAL);
29541fecca9SSchrodinger ZHU Yifan   }
29641fecca9SSchrodinger ZHU Yifan   ASSERT_EQ(LIBC_NAMESPACE::pthread_rwlockattr_destroy(&attr), 0);
29741fecca9SSchrodinger ZHU Yifan }
29841fecca9SSchrodinger ZHU Yifan 
29941fecca9SSchrodinger ZHU Yifan struct SharedData {
30041fecca9SSchrodinger ZHU Yifan   pthread_rwlock_t lock;
30141fecca9SSchrodinger ZHU Yifan   int data;
30241fecca9SSchrodinger ZHU Yifan   LIBC_NAMESPACE::cpp::Atomic<int> reader_count;
30341fecca9SSchrodinger ZHU Yifan   bool writer_flag;
30441fecca9SSchrodinger ZHU Yifan   LIBC_NAMESPACE::cpp::Atomic<int> total_writer_count;
30541fecca9SSchrodinger ZHU Yifan };
30641fecca9SSchrodinger ZHU Yifan 
30741fecca9SSchrodinger ZHU Yifan enum class Operation : int {
30841fecca9SSchrodinger ZHU Yifan   READ = 0,
30941fecca9SSchrodinger ZHU Yifan   WRITE = 1,
31041fecca9SSchrodinger ZHU Yifan   TIMED_READ = 2,
31141fecca9SSchrodinger ZHU Yifan   TIMED_WRITE = 3,
31244df89ccSEric977   CLOCK_READ = 4,
31344df89ccSEric977   CLOCK_WRITE = 5,
31444df89ccSEric977   TRY_READ = 6,
31544df89ccSEric977   TRY_WRITE = 7,
31644df89ccSEric977   COUNT = 8
31741fecca9SSchrodinger ZHU Yifan };
31841fecca9SSchrodinger ZHU Yifan 
31941fecca9SSchrodinger ZHU Yifan LIBC_NAMESPACE::RawMutex *io_mutex;
32041fecca9SSchrodinger ZHU Yifan struct ThreadGuard {
32141fecca9SSchrodinger ZHU Yifan   Operation record[64]{};
32241fecca9SSchrodinger ZHU Yifan   size_t cursor = 0;
32341fecca9SSchrodinger ZHU Yifan   void push(Operation op) { record[cursor++] = op; }
32441fecca9SSchrodinger ZHU Yifan   ~ThreadGuard() {
32541fecca9SSchrodinger ZHU Yifan     if (!LIBC_NAMESPACE::getenv("LIBC_PTHREAD_RWLOCK_TEST_VERBOSE"))
32641fecca9SSchrodinger ZHU Yifan       return;
32741fecca9SSchrodinger ZHU Yifan     pid_t pid = LIBC_NAMESPACE::syscall_impl(SYS_getpid);
32841fecca9SSchrodinger ZHU Yifan     pid_t tid = LIBC_NAMESPACE::syscall_impl(SYS_gettid);
32941fecca9SSchrodinger ZHU Yifan     io_mutex->lock(LIBC_NAMESPACE::cpp::nullopt, true);
33041fecca9SSchrodinger ZHU Yifan     LIBC_NAMESPACE::printf("process %d thread %d: ", pid, tid);
33141fecca9SSchrodinger ZHU Yifan     for (size_t i = 0; i < cursor; ++i)
33241fecca9SSchrodinger ZHU Yifan       LIBC_NAMESPACE::printf("%d ", static_cast<int>(record[i]));
33341fecca9SSchrodinger ZHU Yifan     LIBC_NAMESPACE::printf("\n");
33441fecca9SSchrodinger ZHU Yifan     io_mutex->unlock(true);
33541fecca9SSchrodinger ZHU Yifan   }
33641fecca9SSchrodinger ZHU Yifan };
33741fecca9SSchrodinger ZHU Yifan 
33841fecca9SSchrodinger ZHU Yifan static void randomized_thread_operation(SharedData *data, ThreadGuard &guard) {
33941fecca9SSchrodinger ZHU Yifan   int buffer;
34041fecca9SSchrodinger ZHU Yifan   // We cannot reason about thread order anyway, let's go wild and randomize it
34141fecca9SSchrodinger ZHU Yifan   // directly using getrandom.
34241fecca9SSchrodinger ZHU Yifan   LIBC_NAMESPACE::getrandom(&buffer, sizeof(buffer), 0);
34341fecca9SSchrodinger ZHU Yifan   constexpr int TOTAL = static_cast<int>(Operation::COUNT);
34441fecca9SSchrodinger ZHU Yifan   Operation op = static_cast<Operation>(((buffer % TOTAL) + TOTAL) % TOTAL);
34541fecca9SSchrodinger ZHU Yifan   guard.push(op);
34641fecca9SSchrodinger ZHU Yifan   auto read_ops = [data]() {
34741fecca9SSchrodinger ZHU Yifan     ASSERT_FALSE(data->writer_flag);
34841fecca9SSchrodinger ZHU Yifan     data->reader_count.fetch_add(1, LIBC_NAMESPACE::cpp::MemoryOrder::RELAXED);
34941fecca9SSchrodinger ZHU Yifan     for (int i = 0; i < 10; ++i)
35041fecca9SSchrodinger ZHU Yifan       LIBC_NAMESPACE::sleep_briefly();
35141fecca9SSchrodinger ZHU Yifan     data->reader_count.fetch_sub(1, LIBC_NAMESPACE::cpp::MemoryOrder::RELAXED);
35241fecca9SSchrodinger ZHU Yifan   };
35341fecca9SSchrodinger ZHU Yifan   auto write_ops = [data]() {
35441fecca9SSchrodinger ZHU Yifan     ASSERT_FALSE(data->writer_flag);
35541fecca9SSchrodinger ZHU Yifan     data->data += 1;
35641fecca9SSchrodinger ZHU Yifan     data->writer_flag = true;
35741fecca9SSchrodinger ZHU Yifan     for (int i = 0; i < 10; ++i)
35841fecca9SSchrodinger ZHU Yifan       LIBC_NAMESPACE::sleep_briefly();
35941fecca9SSchrodinger ZHU Yifan     ASSERT_EQ(data->reader_count, 0);
36041fecca9SSchrodinger ZHU Yifan     data->writer_flag = false;
36141fecca9SSchrodinger ZHU Yifan     data->total_writer_count.fetch_add(1);
36241fecca9SSchrodinger ZHU Yifan   };
36341fecca9SSchrodinger ZHU Yifan   auto get_ts = []() {
36441fecca9SSchrodinger ZHU Yifan     timespec ts{};
36541fecca9SSchrodinger ZHU Yifan     LIBC_NAMESPACE::clock_gettime(CLOCK_REALTIME, &ts);
36641fecca9SSchrodinger ZHU Yifan     ts.tv_nsec += 5'000;
36741fecca9SSchrodinger ZHU Yifan     if (ts.tv_nsec >= 1'000'000'000) {
36841fecca9SSchrodinger ZHU Yifan       ts.tv_nsec -= 1'000'000'000;
36941fecca9SSchrodinger ZHU Yifan       ts.tv_sec += 1;
37041fecca9SSchrodinger ZHU Yifan     }
37141fecca9SSchrodinger ZHU Yifan     return ts;
37241fecca9SSchrodinger ZHU Yifan   };
37341fecca9SSchrodinger ZHU Yifan   switch (op) {
37441fecca9SSchrodinger ZHU Yifan   case Operation::READ: {
37541fecca9SSchrodinger ZHU Yifan     LIBC_NAMESPACE::pthread_rwlock_rdlock(&data->lock);
37641fecca9SSchrodinger ZHU Yifan     read_ops();
37741fecca9SSchrodinger ZHU Yifan     LIBC_NAMESPACE::pthread_rwlock_unlock(&data->lock);
37841fecca9SSchrodinger ZHU Yifan     break;
37941fecca9SSchrodinger ZHU Yifan   }
38041fecca9SSchrodinger ZHU Yifan   case Operation::WRITE: {
38141fecca9SSchrodinger ZHU Yifan     LIBC_NAMESPACE::pthread_rwlock_wrlock(&data->lock);
38241fecca9SSchrodinger ZHU Yifan     write_ops();
38341fecca9SSchrodinger ZHU Yifan     LIBC_NAMESPACE::pthread_rwlock_unlock(&data->lock);
38441fecca9SSchrodinger ZHU Yifan     break;
38541fecca9SSchrodinger ZHU Yifan   }
38641fecca9SSchrodinger ZHU Yifan   case Operation::TIMED_READ: {
38741fecca9SSchrodinger ZHU Yifan     timespec ts = get_ts();
38841fecca9SSchrodinger ZHU Yifan     if (LIBC_NAMESPACE::pthread_rwlock_timedrdlock(&data->lock, &ts) == 0) {
38941fecca9SSchrodinger ZHU Yifan       read_ops();
39041fecca9SSchrodinger ZHU Yifan       LIBC_NAMESPACE::pthread_rwlock_unlock(&data->lock);
39141fecca9SSchrodinger ZHU Yifan     }
39241fecca9SSchrodinger ZHU Yifan     break;
39341fecca9SSchrodinger ZHU Yifan   }
39441fecca9SSchrodinger ZHU Yifan   case Operation::TIMED_WRITE: {
39541fecca9SSchrodinger ZHU Yifan     timespec ts = get_ts();
39641fecca9SSchrodinger ZHU Yifan     if (LIBC_NAMESPACE::pthread_rwlock_timedwrlock(&data->lock, &ts) == 0) {
39741fecca9SSchrodinger ZHU Yifan       write_ops();
39841fecca9SSchrodinger ZHU Yifan       LIBC_NAMESPACE::pthread_rwlock_unlock(&data->lock);
39941fecca9SSchrodinger ZHU Yifan     }
40041fecca9SSchrodinger ZHU Yifan     break;
40141fecca9SSchrodinger ZHU Yifan   }
40244df89ccSEric977   case Operation::CLOCK_READ: {
40344df89ccSEric977     timespec ts = get_ts();
40444df89ccSEric977     if (LIBC_NAMESPACE::pthread_rwlock_clockrdlock(&data->lock, CLOCK_MONOTONIC,
40544df89ccSEric977                                                    &ts) == 0) {
40644df89ccSEric977       read_ops();
40744df89ccSEric977       LIBC_NAMESPACE::pthread_rwlock_unlock(&data->lock);
40844df89ccSEric977     }
40944df89ccSEric977     break;
41044df89ccSEric977   }
41144df89ccSEric977   case Operation::CLOCK_WRITE: {
41244df89ccSEric977     timespec ts = get_ts();
41344df89ccSEric977     if (LIBC_NAMESPACE::pthread_rwlock_clockwrlock(&data->lock, CLOCK_MONOTONIC,
41444df89ccSEric977                                                    &ts) == 0) {
41544df89ccSEric977       write_ops();
41644df89ccSEric977       LIBC_NAMESPACE::pthread_rwlock_unlock(&data->lock);
41744df89ccSEric977     }
41844df89ccSEric977     break;
41944df89ccSEric977   }
42041fecca9SSchrodinger ZHU Yifan   case Operation::TRY_READ: {
42141fecca9SSchrodinger ZHU Yifan     if (LIBC_NAMESPACE::pthread_rwlock_tryrdlock(&data->lock) == 0) {
42241fecca9SSchrodinger ZHU Yifan       read_ops();
42341fecca9SSchrodinger ZHU Yifan       LIBC_NAMESPACE::pthread_rwlock_unlock(&data->lock);
42441fecca9SSchrodinger ZHU Yifan     }
42541fecca9SSchrodinger ZHU Yifan     break;
42641fecca9SSchrodinger ZHU Yifan   }
42741fecca9SSchrodinger ZHU Yifan   case Operation::TRY_WRITE: {
42841fecca9SSchrodinger ZHU Yifan     if (LIBC_NAMESPACE::pthread_rwlock_trywrlock(&data->lock) == 0) {
42941fecca9SSchrodinger ZHU Yifan       write_ops();
43041fecca9SSchrodinger ZHU Yifan       LIBC_NAMESPACE::pthread_rwlock_unlock(&data->lock);
43141fecca9SSchrodinger ZHU Yifan     }
43241fecca9SSchrodinger ZHU Yifan     break;
43341fecca9SSchrodinger ZHU Yifan   }
43441fecca9SSchrodinger ZHU Yifan   case Operation::COUNT:
43541fecca9SSchrodinger ZHU Yifan     __builtin_trap();
43641fecca9SSchrodinger ZHU Yifan   }
43741fecca9SSchrodinger ZHU Yifan }
43841fecca9SSchrodinger ZHU Yifan 
43941fecca9SSchrodinger ZHU Yifan static void
44041fecca9SSchrodinger ZHU Yifan randomized_process_operation(SharedData &data,
44141fecca9SSchrodinger ZHU Yifan                              LIBC_NAMESPACE::cpp::Atomic<int> &finish_count,
44241fecca9SSchrodinger ZHU Yifan                              int expected_count) {
44341fecca9SSchrodinger ZHU Yifan   pthread_t threads[32];
44441fecca9SSchrodinger ZHU Yifan   for (auto &i : threads)
44541fecca9SSchrodinger ZHU Yifan     ASSERT_EQ(LIBC_NAMESPACE::pthread_create(
44641fecca9SSchrodinger ZHU Yifan                   &i, nullptr,
44741fecca9SSchrodinger ZHU Yifan                   [](void *arg) -> void * {
44841fecca9SSchrodinger ZHU Yifan                     ThreadGuard guard{};
44941fecca9SSchrodinger ZHU Yifan                     for (int i = 0; i < 64; ++i)
45041fecca9SSchrodinger ZHU Yifan                       randomized_thread_operation(
45141fecca9SSchrodinger ZHU Yifan                           reinterpret_cast<SharedData *>(arg), guard);
45241fecca9SSchrodinger ZHU Yifan                     return nullptr;
45341fecca9SSchrodinger ZHU Yifan                   },
45441fecca9SSchrodinger ZHU Yifan                   &data),
45541fecca9SSchrodinger ZHU Yifan               0);
45641fecca9SSchrodinger ZHU Yifan 
45741fecca9SSchrodinger ZHU Yifan   for (auto &i : threads)
45841fecca9SSchrodinger ZHU Yifan     ASSERT_EQ(LIBC_NAMESPACE::pthread_join(i, nullptr), 0);
45941fecca9SSchrodinger ZHU Yifan 
46041fecca9SSchrodinger ZHU Yifan   finish_count.fetch_add(1);
46141fecca9SSchrodinger ZHU Yifan   while (finish_count.load() != expected_count)
46241fecca9SSchrodinger ZHU Yifan     LIBC_NAMESPACE::sleep_briefly();
46341fecca9SSchrodinger ZHU Yifan 
46441fecca9SSchrodinger ZHU Yifan   ASSERT_EQ(data.total_writer_count.load(), data.data);
46541fecca9SSchrodinger ZHU Yifan   ASSERT_FALSE(data.writer_flag);
46641fecca9SSchrodinger ZHU Yifan   ASSERT_EQ(data.reader_count, 0);
46741fecca9SSchrodinger ZHU Yifan }
46841fecca9SSchrodinger ZHU Yifan 
46941fecca9SSchrodinger ZHU Yifan static void single_process_test(int preference) {
47041fecca9SSchrodinger ZHU Yifan   SharedData data{};
47141fecca9SSchrodinger ZHU Yifan   data.data = 0;
47241fecca9SSchrodinger ZHU Yifan   data.reader_count = 0;
47341fecca9SSchrodinger ZHU Yifan   data.writer_flag = false;
47441fecca9SSchrodinger ZHU Yifan   data.total_writer_count.store(0);
47541fecca9SSchrodinger ZHU Yifan   pthread_rwlockattr_t attr{};
47641fecca9SSchrodinger ZHU Yifan   ASSERT_EQ(LIBC_NAMESPACE::pthread_rwlockattr_init(&attr), 0);
47741fecca9SSchrodinger ZHU Yifan   ASSERT_EQ(LIBC_NAMESPACE::pthread_rwlockattr_setkind_np(&attr, preference),
47841fecca9SSchrodinger ZHU Yifan             0);
47941fecca9SSchrodinger ZHU Yifan   ASSERT_EQ(LIBC_NAMESPACE::pthread_rwlock_init(&data.lock, nullptr), 0);
48041fecca9SSchrodinger ZHU Yifan   LIBC_NAMESPACE::cpp::Atomic<int> finish_count{0};
48141fecca9SSchrodinger ZHU Yifan   randomized_process_operation(data, finish_count, 1);
48241fecca9SSchrodinger ZHU Yifan   ASSERT_EQ(LIBC_NAMESPACE::pthread_rwlock_destroy(&data.lock), 0);
48341fecca9SSchrodinger ZHU Yifan }
48441fecca9SSchrodinger ZHU Yifan 
48541fecca9SSchrodinger ZHU Yifan static void multiple_process_test(int preference) {
48641fecca9SSchrodinger ZHU Yifan   struct PShared {
48741fecca9SSchrodinger ZHU Yifan     SharedData data;
48841fecca9SSchrodinger ZHU Yifan     LIBC_NAMESPACE::cpp::Atomic<int> finish_count;
48941fecca9SSchrodinger ZHU Yifan   };
49041fecca9SSchrodinger ZHU Yifan   PShared *shared_data = reinterpret_cast<PShared *>(
49141fecca9SSchrodinger ZHU Yifan       LIBC_NAMESPACE::mmap(nullptr, sizeof(PShared), PROT_READ | PROT_WRITE,
49241fecca9SSchrodinger ZHU Yifan                            MAP_SHARED | MAP_ANONYMOUS, -1, 0));
49341fecca9SSchrodinger ZHU Yifan   shared_data->data.data = 0;
49441fecca9SSchrodinger ZHU Yifan   shared_data->data.reader_count = 0;
49541fecca9SSchrodinger ZHU Yifan   shared_data->data.writer_flag = false;
49641fecca9SSchrodinger ZHU Yifan   shared_data->data.total_writer_count.store(0);
49741fecca9SSchrodinger ZHU Yifan   shared_data->finish_count.store(0);
49841fecca9SSchrodinger ZHU Yifan   pthread_rwlockattr_t attr{};
49941fecca9SSchrodinger ZHU Yifan   ASSERT_EQ(LIBC_NAMESPACE::pthread_rwlockattr_init(&attr), 0);
50041fecca9SSchrodinger ZHU Yifan   ASSERT_EQ(LIBC_NAMESPACE::pthread_rwlockattr_setkind_np(&attr, preference),
50141fecca9SSchrodinger ZHU Yifan             0);
50241fecca9SSchrodinger ZHU Yifan   ASSERT_EQ(LIBC_NAMESPACE::pthread_rwlockattr_setpshared(
50341fecca9SSchrodinger ZHU Yifan                 &attr, PTHREAD_PROCESS_SHARED),
50441fecca9SSchrodinger ZHU Yifan             0);
50541fecca9SSchrodinger ZHU Yifan   ASSERT_EQ(LIBC_NAMESPACE::pthread_rwlock_init(&shared_data->data.lock, &attr),
50641fecca9SSchrodinger ZHU Yifan             0);
50741fecca9SSchrodinger ZHU Yifan   int pid = LIBC_NAMESPACE::fork();
50841fecca9SSchrodinger ZHU Yifan   randomized_process_operation(shared_data->data, shared_data->finish_count, 2);
50941fecca9SSchrodinger ZHU Yifan   if (pid == 0)
51041fecca9SSchrodinger ZHU Yifan     LIBC_NAMESPACE::exit(0);
51141fecca9SSchrodinger ZHU Yifan   else {
51241fecca9SSchrodinger ZHU Yifan     int status;
51341fecca9SSchrodinger ZHU Yifan     LIBC_NAMESPACE::waitpid(pid, &status, 0);
51441fecca9SSchrodinger ZHU Yifan     ASSERT_EQ(status, 0);
51541fecca9SSchrodinger ZHU Yifan   }
51641fecca9SSchrodinger ZHU Yifan   ASSERT_EQ(LIBC_NAMESPACE::pthread_rwlock_destroy(&shared_data->data.lock), 0);
51741fecca9SSchrodinger ZHU Yifan   LIBC_NAMESPACE::munmap(shared_data, sizeof(PShared));
51841fecca9SSchrodinger ZHU Yifan }
51941fecca9SSchrodinger ZHU Yifan 
52041fecca9SSchrodinger ZHU Yifan TEST_MAIN() {
52141fecca9SSchrodinger ZHU Yifan   io_mutex = new (LIBC_NAMESPACE::mmap(
52241fecca9SSchrodinger ZHU Yifan       nullptr, sizeof(LIBC_NAMESPACE::RawMutex), PROT_READ | PROT_WRITE,
52341fecca9SSchrodinger ZHU Yifan       MAP_ANONYMOUS | MAP_SHARED, -1, 0)) LIBC_NAMESPACE::RawMutex();
52441fecca9SSchrodinger ZHU Yifan   smoke_test();
52541fecca9SSchrodinger ZHU Yifan   deadlock_detection_test();
52641fecca9SSchrodinger ZHU Yifan   try_lock_test();
52741fecca9SSchrodinger ZHU Yifan   destroy_before_unlock_test();
52841fecca9SSchrodinger ZHU Yifan   nullptr_test();
52941fecca9SSchrodinger ZHU Yifan   high_reader_count_test();
53041fecca9SSchrodinger ZHU Yifan   unusual_timespec_test();
53141fecca9SSchrodinger ZHU Yifan   timedlock_with_deadlock_test();
53241fecca9SSchrodinger ZHU Yifan   attributed_initialization_test();
53341fecca9SSchrodinger ZHU Yifan   single_process_test(PTHREAD_RWLOCK_PREFER_READER_NP);
53441fecca9SSchrodinger ZHU Yifan   single_process_test(PTHREAD_RWLOCK_PREFER_WRITER_NONRECURSIVE_NP);
53541fecca9SSchrodinger ZHU Yifan   multiple_process_test(PTHREAD_RWLOCK_PREFER_READER_NP);
53641fecca9SSchrodinger ZHU Yifan   multiple_process_test(PTHREAD_RWLOCK_PREFER_WRITER_NONRECURSIVE_NP);
53741fecca9SSchrodinger ZHU Yifan   io_mutex->~RawMutex();
53841fecca9SSchrodinger ZHU Yifan   LIBC_NAMESPACE::munmap(io_mutex, sizeof(LIBC_NAMESPACE::RawMutex));
53941fecca9SSchrodinger ZHU Yifan   return 0;
54041fecca9SSchrodinger ZHU Yifan }
541