xref: /aosp_15_r20/external/llvm-libc/test/integration/src/threads/cnd_test.cpp (revision 71db0c75aadcf003ffe3238005f61d7618a3fead)
1 //===-- Tests for standard condition variables ----------------------------===//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
8 
9 #include "src/__support/CPP/atomic.h"
10 #include "src/threads/cnd_broadcast.h"
11 #include "src/threads/cnd_destroy.h"
12 #include "src/threads/cnd_init.h"
13 #include "src/threads/cnd_signal.h"
14 #include "src/threads/cnd_wait.h"
15 #include "src/threads/mtx_destroy.h"
16 #include "src/threads/mtx_init.h"
17 #include "src/threads/mtx_lock.h"
18 #include "src/threads/mtx_unlock.h"
19 #include "src/threads/thrd_create.h"
20 #include "src/threads/thrd_join.h"
21 
22 #include "test/IntegrationTest/test.h"
23 
24 #include <threads.h>
25 
26 namespace wait_notify_broadcast_test {
27 
28 // The test in this namespace tests all condition variable operations. The
29 // main thread spawns THRD_COUNT threads, each of which wait on a condition
30 // variable |broadcast_cnd|. After spawing the threads, it waits on another
31 // condition variable |threads_ready_cnd| which will be signalled by the last
32 // thread before it starts waiting on |broadcast_cnd|. On signalled by the
33 // last thread, the main thread then wakes up to broadcast to all waiting
34 // threads to wake up. Each of the THRD_COUNT child threads increment
35 // |broadcast_count| by 1 before they start waiting on |broadcast_cnd|, and
36 // decrement it by 1 after getting signalled on |broadcast_cnd|.
37 
38 constexpr unsigned int THRD_COUNT = 1000;
39 
40 static LIBC_NAMESPACE::cpp::Atomic<unsigned int> broadcast_count(0);
41 static cnd_t broadcast_cnd, threads_ready_cnd;
42 static mtx_t broadcast_mtx, threads_ready_mtx;
43 
broadcast_thread_func(void *)44 int broadcast_thread_func(void *) {
45   LIBC_NAMESPACE::mtx_lock(&broadcast_mtx);
46   unsigned oldval = broadcast_count.fetch_add(1);
47   if (oldval == THRD_COUNT - 1) {
48     LIBC_NAMESPACE::mtx_lock(&threads_ready_mtx);
49     LIBC_NAMESPACE::cnd_signal(&threads_ready_cnd);
50     LIBC_NAMESPACE::mtx_unlock(&threads_ready_mtx);
51   }
52 
53   LIBC_NAMESPACE::cnd_wait(&broadcast_cnd, &broadcast_mtx);
54   LIBC_NAMESPACE::mtx_unlock(&broadcast_mtx);
55   broadcast_count.fetch_sub(1);
56   return 0;
57 }
58 
wait_notify_broadcast_test()59 void wait_notify_broadcast_test() {
60   LIBC_NAMESPACE::cnd_init(&broadcast_cnd);
61   LIBC_NAMESPACE::cnd_init(&threads_ready_cnd);
62   LIBC_NAMESPACE::mtx_init(&broadcast_mtx, mtx_plain);
63   LIBC_NAMESPACE::mtx_init(&threads_ready_mtx, mtx_plain);
64 
65   LIBC_NAMESPACE::mtx_lock(&threads_ready_mtx);
66   thrd_t threads[THRD_COUNT];
67   for (unsigned int i = 0; i < THRD_COUNT; ++i)
68     LIBC_NAMESPACE::thrd_create(&threads[i], broadcast_thread_func, nullptr);
69 
70   LIBC_NAMESPACE::cnd_wait(&threads_ready_cnd, &threads_ready_mtx);
71   LIBC_NAMESPACE::mtx_unlock(&threads_ready_mtx);
72 
73   LIBC_NAMESPACE::mtx_lock(&broadcast_mtx);
74   ASSERT_EQ(broadcast_count.val, THRD_COUNT);
75   LIBC_NAMESPACE::cnd_broadcast(&broadcast_cnd);
76   LIBC_NAMESPACE::mtx_unlock(&broadcast_mtx);
77 
78   for (unsigned int i = 0; i < THRD_COUNT; ++i) {
79     int retval = 0xBAD;
80     LIBC_NAMESPACE::thrd_join(threads[i], &retval);
81     ASSERT_EQ(retval, 0);
82   }
83 
84   ASSERT_EQ(broadcast_count.val, 0U);
85 
86   LIBC_NAMESPACE::cnd_destroy(&broadcast_cnd);
87   LIBC_NAMESPACE::cnd_destroy(&threads_ready_cnd);
88   LIBC_NAMESPACE::mtx_destroy(&broadcast_mtx);
89   LIBC_NAMESPACE::mtx_destroy(&threads_ready_mtx);
90 }
91 
92 } // namespace wait_notify_broadcast_test
93 
94 namespace single_waiter_test {
95 
96 // In this namespace we set up test with two threads, one the main thread
97 // and the other a waiter thread. They wait on each other using condition
98 // variables and mutexes before proceeding to completion.
99 
100 mtx_t waiter_mtx, main_thread_mtx;
101 cnd_t waiter_cnd, main_thread_cnd;
102 
waiter_thread_func(void * unused)103 int waiter_thread_func(void *unused) {
104   LIBC_NAMESPACE::mtx_lock(&waiter_mtx);
105 
106   LIBC_NAMESPACE::mtx_lock(&main_thread_mtx);
107   LIBC_NAMESPACE::cnd_signal(&main_thread_cnd);
108   LIBC_NAMESPACE::mtx_unlock(&main_thread_mtx);
109 
110   LIBC_NAMESPACE::cnd_wait(&waiter_cnd, &waiter_mtx);
111   LIBC_NAMESPACE::mtx_unlock(&waiter_mtx);
112 
113   return 0x600D;
114 }
115 
single_waiter_test()116 void single_waiter_test() {
117   ASSERT_EQ(LIBC_NAMESPACE::mtx_init(&waiter_mtx, mtx_plain),
118             int(thrd_success));
119   ASSERT_EQ(LIBC_NAMESPACE::mtx_init(&main_thread_mtx, mtx_plain),
120             int(thrd_success));
121   ASSERT_EQ(LIBC_NAMESPACE::cnd_init(&waiter_cnd), int(thrd_success));
122   ASSERT_EQ(LIBC_NAMESPACE::cnd_init(&main_thread_cnd), int(thrd_success));
123 
124   ASSERT_EQ(LIBC_NAMESPACE::mtx_lock(&main_thread_mtx), int(thrd_success));
125 
126   thrd_t waiter_thread;
127   LIBC_NAMESPACE::thrd_create(&waiter_thread, waiter_thread_func, nullptr);
128 
129   ASSERT_EQ(LIBC_NAMESPACE::cnd_wait(&main_thread_cnd, &main_thread_mtx),
130             int(thrd_success));
131   ASSERT_EQ(LIBC_NAMESPACE::mtx_unlock(&main_thread_mtx), int(thrd_success));
132 
133   ASSERT_EQ(LIBC_NAMESPACE::mtx_lock(&waiter_mtx), int(thrd_success));
134   ASSERT_EQ(LIBC_NAMESPACE::cnd_signal(&waiter_cnd), int(thrd_success));
135   ASSERT_EQ(LIBC_NAMESPACE::mtx_unlock(&waiter_mtx), int(thrd_success));
136 
137   int retval;
138   LIBC_NAMESPACE::thrd_join(waiter_thread, &retval);
139   ASSERT_EQ(retval, 0x600D);
140 
141   LIBC_NAMESPACE::mtx_destroy(&waiter_mtx);
142   LIBC_NAMESPACE::mtx_destroy(&main_thread_mtx);
143   LIBC_NAMESPACE::cnd_destroy(&waiter_cnd);
144   LIBC_NAMESPACE::cnd_destroy(&main_thread_cnd);
145 }
146 
147 } // namespace single_waiter_test
148 
TEST_MAIN()149 TEST_MAIN() {
150   wait_notify_broadcast_test::wait_notify_broadcast_test();
151   single_waiter_test::single_waiter_test();
152   return 0;
153 }
154