1//===-- tsan_posix.cpp ----------------------------------------------------===//
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// This file is a part of ThreadSanitizer (TSan), a race detector.
10//
11//===----------------------------------------------------------------------===//
12#include "tsan_interface.h"
13#include "tsan_posix_util.h"
14#include "tsan_test_util.h"
15#include "gtest/gtest.h"
16#include <pthread.h>
17
18struct thread_key {
19 pthread_key_t key;
20 pthread_mutex_t *mtx;
21 int val;
22 int *cnt;
23 thread_key(pthread_key_t key, pthread_mutex_t *mtx, int val, int *cnt)
24 : key(key)
25 , mtx(mtx)
26 , val(val)
27 , cnt(cnt) {
28 }
29};
30
31static void thread_secific_dtor(void *v) {
32 thread_key *k = (thread_key *)v;
33 EXPECT_EQ(__interceptor_pthread_mutex_lock(mutex: k->mtx), 0);
34 (*k->cnt)++;
35 __tsan_write4(addr: &k->cnt);
36 EXPECT_EQ(__interceptor_pthread_mutex_unlock(mutex: k->mtx), 0);
37 if (k->val == 42) {
38 // Okay.
39 } else if (k->val == 43 || k->val == 44) {
40 k->val--;
41 EXPECT_EQ(pthread_setspecific(key: k->key, pointer: k), 0);
42 } else {
43 ASSERT_TRUE(false);
44 }
45}
46
47static void *dtors_thread(void *p) {
48 thread_key *k = (thread_key *)p;
49 EXPECT_EQ(pthread_setspecific(key: k->key, pointer: k), 0);
50 return 0;
51}
52
53TEST(Posix, ThreadSpecificDtors) {
54 int cnt = 0;
55 pthread_key_t key;
56 EXPECT_EQ(pthread_key_create(&key, thread_secific_dtor), 0);
57 pthread_mutex_t mtx;
58 EXPECT_EQ(__interceptor_pthread_mutex_init(&mtx, 0), 0);
59 pthread_t th[3];
60 thread_key k1 = thread_key(key, &mtx, 42, &cnt);
61 thread_key k2 = thread_key(key, &mtx, 43, &cnt);
62 thread_key k3 = thread_key(key, &mtx, 44, &cnt);
63 EXPECT_EQ(__interceptor_pthread_create(&th[0], 0, dtors_thread, &k1), 0);
64 EXPECT_EQ(__interceptor_pthread_create(&th[1], 0, dtors_thread, &k2), 0);
65 EXPECT_EQ(__interceptor_pthread_join(th[0], 0), 0);
66 EXPECT_EQ(__interceptor_pthread_create(&th[2], 0, dtors_thread, &k3), 0);
67 EXPECT_EQ(__interceptor_pthread_join(th[1], 0), 0);
68 EXPECT_EQ(__interceptor_pthread_join(th[2], 0), 0);
69 EXPECT_EQ(pthread_key_delete(key), 0);
70 EXPECT_EQ(6, cnt);
71}
72
73#if !defined(__aarch64__) && !defined(__APPLE__)
74static __thread int local_var;
75
76static void *local_thread(void *p) {
77 __tsan_write1(addr: &local_var);
78 __tsan_write1(addr: &p);
79 if (p == 0)
80 return 0;
81 const int kThreads = 4;
82 pthread_t th[kThreads];
83 for (int i = 0; i < kThreads; i++)
84 EXPECT_EQ(__interceptor_pthread_create(thread: &th[i], attr: 0, start_routine: local_thread,
85 arg: (void *)((long)p - 1)),
86 0);
87 for (int i = 0; i < kThreads; i++)
88 EXPECT_EQ(__interceptor_pthread_join(thread: th[i], value_ptr: 0), 0);
89 return 0;
90}
91#endif
92
93TEST(Posix, ThreadLocalAccesses) {
94// The test is failing with high thread count for aarch64.
95// FIXME: track down the issue and re-enable the test.
96// On Darwin, we're running unit tests without interceptors and __thread is
97// using malloc and free, which causes false data race reports. On rare
98// occasions on powerpc64le this test also fails.
99#if !defined(__aarch64__) && !defined(__APPLE__) && !defined(powerpc64le)
100 local_thread(p: (void*)2);
101#endif
102}
103
104struct CondContext {
105 pthread_mutex_t m;
106 pthread_cond_t c;
107 int data;
108};
109
110static void *cond_thread(void *p) {
111 CondContext &ctx = *static_cast<CondContext*>(p);
112
113 EXPECT_EQ(__interceptor_pthread_mutex_lock(mutex: &ctx.m), 0);
114 EXPECT_EQ(ctx.data, 0);
115 ctx.data = 1;
116 EXPECT_EQ(__interceptor_pthread_cond_signal(cond: &ctx.c), 0);
117 EXPECT_EQ(__interceptor_pthread_mutex_unlock(mutex: &ctx.m), 0);
118
119 EXPECT_EQ(__interceptor_pthread_mutex_lock(mutex: &ctx.m), 0);
120 while (ctx.data != 2)
121 EXPECT_EQ(__interceptor_pthread_cond_wait(cond: &ctx.c, mutex: &ctx.m), 0);
122 EXPECT_EQ(__interceptor_pthread_mutex_unlock(mutex: &ctx.m), 0);
123
124 EXPECT_EQ(__interceptor_pthread_mutex_lock(mutex: &ctx.m), 0);
125 ctx.data = 3;
126 EXPECT_EQ(pthread_cond_broadcast(cond: &ctx.c), 0);
127 EXPECT_EQ(__interceptor_pthread_mutex_unlock(mutex: &ctx.m), 0);
128
129 return 0;
130}
131
132TEST(Posix, CondBasic) {
133 CondContext ctx;
134 EXPECT_EQ(__interceptor_pthread_mutex_init(mutex: &ctx.m, attr: 0), 0);
135 EXPECT_EQ(__interceptor_pthread_cond_init(cond: &ctx.c, attr: 0), 0);
136 ctx.data = 0;
137 pthread_t th;
138 EXPECT_EQ(__interceptor_pthread_create(thread: &th, attr: 0, start_routine: cond_thread, arg: &ctx), 0);
139
140 EXPECT_EQ(__interceptor_pthread_mutex_lock(mutex: &ctx.m), 0);
141 while (ctx.data != 1)
142 EXPECT_EQ(__interceptor_pthread_cond_wait(cond: &ctx.c, mutex: &ctx.m), 0);
143 ctx.data = 2;
144 EXPECT_EQ(__interceptor_pthread_mutex_unlock(mutex: &ctx.m), 0);
145 EXPECT_EQ(pthread_cond_broadcast(cond: &ctx.c), 0);
146
147 EXPECT_EQ(__interceptor_pthread_mutex_lock(mutex: &ctx.m), 0);
148 while (ctx.data != 3)
149 EXPECT_EQ(__interceptor_pthread_cond_wait(cond: &ctx.c, mutex: &ctx.m), 0);
150 EXPECT_EQ(__interceptor_pthread_mutex_unlock(mutex: &ctx.m), 0);
151
152 EXPECT_EQ(__interceptor_pthread_join(thread: th, value_ptr: 0), 0);
153 EXPECT_EQ(__interceptor_pthread_cond_destroy(cond: &ctx.c), 0);
154 EXPECT_EQ(__interceptor_pthread_mutex_destroy(mutex: &ctx.m), 0);
155}
156

source code of compiler-rt/lib/tsan/tests/rtl/tsan_posix.cpp