1 // RUN: %clang_tsan -O1 %s -o %t && %run %t 2>&1 | FileCheck %s
3 // Test case for recursive signal handlers, adopted from:
4 // https://github.com/google/sanitizers/issues/478
13 static const int kSigSuspend
= SIGUSR1
;
14 static const int kSigRestart
= SIGUSR2
;
16 static sem_t g_thread_suspend_ack_sem
;
18 static bool g_busy_thread_received_restart
;
20 static volatile bool g_busy_thread_garbage_collected
;
22 static void SaveRegistersInStack() {
23 // Mono walks thread stacks to detect unreferenced objects.
24 // If last object reference is kept in register the object will be collected
25 // This is why threads can't be suspended with something like pthread_suspend
28 static void fail(const char *what
) {
29 fprintf(stderr
, "FAILED: %s (errno=%d)\n", what
, errno
);
33 static void SuspendHandler(int sig
) {
34 int old_errno
= errno
;
35 SaveRegistersInStack();
37 // Enable kSigRestart handling, tsan disables signals around signal handlers.
40 pthread_sigmask(SIG_SETMASK
, &sigset
, 0);
42 // Acknowledge that thread is saved and suspended
43 if (sem_post(&g_thread_suspend_ack_sem
) != 0)
44 fail("sem_post failed");
46 // Wait for wakeup signal.
47 while (!g_busy_thread_received_restart
)
48 usleep(100); // wait for kSigRestart signal
50 // Acknowledge that thread restarted
51 if (sem_post(&g_thread_suspend_ack_sem
) != 0)
52 fail("sem_post failed");
54 g_busy_thread_garbage_collected
= true;
59 static void RestartHandler(int sig
) {
60 g_busy_thread_received_restart
= true;
63 static void StopWorld(pthread_t thread
) {
64 if (pthread_kill(thread
, kSigSuspend
) != 0)
65 fail("pthread_kill failed");
67 while (sem_wait(&g_thread_suspend_ack_sem
) != 0) {
69 fail("sem_wait failed");
73 static void StartWorld(pthread_t thread
) {
74 if (pthread_kill(thread
, kSigRestart
) != 0)
75 fail("pthread_kill failed");
77 while (sem_wait(&g_thread_suspend_ack_sem
) != 0) {
79 fail("sem_wait failed");
83 static void CollectGarbage(pthread_t thread
) {
90 if (sem_init(&g_thread_suspend_ack_sem
, 0, 0) != 0)
91 fail("sem_init failed");
93 struct sigaction act
= {};
94 act
.sa_flags
= SA_RESTART
;
95 act
.sa_handler
= &SuspendHandler
;
96 if (sigaction(kSigSuspend
, &act
, NULL
) != 0)
97 fail("sigaction failed");
98 act
.sa_handler
= &RestartHandler
;
99 if (sigaction(kSigRestart
, &act
, NULL
) != 0)
100 fail("sigaction failed");
103 void* BusyThread(void *arg
) {
105 while (!g_busy_thread_garbage_collected
) {
106 usleep(100); // Tsan deadlocks without these sleeps
111 int main(int argc
, const char *argv
[]) {
113 pthread_t busy_thread
;
114 if (pthread_create(&busy_thread
, NULL
, &BusyThread
, NULL
) != 0)
115 fail("pthread_create failed");
116 CollectGarbage(busy_thread
);
117 if (pthread_join(busy_thread
, 0) != 0)
118 fail("pthread_join failed");
119 fprintf(stderr
, "DONE\n");
124 // CHECK-NOT: ThreadSanitizer CHECK failed
125 // CHECK-NOT: WARNING: ThreadSanitizer: