1 // Copyright 2016 The Fuchsia Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #include <assert.h>
6 #include <zircon/syscalls.h>
7 #include <unittest/unittest.h>
8 #include <pthread.h>
9 #include <stdatomic.h>
10 #include <stdio.h>
11 #include <unistd.h>
12 
13 static pthread_key_t tsd_key;
14 static pthread_key_t tsd_key_dtor;
15 static atomic_int dtor_count = ATOMIC_VAR_INIT(0);
16 
dtor(void * unused)17 void dtor(void* unused) {
18     atomic_fetch_add(&dtor_count, 1);
19 }
20 
test_tls(int thread_no)21 static void test_tls(int thread_no) {
22     int value1 = thread_no;
23     int value2 = thread_no + 10;
24     EXPECT_EQ(pthread_setspecific(tsd_key, &value1), 0,
25               "Error while setting tls value");
26     EXPECT_EQ(pthread_setspecific(tsd_key_dtor, &value2), 0,
27               "Error while setting tls value");
28     zx_nanosleep(zx_deadline_after(ZX_MSEC(100)));
29     int* v = pthread_getspecific(tsd_key);
30     EXPECT_EQ(*v, value1, "wrong TLS value for key");
31     v = pthread_getspecific(tsd_key_dtor);
32     EXPECT_EQ(*v, value2, "wrong TLS value for key_dtor");
33     unittest_printf("tls_test completed for thread: %d\n", thread_no);
34 }
35 
do_work(void * arg)36 static void* do_work(void* arg) {
37     unittest_printf("do_work for thread: %d\n", *(int*)arg);
38     test_tls(*(int*)arg);
39     return NULL;
40 }
41 
tls_test(void)42 bool tls_test(void) {
43     BEGIN_TEST;
44     ASSERT_EQ(pthread_key_create(&tsd_key, NULL), 0, "Error during key creation");
45     ASSERT_EQ(pthread_key_create(&tsd_key_dtor, dtor), 0, "Error during key creation");
46 
47     int expected_dtor_count = 0;
48 
49     // Run this 20 times for sanity check
50     for (int i = 1; i <= 20; i++) {
51         int main_thread = 1, thread_1 = i * 2, thread_2 = i * 2 + 1;
52 
53         pthread_t thread2, thread3;
54 
55         unittest_printf("creating thread: %d\n", thread_1);
56         pthread_create(&thread2, NULL, do_work, &thread_1);
57 
58         unittest_printf("creating thread: %d\n", thread_2);
59         pthread_create(&thread3, NULL, do_work, &thread_2);
60 
61         test_tls(main_thread);
62 
63         unittest_printf("joining thread: %d\n", thread_1);
64         pthread_join(thread2, NULL);
65 
66         unittest_printf("joining thread: %d\n", thread_2);
67         pthread_join(thread3, NULL);
68 
69         expected_dtor_count += 2;
70         ASSERT_EQ(atomic_load(&dtor_count), expected_dtor_count, "dtors not run");
71     }
72     END_TEST;
73 }
74 
75 BEGIN_TEST_CASE(tls_tests)
RUN_TEST(tls_test)76 RUN_TEST(tls_test)
77 END_TEST_CASE(tls_tests)
78 
79 #ifndef BUILD_COMBINED_TESTS
80 int main(int argc, char** argv) {
81     return unittest_run_all_tests(argc, argv) ? 0 : -1;
82 }
83 #endif
84