xref: /llvm-project/libc/test/integration/src/threads/call_once_test.cpp (revision b6bc9d72f65a5086f310f321e969d96e9a559e75)
1d5475af2SSiva Chandra Reddy //===-- Tests for call_once -----------------------------------------------===//
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/call_once.h"
11d5475af2SSiva Chandra Reddy #include "src/threads/mtx_destroy.h"
12d5475af2SSiva Chandra Reddy #include "src/threads/mtx_init.h"
13d5475af2SSiva Chandra Reddy #include "src/threads/mtx_lock.h"
14d5475af2SSiva Chandra Reddy #include "src/threads/mtx_unlock.h"
15d5475af2SSiva Chandra Reddy #include "src/threads/thrd_create.h"
16d5475af2SSiva Chandra Reddy #include "src/threads/thrd_join.h"
17d5475af2SSiva Chandra Reddy 
18af1315c2SSiva Chandra Reddy #include "test/IntegrationTest/test.h"
19d5475af2SSiva Chandra Reddy 
20d5475af2SSiva Chandra Reddy #include <threads.h>
21d5475af2SSiva Chandra Reddy 
22d5475af2SSiva Chandra Reddy static constexpr unsigned int NUM_THREADS = 5;
23*b6bc9d72SGuillaume Chatelet static LIBC_NAMESPACE::cpp::Atomic<unsigned int> thread_count;
24d5475af2SSiva Chandra Reddy 
25d5475af2SSiva Chandra Reddy static unsigned int call_count;
call_once_func()26d5475af2SSiva Chandra Reddy static void call_once_func() { ++call_count; }
27d5475af2SSiva Chandra Reddy 
func(void *)28d5475af2SSiva Chandra Reddy static int func(void *) {
29d5475af2SSiva Chandra Reddy   static once_flag flag = ONCE_FLAG_INIT;
30*b6bc9d72SGuillaume Chatelet   LIBC_NAMESPACE::call_once(&flag, call_once_func);
31d5475af2SSiva Chandra Reddy 
32d5475af2SSiva Chandra Reddy   thread_count.fetch_add(1);
33d5475af2SSiva Chandra Reddy 
34d5475af2SSiva Chandra Reddy   return 0;
35d5475af2SSiva Chandra Reddy }
36d5475af2SSiva Chandra Reddy 
call_from_5_threads()37d5475af2SSiva Chandra Reddy void call_from_5_threads() {
38d5475af2SSiva Chandra Reddy   // Ensure the call count and thread count are 0 to begin with.
39d5475af2SSiva Chandra Reddy   call_count = 0;
40d5475af2SSiva Chandra Reddy   thread_count = 0;
41d5475af2SSiva Chandra Reddy 
42d5475af2SSiva Chandra Reddy   thrd_t threads[NUM_THREADS];
43d5475af2SSiva Chandra Reddy   for (unsigned int i = 0; i < NUM_THREADS; ++i) {
44*b6bc9d72SGuillaume Chatelet     ASSERT_EQ(LIBC_NAMESPACE::thrd_create(threads + i, func, nullptr),
45d5475af2SSiva Chandra Reddy               static_cast<int>(thrd_success));
46d5475af2SSiva Chandra Reddy   }
47d5475af2SSiva Chandra Reddy 
48d5475af2SSiva Chandra Reddy   for (unsigned int i = 0; i < NUM_THREADS; ++i) {
49d5475af2SSiva Chandra Reddy     int retval;
50*b6bc9d72SGuillaume Chatelet     ASSERT_EQ(LIBC_NAMESPACE::thrd_join(threads[i], &retval),
51d5475af2SSiva Chandra Reddy               static_cast<int>(thrd_success));
52d5475af2SSiva Chandra Reddy     ASSERT_EQ(retval, 0);
53d5475af2SSiva Chandra Reddy   }
54d5475af2SSiva Chandra Reddy 
55d5475af2SSiva Chandra Reddy   EXPECT_EQ(thread_count.val, 5U);
56d5475af2SSiva Chandra Reddy   EXPECT_EQ(call_count, 1U);
57d5475af2SSiva Chandra Reddy }
58d5475af2SSiva Chandra Reddy 
59d5475af2SSiva Chandra Reddy static mtx_t once_func_blocker;
blocking_once_func()60d5475af2SSiva Chandra Reddy static void blocking_once_func() {
61*b6bc9d72SGuillaume Chatelet   LIBC_NAMESPACE::mtx_lock(&once_func_blocker);
62*b6bc9d72SGuillaume Chatelet   LIBC_NAMESPACE::mtx_unlock(&once_func_blocker);
63d5475af2SSiva Chandra Reddy }
64d5475af2SSiva Chandra Reddy 
65*b6bc9d72SGuillaume Chatelet static LIBC_NAMESPACE::cpp::Atomic<unsigned int> start_count;
66*b6bc9d72SGuillaume Chatelet static LIBC_NAMESPACE::cpp::Atomic<unsigned int> done_count;
once_func_caller(void *)67d5475af2SSiva Chandra Reddy static int once_func_caller(void *) {
68d5475af2SSiva Chandra Reddy   static once_flag flag;
69d5475af2SSiva Chandra Reddy   start_count.fetch_add(1);
70*b6bc9d72SGuillaume Chatelet   LIBC_NAMESPACE::call_once(&flag, blocking_once_func);
71d5475af2SSiva Chandra Reddy   done_count.fetch_add(1);
72d5475af2SSiva Chandra Reddy   return 0;
73d5475af2SSiva Chandra Reddy }
74d5475af2SSiva Chandra Reddy 
75d5475af2SSiva Chandra Reddy // Test the synchronization aspect of the call_once function.
76d5475af2SSiva Chandra Reddy // This is not a fool proof test, but something which might be
77d5475af2SSiva Chandra Reddy // useful when we add a flakiness detection scheme to UnitTest.
test_synchronization()78d5475af2SSiva Chandra Reddy void test_synchronization() {
79d5475af2SSiva Chandra Reddy   start_count = 0;
80d5475af2SSiva Chandra Reddy   done_count = 0;
81d5475af2SSiva Chandra Reddy 
82*b6bc9d72SGuillaume Chatelet   ASSERT_EQ(LIBC_NAMESPACE::mtx_init(&once_func_blocker, mtx_plain),
83d5475af2SSiva Chandra Reddy             static_cast<int>(thrd_success));
84d5475af2SSiva Chandra Reddy   // Lock the blocking mutex so that the once func blocks.
85*b6bc9d72SGuillaume Chatelet   ASSERT_EQ(LIBC_NAMESPACE::mtx_lock(&once_func_blocker),
86d5475af2SSiva Chandra Reddy             static_cast<int>(thrd_success));
87d5475af2SSiva Chandra Reddy 
88d5475af2SSiva Chandra Reddy   thrd_t t1, t2;
89*b6bc9d72SGuillaume Chatelet   ASSERT_EQ(LIBC_NAMESPACE::thrd_create(&t1, once_func_caller, nullptr),
90d5475af2SSiva Chandra Reddy             static_cast<int>(thrd_success));
91*b6bc9d72SGuillaume Chatelet   ASSERT_EQ(LIBC_NAMESPACE::thrd_create(&t2, once_func_caller, nullptr),
92d5475af2SSiva Chandra Reddy             static_cast<int>(thrd_success));
93d5475af2SSiva Chandra Reddy 
94d5475af2SSiva Chandra Reddy   while (start_count.load() != 2)
95d5475af2SSiva Chandra Reddy     ; // Spin until both threads start.
96d5475af2SSiva Chandra Reddy 
97d5475af2SSiva Chandra Reddy   // Since the once func is blocked, the threads should not be done yet.
98d5475af2SSiva Chandra Reddy   EXPECT_EQ(done_count.val, 0U);
99d5475af2SSiva Chandra Reddy 
100d5475af2SSiva Chandra Reddy   // Unlock the blocking mutex so that the once func blocks.
101*b6bc9d72SGuillaume Chatelet   ASSERT_EQ(LIBC_NAMESPACE::mtx_unlock(&once_func_blocker),
102d5475af2SSiva Chandra Reddy             static_cast<int>(thrd_success));
103d5475af2SSiva Chandra Reddy 
104d5475af2SSiva Chandra Reddy   int retval;
105*b6bc9d72SGuillaume Chatelet   ASSERT_EQ(LIBC_NAMESPACE::thrd_join(t1, &retval),
106d5475af2SSiva Chandra Reddy             static_cast<int>(thrd_success));
107d5475af2SSiva Chandra Reddy   ASSERT_EQ(retval, 0);
108*b6bc9d72SGuillaume Chatelet   ASSERT_EQ(LIBC_NAMESPACE::thrd_join(t2, &retval),
109d5475af2SSiva Chandra Reddy             static_cast<int>(thrd_success));
110d5475af2SSiva Chandra Reddy   ASSERT_EQ(retval, 0);
111d5475af2SSiva Chandra Reddy 
112d5475af2SSiva Chandra Reddy   ASSERT_EQ(done_count.val, 2U);
113d5475af2SSiva Chandra Reddy 
114*b6bc9d72SGuillaume Chatelet   LIBC_NAMESPACE::mtx_destroy(&once_func_blocker);
115d5475af2SSiva Chandra Reddy }
116d5475af2SSiva Chandra Reddy 
TEST_MAIN()11712df3080SSiva Chandra Reddy TEST_MAIN() {
118d5475af2SSiva Chandra Reddy   call_from_5_threads();
119d5475af2SSiva Chandra Reddy   test_synchronization();
120d5475af2SSiva Chandra Reddy   return 0;
121d5475af2SSiva Chandra Reddy }
122