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
1614static sem_t g_thread_suspend_ack_sem;
1715
18- static bool g_busy_thread_received_restart;
19-
2016static volatile bool g_busy_thread_garbage_collected;
2117
2218static 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+
3352static 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
6393static 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
73100static 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
83107static 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
103130void * 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
111150int 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