Skip to content

Commit 1b21726

Browse files
committed
[tsan] Use sigsuspend and check that the signals are still blocked in recursive signal test
1 parent 3c283ef commit 1b21726

File tree

1 file changed

+62
-19
lines changed

1 file changed

+62
-19
lines changed

compiler-rt/test/tsan/signal_recursive.cpp

Lines changed: 62 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,6 @@
33
// Test case for recursive signal handlers, adopted from:
44
// https://github.com/google/sanitizers/issues/478
55

6-
// REQUIRES: disabled
7-
86
#include "test.h"
97
#include <semaphore.h>
108
#include <signal.h>
@@ -15,8 +13,6 @@ static const int kSigRestart = SIGUSR2;
1513

1614
static sem_t g_thread_suspend_ack_sem;
1715

18-
static bool g_busy_thread_received_restart;
19-
2016
static volatile bool g_busy_thread_garbage_collected;
2117

2218
static void SaveRegistersInStack() {
@@ -30,22 +26,51 @@ static void fail(const char *what) {
3026
exit(1);
3127
}
3228

29+
static void CheckSigBlocked(const sigset_t &oldset, const sigset_t &newset,
30+
int sig) {
31+
const int is_old_member = sigismember(&oldset, sig);
32+
const int is_new_member = sigismember(&newset, sig);
33+
34+
if (is_old_member == -1 || is_new_member == -1)
35+
fail("sigismember failed");
36+
37+
if (is_old_member != is_new_member)
38+
fail("restoring signals failed");
39+
}
40+
41+
sigset_t GetCurrentSigSet() {
42+
sigset_t set;
43+
if (sigemptyset(&set) != 0)
44+
fail("sigemptyset failed");
45+
46+
if (pthread_sigmask(SIG_BLOCK, NULL, &set) != 0)
47+
fail("pthread_sigmask failed");
48+
49+
return set;
50+
}
51+
3352
static void SuspendHandler(int sig) {
3453
int old_errno = errno;
3554
SaveRegistersInStack();
3655

3756
// Enable kSigRestart handling, tsan disables signals around signal handlers.
38-
sigset_t sigset;
39-
sigemptyset(&sigset);
40-
pthread_sigmask(SIG_SETMASK, &sigset, 0);
57+
const auto oldset = GetCurrentSigSet();
4158

4259
// Acknowledge that thread is saved and suspended
4360
if (sem_post(&g_thread_suspend_ack_sem) != 0)
4461
fail("sem_post failed");
4562

4663
// Wait for wakeup signal.
47-
while (!g_busy_thread_received_restart)
48-
usleep(100); // wait for kSigRestart signal
64+
sigset_t sigset;
65+
sigemptyset(&sigset);
66+
if (sigsuspend(&sigset) != 0 && errno != EINTR)
67+
fail("sigsuspend failed");
68+
69+
const auto newset = GetCurrentSigSet();
70+
71+
// Check that the same signals are blocked as before
72+
CheckSigBlocked(oldset, newset, kSigSuspend);
73+
CheckSigBlocked(oldset, newset, kSigRestart);
4974

5075
// Acknowledge that thread restarted
5176
if (sem_post(&g_thread_suspend_ack_sem) != 0)
@@ -56,31 +81,33 @@ static void SuspendHandler(int sig) {
5681
errno = old_errno;
5782
}
5883

59-
static void RestartHandler(int sig) {
60-
g_busy_thread_received_restart = true;
84+
static void RestartHandler(int sig) {}
85+
86+
static void WaitSem() {
87+
while (sem_wait(&g_thread_suspend_ack_sem) != 0) {
88+
if (errno != EINTR)
89+
fail("sem_wait failed");
90+
}
6191
}
6292

6393
static void StopWorld(pthread_t thread) {
6494
if (pthread_kill(thread, kSigSuspend) != 0)
6595
fail("pthread_kill failed");
6696

67-
while (sem_wait(&g_thread_suspend_ack_sem) != 0) {
68-
if (errno != EINTR)
69-
fail("sem_wait failed");
70-
}
97+
WaitSem();
7198
}
7299

73100
static void StartWorld(pthread_t thread) {
74101
if (pthread_kill(thread, kSigRestart) != 0)
75102
fail("pthread_kill failed");
76103

77-
while (sem_wait(&g_thread_suspend_ack_sem) != 0) {
78-
if (errno != EINTR)
79-
fail("sem_wait failed");
80-
}
104+
WaitSem();
81105
}
82106

83107
static void CollectGarbage(pthread_t thread) {
108+
// Wait for the thread to start
109+
WaitSem();
110+
84111
StopWorld(thread);
85112
// Walk stacks
86113
StartWorld(thread);
@@ -102,21 +129,37 @@ static void Init() {
102129

103130
void* BusyThread(void *arg) {
104131
(void)arg;
132+
const auto oldset = GetCurrentSigSet();
133+
134+
if (sem_post(&g_thread_suspend_ack_sem) != 0)
135+
fail("sem_post failed");
136+
105137
while (!g_busy_thread_garbage_collected) {
106138
usleep(100); // Tsan deadlocks without these sleeps
107139
}
140+
141+
const auto newset = GetCurrentSigSet();
142+
143+
// Check that we have the same signals blocked as before
144+
CheckSigBlocked(oldset, newset, kSigSuspend);
145+
CheckSigBlocked(oldset, newset, kSigRestart);
146+
108147
return NULL;
109148
}
110149

111150
int main(int argc, const char *argv[]) {
112151
Init();
152+
113153
pthread_t busy_thread;
114154
if (pthread_create(&busy_thread, NULL, &BusyThread, NULL) != 0)
115155
fail("pthread_create failed");
156+
116157
CollectGarbage(busy_thread);
117158
if (pthread_join(busy_thread, 0) != 0)
118159
fail("pthread_join failed");
160+
119161
fprintf(stderr, "DONE\n");
162+
120163
return 0;
121164
}
122165

0 commit comments

Comments
 (0)