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