1//===-- sanitizer_thread_registry_test.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 shared sanitizer runtime.
10//
11//===----------------------------------------------------------------------===//
12#include "sanitizer_common/sanitizer_thread_arg_retval.h"
13
14#include "gtest/gtest.h"
15#include "sanitizer_mutex.h"
16
17namespace __sanitizer {
18
19static int t;
20static void* arg = &t;
21static void* (*routine)(void*) = [](void*) { return arg; };
22static void* retval = (&t) + 1;
23
24TEST(ThreadArgRetvalTest, CreateFail) {
25 ThreadArgRetval td;
26 td.Create(detached: false, args: {.routine: routine, .arg_retval: arg}, fn: []() { return 0; });
27 EXPECT_EQ(0u, td.size());
28}
29
30TEST(ThreadArgRetvalTest, CreateRunJoin) {
31 ThreadArgRetval td;
32 td.Create(detached: false, args: {.routine: routine, .arg_retval: arg}, fn: []() { return 1; });
33 EXPECT_EQ(1u, td.size());
34
35 EXPECT_EQ(arg, td.GetArgs(thread: 1).arg_retval);
36 EXPECT_EQ(routine, td.GetArgs(thread: 1).routine);
37 EXPECT_EQ(1u, td.size());
38
39 td.Finish(thread: 1, retval);
40 EXPECT_EQ(1u, td.size());
41
42 td.Join(thread: 1, fn: []() { return false; });
43 EXPECT_EQ(1u, td.size());
44
45 td.Join(thread: 1, fn: []() { return true; });
46 EXPECT_EQ(0u, td.size());
47}
48
49TEST(ThreadArgRetvalTest, CreateJoinRun) {
50 ThreadArgRetval td;
51 td.Create(detached: false, args: {.routine: routine, .arg_retval: arg}, fn: []() { return 1; });
52 EXPECT_EQ(1u, td.size());
53
54 td.Join(thread: 1, fn: []() { return false; });
55 EXPECT_EQ(1u, td.size());
56
57 td.Join(thread: 1, fn: [&]() {
58 // Expected to happen on another thread.
59 EXPECT_EQ(1u, td.size());
60
61 EXPECT_EQ(arg, td.GetArgs(thread: 1).arg_retval);
62 EXPECT_EQ(routine, td.GetArgs(thread: 1).routine);
63 EXPECT_EQ(1u, td.size());
64
65 td.Finish(thread: 1, retval);
66 EXPECT_EQ(1u, td.size());
67 return true;
68 });
69 EXPECT_EQ(0u, td.size());
70}
71
72TEST(ThreadArgRetvalTest, CreateRunDetach) {
73 ThreadArgRetval td;
74 td.Create(detached: false, args: {.routine: routine, .arg_retval: arg}, fn: []() { return 1; });
75 EXPECT_EQ(1u, td.size());
76
77 EXPECT_EQ(arg, td.GetArgs(thread: 1).arg_retval);
78 EXPECT_EQ(routine, td.GetArgs(thread: 1).routine);
79 EXPECT_EQ(1u, td.size());
80
81 td.Finish(thread: 1, retval);
82 EXPECT_EQ(1u, td.size());
83
84 td.Detach(thread: 1, fn: []() { return false; });
85 EXPECT_EQ(1u, td.size());
86
87 td.Detach(thread: 1, fn: []() { return true; });
88 EXPECT_EQ(0u, td.size());
89}
90
91TEST(ThreadArgRetvalTest, CreateDetachRun) {
92 ThreadArgRetval td;
93 td.Create(detached: false, args: {.routine: routine, .arg_retval: arg}, fn: []() { return 1; });
94 EXPECT_EQ(1u, td.size());
95
96 td.Detach(thread: 1, fn: []() { return true; });
97 EXPECT_EQ(1u, td.size());
98
99 EXPECT_EQ(arg, td.GetArgs(thread: 1).arg_retval);
100 EXPECT_EQ(routine, td.GetArgs(thread: 1).routine);
101 EXPECT_EQ(1u, td.size());
102
103 td.Finish(thread: 1, retval);
104 EXPECT_EQ(0u, td.size());
105}
106
107TEST(ThreadArgRetvalTest, CreateRunJoinReuse) {
108 ThreadArgRetval td;
109 td.Create(detached: false, args: {.routine: routine, .arg_retval: arg}, fn: []() { return 1; });
110 EXPECT_EQ(1u, td.size());
111
112 td.Finish(thread: 1, retval);
113 EXPECT_EQ(1u, td.size());
114
115 td.Join(thread: 1, fn: [&]() {
116 // Reuse thread id.
117 td.Create(detached: false, args: {.routine: routine, .arg_retval: arg}, fn: []() { return 1; });
118 EXPECT_EQ(1u, td.size());
119 return true;
120 });
121 // Even if JoinFn succeeded, we can't erase mismatching thread.
122 EXPECT_EQ(1u, td.size());
123
124 // Now we can join another one.
125 td.Join(thread: 1, fn: []() { return true; });
126 EXPECT_EQ(0u, td.size());
127}
128
129TEST(ThreadArgRetvalTest, GetAllPtrsLocked) {
130 ThreadArgRetval td;
131 td.Create(detached: false, args: {.routine: routine, .arg_retval: arg}, fn: []() { return 1; });
132 {
133 GenericScopedLock<ThreadArgRetval> lock(&td);
134 InternalMmapVector<uptr> ptrs;
135 td.GetAllPtrsLocked(ptrs: &ptrs);
136 EXPECT_EQ(1u, ptrs.size());
137 EXPECT_EQ((uptr)arg, ptrs[0]);
138 }
139
140 td.Finish(thread: 1, retval);
141 {
142 GenericScopedLock<ThreadArgRetval> lock(&td);
143 InternalMmapVector<uptr> ptrs;
144 td.GetAllPtrsLocked(ptrs: &ptrs);
145 EXPECT_EQ(1u, ptrs.size());
146 EXPECT_EQ((uptr)retval, ptrs[0]);
147 }
148
149 td.Join(thread: 1, fn: []() { return true; });
150 {
151 GenericScopedLock<ThreadArgRetval> lock(&td);
152 InternalMmapVector<uptr> ptrs;
153 td.GetAllPtrsLocked(ptrs: &ptrs);
154 EXPECT_TRUE(ptrs.empty());
155 }
156}
157
158} // namespace __sanitizer
159

source code of compiler-rt/lib/sanitizer_common/tests/sanitizer_thread_arg_retval_test.cpp