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
13static pthread_key_t tsd_key;
14static pthread_key_t tsd_key_dtor;
15static atomic_int dtor_count = ATOMIC_VAR_INIT(0);
16
17void dtor(void* unused) {
18    atomic_fetch_add(&dtor_count, 1);
19}
20
21static 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
36static 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
42bool 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
75BEGIN_TEST_CASE(tls_tests)
76RUN_TEST(tls_test)
77END_TEST_CASE(tls_tests)
78
79#ifndef BUILD_COMBINED_TESTS
80int main(int argc, char** argv) {
81    return unittest_run_all_tests(argc, argv) ? 0 : -1;
82}
83#endif
84