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
20static constexpr int THREAD_DATA_INITVAL = 0x1234;
21static constexpr int THREAD_DATA_FINIVAL = 0x4321;
22static constexpr int THREAD_RUN_VAL = 0x600D;
23
24static int child_thread_data = THREAD_DATA_INITVAL;
25static int main_thread_data = THREAD_DATA_INITVAL;
26
27static pthread_key_t key;
28static 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.
34static void dtor_failure(void *) { ASSERT_TRUE(false); }
35
36static 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
46static 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
53static 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
72static 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
81TEST_MAIN() {
82 standard_usage_test();
83 null_value_test();
84 return 0;
85}
86

source code of libc/test/integration/src/pthread/pthread_tss_test.cpp