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