Index: test/tsan/barrier.cc =================================================================== --- test/tsan/barrier.cc +++ test/tsan/barrier.cc @@ -2,10 +2,7 @@ // CHECK-NOT: ThreadSanitizer: data race // CHECK: DONE -#include -#include -#include -#include +#include "test.h" const int kSize = 4; volatile int kIter = 10; // prevent unwinding Index: test/tsan/bench.h =================================================================== --- test/tsan/bench.h +++ test/tsan/bench.h @@ -5,6 +5,8 @@ #include #include +#include "test.h" + int bench_nthread; int bench_niter; int grow_clock_var; @@ -31,14 +33,9 @@ pthread_barrier_destroy(&glow_clock_barrier); __atomic_load_n(&grow_clock_var, __ATOMIC_ACQUIRE); - timespec tp0; - clock_gettime(CLOCK_MONOTONIC, &tp0); + BENCH_STOPWATCH_START(); bench(); - timespec tp1; - clock_gettime(CLOCK_MONOTONIC, &tp1); - unsigned long long t = - (tp1.tv_sec * 1000000000ULL + tp1.tv_nsec) - - (tp0.tv_sec * 1000000000ULL + tp0.tv_nsec); + BENCH_STOPWATCH_STOP(); fprintf(stderr, "%llu ns/iter\n", t / bench_niter); fprintf(stderr, "DONE\n"); } Index: test/tsan/race_on_barrier2.c =================================================================== --- test/tsan/race_on_barrier2.c +++ test/tsan/race_on_barrier2.c @@ -1,8 +1,5 @@ // RUN: %clang_tsan -O1 %s -o %t && %deflake %run %t | FileCheck %s -#include -#include -#include -#include +#include "test.h" pthread_barrier_t B; int Global; Index: test/tsan/test.h =================================================================== --- test/tsan/test.h +++ test/tsan/test.h @@ -1,3 +1,4 @@ +#include #include #include #include @@ -6,6 +7,10 @@ #include #include +#ifdef __APPLE__ +#include +#endif + // TSan-invisible barrier. // Tests use it to establish necessary execution order in a way that does not // interfere with tsan (does not establish synchronization between threads). @@ -60,3 +65,73 @@ fprintf(stderr, format, (unsigned long) address); #endif } + +#ifdef __APPLE__ + +// Darwin doesn't have pthread_barrier_* APIs, let's re-implement them with +// mutexes and condition variables. +typedef int pthread_barrierattr_t; +typedef struct { + pthread_mutex_t mutex; + pthread_cond_t cond; + int current_count; + int max_count; +} pthread_barrier_t; +#define PTHREAD_BARRIER_SERIAL_THREAD 1 + +int pthread_barrier_init(pthread_barrier_t *barrier, + const pthread_barrierattr_t *attr, unsigned count) { + assert(count > 0); + assert(pthread_mutex_init(&barrier->mutex, 0) == 0); + assert(pthread_cond_init(&barrier->cond, 0) == 0); + barrier->max_count = count; + barrier->current_count = 0; + return 0; +} + +int pthread_barrier_wait(pthread_barrier_t *barrier) { + pthread_mutex_lock(&barrier->mutex); + barrier->current_count += 1; + if (barrier->current_count >= barrier->max_count) { + barrier->current_count = 0; + pthread_cond_broadcast(&barrier->cond); + pthread_mutex_unlock(&barrier->mutex); + return PTHREAD_BARRIER_SERIAL_THREAD; + } else { + pthread_cond_wait(&barrier->cond, &barrier->mutex); + pthread_mutex_unlock(&barrier->mutex); + return 0; + } +} + +int pthread_barrier_destroy(pthread_barrier_t *barrier) { + pthread_cond_destroy(&barrier->cond); + pthread_mutex_destroy(&barrier->mutex); + return 0; +} + +unsigned long long darwin_uptime() { + static mach_timebase_info_data_t timebase_info; + if (timebase_info.denom == 0) mach_timebase_info(&timebase_info); + return (mach_absolute_time() * timebase_info.numer) / timebase_info.denom; +} + +#define BENCH_STOPWATCH_START() \ + unsigned long long tp0 = darwin_uptime() +#define BENCH_STOPWATCH_STOP() \ + unsigned long long tp1 = darwin_uptime(); \ + unsigned long long t = tp1 - tp0 + +#else // __APPLE__ + +#define BENCH_STOPWATCH_START() \ + timespec tp0; \ + clock_gettime(CLOCK_MONOTONIC, &tp0) +#define BENCH_STOPWATCH_STOP() \ + timespec tp1; \ + clock_gettime(CLOCK_MONOTONIC, &tp1); \ + unsigned long long t = \ + (tp1.tv_sec * 1000000000ULL + tp1.tv_nsec) - \ + (tp0.tv_sec * 1000000000ULL + tp0.tv_nsec) + +#endif // __APPLE__