xref: /llvm-project/compiler-rt/test/tsan/Linux/signal_in_futex_wait.cpp (revision cc98ffb6dc6ca3e68fd939558eb8c4ddb1cc03de)
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 
futex(int * uaddr,int futex_op,int val,const struct timespec * timeout,int * uaddr2,int val3)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:
Mutex()29   Mutex() : value(0) {}
30 
lock()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(&value, FUTEX_WAIT_PRIVATE, 1, nullptr, nullptr, 0);
37       if (r == -1 && errno != EAGAIN) {
38         fprintf(stderr, "futex wait error\n");
39         abort();
40       }
41     }
42   }
43 
unlock()44   void unlock() {
45     value = 0;
46     int r = futex(&value, FUTEX_WAKE_PRIVATE, 1, nullptr, nullptr, 0);
47     if (r == -1) {
48       fprintf(stderr, "futex wake error\n");
49       abort();
50     }
51   }
52 
53 private:
54   int value;
55 };
56 
57 Mutex mutex;
58 
Thread(void * x)59 void *Thread(void *x) {
60   // Waiting for the futex.
61   mutex.lock();
62   // Finished waiting.
63   return nullptr;
64 }
65 
SigprofHandler(int signal,siginfo_t * info,void * context)66 static void SigprofHandler(int signal, siginfo_t *info, void *context) {
67   // Unlock the futex.
68   mutex.unlock();
69 }
70 
InstallSignalHandler()71 void InstallSignalHandler() {
72   struct sigaction sa;
73   sa.sa_sigaction = SigprofHandler;
74   sigemptyset(&sa.sa_mask);
75   sa.sa_flags = SA_RESTART | SA_SIGINFO;
76   if (sigaction(SIGPROF, &sa, 0) != 0) {
77     fprintf(stderr, "failed to install signal handler\n");
78     abort();
79   }
80 }
81 
main()82 int main() {
83   alarm(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(&thread, NULL, 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(thread, SIGPROF);
102   assert(r == 0);
103 
104   // Futex should be notified and the thread should be able to continue.
105   pthread_join(thread, NULL);
106 
107   // Exiting successfully.
108   fprintf(stderr, "PASS\n");
109   return 0;
110 }
111 
112 // CHECK-NOT: WARNING: ThreadSanitizer:
113 // CHECK: PASS
114