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
17int 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.
27class Mutex {
28public:
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
53private:
54 int value;
55};
56
57Mutex mutex;
58
59void *Thread(void *x) {
60 // Waiting for the futex.
61 mutex.lock();
62 // Finished waiting.
63 return nullptr;
64}
65
66static void SigprofHandler(int signal, siginfo_t *info, void *context) {
67 // Unlock the futex.
68 mutex.unlock();
69}
70
71void 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
82int 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

source code of compiler-rt/test/tsan/Linux/signal_in_futex_wait.cpp