1 //===-- sanitizer_stoptheworld_test.cc ------------------------------------===//
3 // The LLVM Compiler Infrastructure
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
8 //===----------------------------------------------------------------------===//
10 // Tests for sanitizer_stoptheworld.h
12 //===----------------------------------------------------------------------===//
14 #include "sanitizer_common/sanitizer_platform.h"
15 #if SANITIZER_LINUX && defined(__x86_64__)
17 #include "sanitizer_common/sanitizer_stoptheworld.h"
18 #include "gtest/gtest.h"
20 #include "sanitizer_common/sanitizer_libc.h"
21 #include "sanitizer_common/sanitizer_common.h"
26 namespace __sanitizer
{
28 static pthread_mutex_t incrementer_thread_exit_mutex
;
30 struct CallbackArgument
{
32 volatile bool threads_stopped
;
33 volatile bool callback_executed
;
36 threads_stopped(false),
37 callback_executed(false) {}
40 void *IncrementerThread(void *argument
) {
41 CallbackArgument
*callback_argument
= (CallbackArgument
*)argument
;
43 __sync_fetch_and_add(&callback_argument
->counter
, 1);
44 if (pthread_mutex_trylock(&incrementer_thread_exit_mutex
) == 0) {
45 pthread_mutex_unlock(&incrementer_thread_exit_mutex
);
53 // This callback checks that IncrementerThread is suspended at the time of its
55 void Callback(const SuspendedThreadsList
&suspended_threads_list
,
57 CallbackArgument
*callback_argument
= (CallbackArgument
*)argument
;
58 callback_argument
->callback_executed
= true;
59 int counter_at_init
= __sync_fetch_and_add(&callback_argument
->counter
, 0);
60 for (uptr i
= 0; i
< 1000; i
++) {
62 if (__sync_fetch_and_add(&callback_argument
->counter
, 0) !=
64 callback_argument
->threads_stopped
= false;
68 callback_argument
->threads_stopped
= true;
71 TEST(StopTheWorld
, SuspendThreadsSimple
) {
72 pthread_mutex_init(&incrementer_thread_exit_mutex
, NULL
);
73 CallbackArgument argument
;
75 int pthread_create_result
;
76 pthread_mutex_lock(&incrementer_thread_exit_mutex
);
77 pthread_create_result
= pthread_create(&thread_id
, NULL
, IncrementerThread
,
79 ASSERT_EQ(0, pthread_create_result
);
80 StopTheWorld(&Callback
, &argument
);
81 pthread_mutex_unlock(&incrementer_thread_exit_mutex
);
82 EXPECT_TRUE(argument
.callback_executed
);
83 EXPECT_TRUE(argument
.threads_stopped
);
84 // argument is on stack, so we have to wait for the incrementer thread to
85 // terminate before we can return from this function.
86 ASSERT_EQ(0, pthread_join(thread_id
, NULL
));
87 pthread_mutex_destroy(&incrementer_thread_exit_mutex
);
90 // A more comprehensive test where we spawn a bunch of threads while executing
91 // StopTheWorld in parallel.
92 static const uptr kThreadCount
= 50;
93 static const uptr kStopWorldAfter
= 10; // let this many threads spawn first
95 static pthread_mutex_t advanced_incrementer_thread_exit_mutex
;
97 struct AdvancedCallbackArgument
{
98 volatile uptr thread_index
;
99 volatile int counters
[kThreadCount
];
100 pthread_t thread_ids
[kThreadCount
];
101 volatile bool threads_stopped
;
102 volatile bool callback_executed
;
103 volatile bool fatal_error
;
104 AdvancedCallbackArgument()
106 threads_stopped(false),
107 callback_executed(false),
108 fatal_error(false) {}
111 void *AdvancedIncrementerThread(void *argument
) {
112 AdvancedCallbackArgument
*callback_argument
=
113 (AdvancedCallbackArgument
*)argument
;
114 uptr this_thread_index
= __sync_fetch_and_add(
115 &callback_argument
->thread_index
, 1);
116 // Spawn the next thread.
117 int pthread_create_result
;
118 if (this_thread_index
+ 1 < kThreadCount
) {
119 pthread_create_result
=
120 pthread_create(&callback_argument
->thread_ids
[this_thread_index
+ 1],
121 NULL
, AdvancedIncrementerThread
, argument
);
122 // Cannot use ASSERT_EQ in non-void-returning functions. If there's a
123 // problem, defer failing to the main thread.
124 if (pthread_create_result
!= 0) {
125 callback_argument
->fatal_error
= true;
126 __sync_fetch_and_add(&callback_argument
->thread_index
,
127 kThreadCount
- callback_argument
->thread_index
);
130 // Do the actual work.
132 __sync_fetch_and_add(&callback_argument
->counters
[this_thread_index
], 1);
133 if (pthread_mutex_trylock(&advanced_incrementer_thread_exit_mutex
) == 0) {
134 pthread_mutex_unlock(&advanced_incrementer_thread_exit_mutex
);
142 void AdvancedCallback(const SuspendedThreadsList
&suspended_threads_list
,
144 AdvancedCallbackArgument
*callback_argument
=
145 (AdvancedCallbackArgument
*)argument
;
146 callback_argument
->callback_executed
= true;
148 int counters_at_init
[kThreadCount
];
149 for (uptr j
= 0; j
< kThreadCount
; j
++)
150 counters_at_init
[j
] = __sync_fetch_and_add(&callback_argument
->counters
[j
],
152 for (uptr i
= 0; i
< 10; i
++) {
154 for (uptr j
= 0; j
< kThreadCount
; j
++)
155 if (__sync_fetch_and_add(&callback_argument
->counters
[j
], 0) !=
156 counters_at_init
[j
]) {
157 callback_argument
->threads_stopped
= false;
161 callback_argument
->threads_stopped
= true;
164 TEST(StopTheWorld
, SuspendThreadsAdvanced
) {
165 pthread_mutex_init(&advanced_incrementer_thread_exit_mutex
, NULL
);
166 AdvancedCallbackArgument argument
;
168 pthread_mutex_lock(&advanced_incrementer_thread_exit_mutex
);
169 int pthread_create_result
;
170 pthread_create_result
= pthread_create(&argument
.thread_ids
[0], NULL
,
171 AdvancedIncrementerThread
,
173 ASSERT_EQ(0, pthread_create_result
);
174 // Wait for several threads to spawn before proceeding.
175 while (__sync_fetch_and_add(&argument
.thread_index
, 0) < kStopWorldAfter
)
177 StopTheWorld(&AdvancedCallback
, &argument
);
178 EXPECT_TRUE(argument
.callback_executed
);
179 EXPECT_TRUE(argument
.threads_stopped
);
181 // Wait for all threads to spawn before we start terminating them.
182 while (__sync_fetch_and_add(&argument
.thread_index
, 0) < kThreadCount
)
184 ASSERT_FALSE(argument
.fatal_error
); // a pthread_create has failed
185 // Signal the threads to terminate.
186 pthread_mutex_unlock(&advanced_incrementer_thread_exit_mutex
);
187 for (uptr i
= 0; i
< kThreadCount
; i
++)
188 ASSERT_EQ(0, pthread_join(argument
.thread_ids
[i
], NULL
));
189 pthread_mutex_destroy(&advanced_incrementer_thread_exit_mutex
);
192 } // namespace __sanitizer
194 #endif // SANITIZER_LINUX && defined(__x86_64__)