1 | // RUN: %clang_tsan -O1 %s -o %t && %run %t 2>&1 | FileCheck %s |
2 | // The test was reported to hang sometimes on Darwin: |
3 | // https://lists.llvm.org/pipermail/llvm-commits/Week-of-Mon-20210517/917003.html |
4 | // UNSUPPORTED: darwin |
5 | |
6 | #include "test.h" |
7 | #include <signal.h> |
8 | #include <string.h> |
9 | #include <sys/time.h> |
10 | |
11 | int test; |
12 | int done; |
13 | int signals_handled; |
14 | pthread_t main_thread; |
15 | pthread_mutex_t mutex; |
16 | pthread_cond_t cond; |
17 | |
18 | void timer_handler(int signum) { |
19 | write(fd: 2, buf: "timer_handler\n" , n: strlen(s: "timer_handler\n" )); |
20 | if (++signals_handled < 10) |
21 | return; |
22 | switch (test) { |
23 | case 0: |
24 | __atomic_store_n(&done, 1, __ATOMIC_RELEASE); |
25 | (void)pthread_kill(threadid: main_thread, SIGUSR1); |
26 | case 1: |
27 | if (pthread_mutex_trylock(mutex: &mutex) == 0) { |
28 | __atomic_store_n(&done, 1, __ATOMIC_RELEASE); |
29 | pthread_cond_signal(cond: &cond); |
30 | pthread_mutex_unlock(mutex: &mutex); |
31 | } |
32 | case 2: |
33 | __atomic_store_n(&done, 1, __ATOMIC_RELEASE); |
34 | } |
35 | } |
36 | |
37 | int main(int argc, char **argv) { |
38 | main_thread = pthread_self(); |
39 | pthread_mutex_init(mutex: &mutex, mutexattr: 0); |
40 | pthread_cond_init(cond: &cond, cond_attr: 0); |
41 | |
42 | sigset_t sigset; |
43 | sigemptyset(set: &sigset); |
44 | sigaddset(set: &sigset, SIGUSR1); |
45 | if (sigprocmask(SIG_BLOCK, set: &sigset, NULL)) |
46 | exit(status: (perror(s: "sigprocmask" ), 1)); |
47 | |
48 | struct sigaction sa; |
49 | memset(s: &sa, c: 0, n: sizeof(sa)); |
50 | sa.sa_handler = &timer_handler; |
51 | if (sigaction(SIGALRM, act: &sa, NULL)) |
52 | exit(status: (perror(s: "setitimer" ), 1)); |
53 | |
54 | for (test = 0; test < 3; test++) { |
55 | fprintf(stderr, format: "test %d\n" , test); |
56 | struct itimerval timer; |
57 | timer.it_value.tv_sec = 0; |
58 | timer.it_value.tv_usec = 50000; |
59 | timer.it_interval = timer.it_value; |
60 | if (setitimer(ITIMER_REAL, new: &timer, NULL)) |
61 | exit(status: (perror(s: "setitimer" ), 1)); |
62 | |
63 | switch (test) { |
64 | case 0: |
65 | while (__atomic_load_n(&done, __ATOMIC_ACQUIRE) == 0) { |
66 | int signum; |
67 | sigwait(set: &sigset, sig: &signum); |
68 | write(fd: 2, buf: "sigwait\n" , n: strlen(s: "sigwait\n" )); |
69 | } |
70 | case 1: |
71 | pthread_mutex_lock(mutex: &mutex); |
72 | while (__atomic_load_n(&done, __ATOMIC_ACQUIRE) == 0) { |
73 | pthread_cond_wait(cond: &cond, mutex: &mutex); |
74 | write(fd: 2, buf: "pthread_cond_wait\n" , n: strlen(s: "pthread_cond_wait\n" )); |
75 | } |
76 | pthread_mutex_unlock(mutex: &mutex); |
77 | case 2: |
78 | while (__atomic_load_n(&done, __ATOMIC_ACQUIRE) == 0) { |
79 | } |
80 | } |
81 | |
82 | memset(s: &timer, c: 0, n: sizeof(timer)); |
83 | if (setitimer(ITIMER_REAL, new: &timer, NULL)) |
84 | exit(status: (perror(s: "setitimer" ), 1)); |
85 | done = 0; |
86 | signals_handled = 0; |
87 | } |
88 | fprintf(stderr, format: "DONE\n" ); |
89 | } |
90 | |
91 | // CHECK: DONE |
92 | |