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