1 | // RUN: %clang_tsan %s -lstdc++ -o %t && %run %t 2>&1 | FileCheck %s |
2 | |
3 | #include "../test.h" |
4 | #include <errno.h> |
5 | #include <linux/futex.h> |
6 | #include <pthread.h> |
7 | #include <signal.h> |
8 | #include <stdio.h> |
9 | #include <sys/syscall.h> |
10 | |
11 | #include <cassert> |
12 | #include <stdexcept> |
13 | #include <thread> |
14 | |
15 | #include <sanitizer/linux_syscall_hooks.h> |
16 | |
17 | int futex(int *uaddr, int futex_op, int val, const struct timespec *timeout, |
18 | int *uaddr2, int val3) { |
19 | __sanitizer_syscall_pre_futex(uaddr, futex_op, val, timeout, uaddr2, val3); |
20 | int result = syscall(SYS_futex, uaddr, futex_op, val, timeout, uaddr2, val3); |
21 | __sanitizer_syscall_post_futex(result, uaddr, futex_op, val, timeout, uaddr2, |
22 | val3); |
23 | return result; |
24 | } |
25 | |
26 | // Simple mutex implementation using futex. |
27 | class Mutex { |
28 | public: |
29 | Mutex() : value(0) {} |
30 | |
31 | void lock() { |
32 | int c; |
33 | while ((c = __sync_val_compare_and_swap(&value, 0, 1)) != 0) { |
34 | if (c != 1) |
35 | continue; |
36 | int r = futex(uaddr: &value, FUTEX_WAIT_PRIVATE, val: 1, timeout: nullptr, uaddr2: nullptr, val3: 0); |
37 | if (r == -1 && errno != EAGAIN) { |
38 | fprintf(stderr, format: "futex wait error\n" ); |
39 | abort(); |
40 | } |
41 | } |
42 | } |
43 | |
44 | void unlock() { |
45 | value = 0; |
46 | int r = futex(uaddr: &value, FUTEX_WAKE_PRIVATE, val: 1, timeout: nullptr, uaddr2: nullptr, val3: 0); |
47 | if (r == -1) { |
48 | fprintf(stderr, format: "futex wake error\n" ); |
49 | abort(); |
50 | } |
51 | } |
52 | |
53 | private: |
54 | int value; |
55 | }; |
56 | |
57 | Mutex mutex; |
58 | |
59 | void *Thread(void *x) { |
60 | // Waiting for the futex. |
61 | mutex.lock(); |
62 | // Finished waiting. |
63 | return nullptr; |
64 | } |
65 | |
66 | static void SigprofHandler(int signal, siginfo_t *info, void *context) { |
67 | // Unlock the futex. |
68 | mutex.unlock(); |
69 | } |
70 | |
71 | void InstallSignalHandler() { |
72 | struct sigaction sa; |
73 | sa.sa_sigaction = SigprofHandler; |
74 | sigemptyset(set: &sa.sa_mask); |
75 | sa.sa_flags = SA_RESTART | SA_SIGINFO; |
76 | if (sigaction(SIGPROF, act: &sa, oact: 0) != 0) { |
77 | fprintf(stderr, format: "failed to install signal handler\n" ); |
78 | abort(); |
79 | } |
80 | } |
81 | |
82 | int main() { |
83 | alarm(seconds: 60); // Kill the test if it hangs. |
84 | |
85 | // Install the signal handler |
86 | InstallSignalHandler(); |
87 | |
88 | // Lock the futex at first so the other thread will wait for it. |
89 | mutex.lock(); |
90 | |
91 | // Create the thread to wait for the futex. |
92 | pthread_t thread; |
93 | pthread_create(newthread: &thread, NULL, start_routine: Thread, NULL); |
94 | |
95 | // Just waiting a bit to make sure the thead is at the FUTEX_WAIT_PRIVATE |
96 | // syscall. |
97 | std::this_thread::sleep_for(std::chrono::milliseconds(100)); |
98 | |
99 | // Send the signal to the other thread, which will send the futex wake |
100 | // syscall. |
101 | int r = pthread_kill(threadid: thread, SIGPROF); |
102 | assert(r == 0); |
103 | |
104 | // Futex should be notified and the thread should be able to continue. |
105 | pthread_join(th: thread, NULL); |
106 | |
107 | // Exiting successfully. |
108 | fprintf(stderr, format: "PASS\n" ); |
109 | return 0; |
110 | } |
111 | |
112 | // CHECK-NOT: WARNING: ThreadSanitizer: |
113 | // CHECK: PASS |
114 | |