xref: /aosp_15_r20/external/llvm-libc/test/integration/src/pthread/pthread_tss_test.cpp (revision 71db0c75aadcf003ffe3238005f61d7618a3fead)
1 //===-- Tests for TSS API like pthread_setspecific etc. -------------------===//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
8 
9 #include "src/pthread/pthread_create.h"
10 #include "src/pthread/pthread_exit.h"
11 #include "src/pthread/pthread_getspecific.h"
12 #include "src/pthread/pthread_join.h"
13 #include "src/pthread/pthread_key_create.h"
14 #include "src/pthread/pthread_key_delete.h"
15 #include "src/pthread/pthread_setspecific.h"
16 #include "test/IntegrationTest/test.h"
17 
18 #include <pthread.h>
19 
20 static constexpr int THREAD_DATA_INITVAL = 0x1234;
21 static constexpr int THREAD_DATA_FINIVAL = 0x4321;
22 static constexpr int THREAD_RUN_VAL = 0x600D;
23 
24 static int child_thread_data = THREAD_DATA_INITVAL;
25 static int main_thread_data = THREAD_DATA_INITVAL;
26 
27 static pthread_key_t key;
dtor(void * data)28 static void dtor(void *data) {
29   auto *v = reinterpret_cast<int *>(data);
30   *v = THREAD_DATA_FINIVAL;
31 }
32 
33 // Used to test that we don't call the destructor when the mapped value in NULL.
dtor_failure(void *)34 static void dtor_failure(void *) { ASSERT_TRUE(false); }
35 
func(void * obj)36 static void *func(void *obj) {
37   ASSERT_EQ(LIBC_NAMESPACE::pthread_setspecific(key, &child_thread_data), 0);
38   int *d = reinterpret_cast<int *>(LIBC_NAMESPACE::pthread_getspecific(key));
39   ASSERT_TRUE(d != nullptr);
40   ASSERT_EQ(&child_thread_data, d);
41   ASSERT_EQ(*d, THREAD_DATA_INITVAL);
42   *reinterpret_cast<int *>(obj) = THREAD_RUN_VAL;
43   return nullptr;
44 }
45 
func_null_val(void *)46 static void *func_null_val(void *) {
47   // null value, we should not call dtor
48   ASSERT_EQ(LIBC_NAMESPACE::pthread_setspecific(key, nullptr), 0);
49   ASSERT_EQ(LIBC_NAMESPACE::pthread_getspecific(key), nullptr);
50   return nullptr;
51 }
52 
standard_usage_test()53 static void standard_usage_test() {
54   ASSERT_EQ(LIBC_NAMESPACE::pthread_key_create(&key, &dtor), 0);
55   ASSERT_EQ(LIBC_NAMESPACE::pthread_setspecific(key, &main_thread_data), 0);
56   int *d = reinterpret_cast<int *>(LIBC_NAMESPACE::pthread_getspecific(key));
57   ASSERT_TRUE(d != nullptr);
58   ASSERT_EQ(&main_thread_data, d);
59   ASSERT_EQ(*d, THREAD_DATA_INITVAL);
60 
61   pthread_t th;
62   int arg = 0xBAD;
63   ASSERT_EQ(LIBC_NAMESPACE::pthread_create(&th, nullptr, &func, &arg), 0);
64   void *retval = &child_thread_data; // Init to some non-nullptr val.
65   ASSERT_EQ(LIBC_NAMESPACE::pthread_join(th, &retval), 0);
66   ASSERT_EQ(retval, nullptr);
67   ASSERT_EQ(arg, THREAD_RUN_VAL);
68   ASSERT_EQ(child_thread_data, THREAD_DATA_FINIVAL);
69   ASSERT_EQ(LIBC_NAMESPACE::pthread_key_delete(key), 0);
70 }
71 
null_value_test()72 static void null_value_test() {
73   pthread_t th;
74   ASSERT_EQ(LIBC_NAMESPACE::pthread_key_create(&key, &dtor_failure), 0);
75   ASSERT_EQ(
76       LIBC_NAMESPACE::pthread_create(&th, nullptr, &func_null_val, nullptr), 0);
77   ASSERT_EQ(LIBC_NAMESPACE::pthread_join(th, nullptr), 0);
78   ASSERT_EQ(LIBC_NAMESPACE::pthread_key_delete(key), 0);
79 }
80 
TEST_MAIN()81 TEST_MAIN() {
82   standard_usage_test();
83   null_value_test();
84   return 0;
85 }
86