mirror of
https://github.com/llvm/llvm-project.git
synced 2025-04-16 14:56:39 +00:00

I introduced this test in #86537, let's remove some unneeded debugging comments. This PR was initially also moving the test to linux directory but looks like it's already done by 17ab9e64464f989b3fe4a304a450581a618097a0 .
114 lines
2.7 KiB
C++
114 lines
2.7 KiB
C++
// RUN: %clang_tsan %s -lstdc++ -o %t && %run %t 2>&1 | FileCheck %s
|
|
|
|
#include "../test.h"
|
|
#include <errno.h>
|
|
#include <linux/futex.h>
|
|
#include <pthread.h>
|
|
#include <signal.h>
|
|
#include <stdio.h>
|
|
#include <sys/syscall.h>
|
|
|
|
#include <cassert>
|
|
#include <stdexcept>
|
|
#include <thread>
|
|
|
|
#include <sanitizer/linux_syscall_hooks.h>
|
|
|
|
int futex(int *uaddr, int futex_op, int val, const struct timespec *timeout,
|
|
int *uaddr2, int val3) {
|
|
__sanitizer_syscall_pre_futex(uaddr, futex_op, val, timeout, uaddr2, val3);
|
|
int result = syscall(SYS_futex, uaddr, futex_op, val, timeout, uaddr2, val3);
|
|
__sanitizer_syscall_post_futex(result, uaddr, futex_op, val, timeout, uaddr2,
|
|
val3);
|
|
return result;
|
|
}
|
|
|
|
// Simple mutex implementation using futex.
|
|
class Mutex {
|
|
public:
|
|
Mutex() : value(0) {}
|
|
|
|
void lock() {
|
|
int c;
|
|
while ((c = __sync_val_compare_and_swap(&value, 0, 1)) != 0) {
|
|
if (c != 1)
|
|
continue;
|
|
int r = futex(&value, FUTEX_WAIT_PRIVATE, 1, nullptr, nullptr, 0);
|
|
if (r == -1 && errno != EAGAIN) {
|
|
fprintf(stderr, "futex wait error\n");
|
|
abort();
|
|
}
|
|
}
|
|
}
|
|
|
|
void unlock() {
|
|
value = 0;
|
|
int r = futex(&value, FUTEX_WAKE_PRIVATE, 1, nullptr, nullptr, 0);
|
|
if (r == -1) {
|
|
fprintf(stderr, "futex wake error\n");
|
|
abort();
|
|
}
|
|
}
|
|
|
|
private:
|
|
int value;
|
|
};
|
|
|
|
Mutex mutex;
|
|
|
|
void *Thread(void *x) {
|
|
// Waiting for the futex.
|
|
mutex.lock();
|
|
// Finished waiting.
|
|
return nullptr;
|
|
}
|
|
|
|
static void SigprofHandler(int signal, siginfo_t *info, void *context) {
|
|
// Unlock the futex.
|
|
mutex.unlock();
|
|
}
|
|
|
|
void InstallSignalHandler() {
|
|
struct sigaction sa;
|
|
sa.sa_sigaction = SigprofHandler;
|
|
sigemptyset(&sa.sa_mask);
|
|
sa.sa_flags = SA_RESTART | SA_SIGINFO;
|
|
if (sigaction(SIGPROF, &sa, 0) != 0) {
|
|
fprintf(stderr, "failed to install signal handler\n");
|
|
abort();
|
|
}
|
|
}
|
|
|
|
int main() {
|
|
alarm(60); // Kill the test if it hangs.
|
|
|
|
// Install the signal handler
|
|
InstallSignalHandler();
|
|
|
|
// Lock the futex at first so the other thread will wait for it.
|
|
mutex.lock();
|
|
|
|
// Create the thread to wait for the futex.
|
|
pthread_t thread;
|
|
pthread_create(&thread, NULL, Thread, NULL);
|
|
|
|
// Just waiting a bit to make sure the thead is at the FUTEX_WAIT_PRIVATE
|
|
// syscall.
|
|
std::this_thread::sleep_for(std::chrono::milliseconds(100));
|
|
|
|
// Send the signal to the other thread, which will send the futex wake
|
|
// syscall.
|
|
int r = pthread_kill(thread, SIGPROF);
|
|
assert(r == 0);
|
|
|
|
// Futex should be notified and the thread should be able to continue.
|
|
pthread_join(thread, NULL);
|
|
|
|
// Exiting successfully.
|
|
fprintf(stderr, "PASS\n");
|
|
return 0;
|
|
}
|
|
|
|
// CHECK-NOT: WARNING: ThreadSanitizer:
|
|
// CHECK: PASS
|