Index: compiler-rt/trunk/test/tsan/gcd-apply-race.c =================================================================== --- compiler-rt/trunk/test/tsan/gcd-apply-race.c +++ compiler-rt/trunk/test/tsan/gcd-apply-race.c @@ -0,0 +1,32 @@ +// RUN: %clang_tsan %s -o %t +// RUN: %deflake %run %t 2>&1 | FileCheck %s + +// REQUIRES: dispatch + +#include + +#include "test.h" + +long global; + +int main(int argc, const char *argv[]) { + barrier_init(&barrier, 2); + fprintf(stderr, "start\n"); + + // Warm up GCD (workaround for macOS Sierra where dispatch_apply might run single-threaded). + dispatch_sync(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ }); + + dispatch_queue_t q = dispatch_queue_create("my.queue", DISPATCH_QUEUE_CONCURRENT); + dispatch_apply(2, q, ^(size_t i) { + global = i; + barrier_wait(&barrier); + }); + + fprintf(stderr, "done\n"); + return 0; +} + +// CHECK: start +// CHECK: WARNING: ThreadSanitizer: data race +// CHECK: Location is global 'global' +// CHECK: done Index: compiler-rt/trunk/test/tsan/gcd-apply.c =================================================================== --- compiler-rt/trunk/test/tsan/gcd-apply.c +++ compiler-rt/trunk/test/tsan/gcd-apply.c @@ -0,0 +1,54 @@ +// RUN: %clang_tsan %s -o %t +// RUN: %run %t 2>&1 | FileCheck %s + +// REQUIRES: dispatch + +// TODO(yln): Deadlocks while gcd-apply.mm does not. What's the difference +// between C and Obj-C compiler? +// REQUIRES: disable + +#include + +#include "test.h" + +long global; +long array[2]; + +void callback(void *context, size_t i) { + long n = global; + array[i] = n + i; + barrier_wait(&barrier); +} + +int main(int argc, const char *argv[]) { + barrier_init(&barrier, 2); + fprintf(stderr, "start\n"); + + // Warm up GCD (workaround for macOS Sierra where dispatch_apply might run single-threaded). + dispatch_sync(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ }); + + dispatch_queue_t q = dispatch_queue_create("my.queue", DISPATCH_QUEUE_CONCURRENT); + + global = 42; + + dispatch_apply(100, q, ^(size_t i) { + long n = global; + array[i] = n + i; + barrier_wait(&barrier); + }); + + for (int i = 0; i < 100; i++) { + fprintf(stderr, "array[%d] = %ld\n", i, array[i]); + } + + global = 43; + + dispatch_apply_f(100, q, NULL, &callback); + + fprintf(stderr, "done\n"); + return 0; +} + +// CHECK: start +// CHECK: done +// CHECK-NOT: WARNING: ThreadSanitizer Index: compiler-rt/trunk/test/tsan/gcd-data.c =================================================================== --- compiler-rt/trunk/test/tsan/gcd-data.c +++ compiler-rt/trunk/test/tsan/gcd-data.c @@ -0,0 +1,40 @@ +// RUN: %clang_tsan %s -o %t +// RUN: %run %t 2>&1 | FileCheck %s + +// REQUIRES: dispatch + +#include + +#include + +long global; + +int main(int argc, const char *argv[]) { + fprintf(stderr, "Hello world.\n"); + + dispatch_queue_t q = dispatch_queue_create("my.queue", DISPATCH_QUEUE_SERIAL); + dispatch_semaphore_t sem = dispatch_semaphore_create(0); + + global = 44; + dispatch_data_t data = dispatch_data_create("buffer", 6, q, ^{ + fprintf(stderr, "Data destructor.\n"); + global++; + + dispatch_semaphore_signal(sem); + }); + dispatch_release(data); + data = NULL; + + dispatch_semaphore_wait(sem, DISPATCH_TIME_FOREVER); + + data = dispatch_data_create("buffer", 6, q, DISPATCH_DATA_DESTRUCTOR_DEFAULT); + dispatch_release(data); + data = NULL; + + fprintf(stderr, "Done.\n"); +} + +// CHECK: Hello world. +// CHECK: Data destructor. +// CHECK-NOT: WARNING: ThreadSanitizer +// CHECK: Done. Index: compiler-rt/trunk/test/tsan/gcd-dispatch_main.c =================================================================== --- compiler-rt/trunk/test/tsan/gcd-dispatch_main.c +++ compiler-rt/trunk/test/tsan/gcd-dispatch_main.c @@ -0,0 +1,43 @@ +// Check that we don't crash when dispatch_main calls pthread_exit which +// quits the main thread. + +// RUN: %clang_tsan %s -o %t +// RUN: %run %t 2>&1 | FileCheck %s + +// REQUIRES: dispatch + +#include + +#include +#include + +int main() { + fprintf(stderr,"Hello world"); + + dispatch_queue_t q = dispatch_queue_create("my.queue", DISPATCH_QUEUE_SERIAL); + + dispatch_async(q, ^{ + fprintf(stderr,"1"); + }); + + dispatch_async(q, ^{ + fprintf(stderr,"2"); + }); + + dispatch_async(q, ^{ + fprintf(stderr,"3"); + + dispatch_async(dispatch_get_main_queue(), ^{ + fprintf(stderr,"Done."); + sleep(1); + exit(0); + }); + }); + + dispatch_main(); +} + +// CHECK: Hello world +// CHECK: Done. +// CHECK-NOT: WARNING: ThreadSanitizer +// CHECK-NOT: CHECK failed Index: compiler-rt/trunk/test/tsan/gcd-dispatch_once_deadlock.c =================================================================== --- compiler-rt/trunk/test/tsan/gcd-dispatch_once_deadlock.c +++ compiler-rt/trunk/test/tsan/gcd-dispatch_once_deadlock.c @@ -0,0 +1,45 @@ +// Check that calling dispatch_once from a report callback works. + +// RUN: %clang_tsan %s -o %t +// RUN: not %run %t 2>&1 | FileCheck %s + +// REQUIRES: dispatch + +#include + +#include +#include + +long g = 0; +long h = 0; +void f() { + static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^{ + g++; + }); + h++; +} + +void __tsan_on_report() { + fprintf(stderr, "Report.\n"); + f(); +} + +int main() { + fprintf(stderr, "Hello world.\n"); + + f(); + + pthread_mutex_t mutex = {0}; + pthread_mutex_lock(&mutex); + + fprintf(stderr, "g = %ld.\n", g); + fprintf(stderr, "h = %ld.\n", h); + fprintf(stderr, "Done.\n"); +} + +// CHECK: Hello world. +// CHECK: Report. +// CHECK: g = 1 +// CHECK: h = 2 +// CHECK: Done. Index: compiler-rt/trunk/test/tsan/gcd-groups-destructor.c =================================================================== --- compiler-rt/trunk/test/tsan/gcd-groups-destructor.c +++ compiler-rt/trunk/test/tsan/gcd-groups-destructor.c @@ -0,0 +1,45 @@ +// RUN: %clangxx_tsan %s -o %t +// RUN: %run %t 2>&1 | FileCheck %s + +// REQUIRES: dispatch + +#include + +#import +#import + +_Atomic(long) destructor_counter = 0; + +struct MyStruct { + virtual ~MyStruct() { + usleep(10000); + atomic_fetch_add_explicit(&destructor_counter, 1, memory_order_relaxed); + } +}; + +int main(int argc, const char *argv[]) { + fprintf(stderr, "Hello world.\n"); + + dispatch_queue_t q = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0); + dispatch_group_t g = dispatch_group_create(); + + for (int i = 0; i < 100; i++) { + std::shared_ptr shared(new MyStruct()); + + dispatch_group_async(g, q, ^{ + shared.get(); // just to make sure the object is captured by the block + }); + } + + dispatch_group_wait(g, DISPATCH_TIME_FOREVER); + + if (destructor_counter != 100) { + abort(); + } + + fprintf(stderr, "Done.\n"); +} + +// CHECK: Hello world. +// CHECK-NOT: WARNING: ThreadSanitizer +// CHECK: Done. Index: compiler-rt/trunk/test/tsan/gcd-groups-leave.c =================================================================== --- compiler-rt/trunk/test/tsan/gcd-groups-leave.c +++ compiler-rt/trunk/test/tsan/gcd-groups-leave.c @@ -0,0 +1,58 @@ +// RUN: %clang_tsan %s -o %t +// RUN: %run %t 2>&1 | FileCheck %s + +// REQUIRES: dispatch + +#include + +#include "test.h" + +dispatch_semaphore_t sem; + +long global; +long global2; + +void callback(void *context) { + global2 = 48; + barrier_wait(&barrier); + + dispatch_semaphore_signal(sem); +} + +int main() { + fprintf(stderr, "Hello world.\n"); + barrier_init(&barrier, 2); + + dispatch_queue_t q = dispatch_queue_create("my.queue", DISPATCH_QUEUE_CONCURRENT); + dispatch_group_t g = dispatch_group_create(); + sem = dispatch_semaphore_create(0); + + dispatch_group_enter(g); + dispatch_async(q, ^{ + global = 47; + dispatch_group_leave(g); + barrier_wait(&barrier); + }); + dispatch_group_notify(g, q, ^{ + global = 48; + barrier_wait(&barrier); + + dispatch_semaphore_signal(sem); + }); + dispatch_semaphore_wait(sem, DISPATCH_TIME_FOREVER); + + dispatch_group_enter(g); + dispatch_async(q, ^{ + global2 = 47; + dispatch_group_leave(g); + barrier_wait(&barrier); + }); + dispatch_group_notify_f(g, q, NULL, &callback); + dispatch_semaphore_wait(sem, DISPATCH_TIME_FOREVER); + + fprintf(stderr, "Done.\n"); +} + +// CHECK: Hello world. +// CHECK-NOT: WARNING: ThreadSanitizer +// CHECK: Done. Index: compiler-rt/trunk/test/tsan/gcd-groups-stress.c =================================================================== --- compiler-rt/trunk/test/tsan/gcd-groups-stress.c +++ compiler-rt/trunk/test/tsan/gcd-groups-stress.c @@ -0,0 +1,47 @@ +// RUN: %clang_tsan %s -o %t +// RUN: %run %t 2>&1 | FileCheck %s + +// REQUIRES: dispatch + +#include + +#include + +void notify_callback(void *context) { + // Do nothing. +} + +int main() { + fprintf(stderr, "Hello world."); + + dispatch_queue_t q = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0); + + for (int i = 0; i < 300000; i++) { + dispatch_group_t g = dispatch_group_create(); + dispatch_group_enter(g); + dispatch_async(q, ^{ + dispatch_group_leave(g); + }); + dispatch_group_notify(g, q, ^{ + // Do nothing. + }); + dispatch_release(g); + } + + for (int i = 0; i < 300000; i++) { + dispatch_group_t g = dispatch_group_create(); + dispatch_group_enter(g); + dispatch_async(q, ^{ + dispatch_group_leave(g); + }); + dispatch_group_notify_f(g, q, NULL, ¬ify_callback); + dispatch_release(g); + } + + fprintf(stderr, "Done."); +} + +// CHECK: Hello world. +// CHECK: Done. +// CHECK-NOT: WARNING: ThreadSanitizer +// CHECK-NOT: CHECK failed Index: compiler-rt/trunk/test/tsan/gcd-once.c =================================================================== --- compiler-rt/trunk/test/tsan/gcd-once.c +++ compiler-rt/trunk/test/tsan/gcd-once.c @@ -0,0 +1,57 @@ +// RUN: %clang_tsan %s -o %t +// RUN: %run %t 2>&1 | FileCheck %s + +// REQUIRES: dispatch + +#include + +#include "test.h" + +static const long kNumThreads = 4; + +long global; +long global2; + +static dispatch_once_t once_token; +static dispatch_once_t once_token2; + +void f(void *a) { + global2 = 42; + usleep(100000); +} + +void *Thread(void *a) { + barrier_wait(&barrier); + + dispatch_once(&once_token, ^{ + global = 42; + usleep(100000); + }); + long x = global; + + dispatch_once_f(&once_token2, NULL, f); + long x2 = global2; + + fprintf(stderr, "global = %ld\n", x); + fprintf(stderr, "global2 = %ld\n", x2); + return 0; +} + +int main() { + fprintf(stderr, "Hello world.\n"); + barrier_init(&barrier, kNumThreads); + + pthread_t t[kNumThreads]; + for (int i = 0; i < kNumThreads; i++) { + pthread_create(&t[i], 0, Thread, 0); + } + for (int i = 0; i < kNumThreads; i++) { + pthread_join(t[i], 0); + } + + fprintf(stderr, "Done.\n"); +} + +// CHECK: Hello world. +// CHECK: Done. +// CHECK-NOT: WARNING: ThreadSanitizer Index: compiler-rt/trunk/test/tsan/gcd-semaphore-norace.c =================================================================== --- compiler-rt/trunk/test/tsan/gcd-semaphore-norace.c +++ compiler-rt/trunk/test/tsan/gcd-semaphore-norace.c @@ -0,0 +1,33 @@ +// RUN: %clang_tsan %s -o %t +// RUN: %run %t 2>&1 | FileCheck %s + +// REQUIRES: dispatch + +#include + +#include + +long global; + +int main() { + fprintf(stderr, "Hello world."); + + global = 42; + + dispatch_semaphore_t sem = dispatch_semaphore_create(0); + dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ + + global = 43; + dispatch_semaphore_signal(sem); + }); + + dispatch_semaphore_wait(sem, DISPATCH_TIME_FOREVER); + global = 44; + + fprintf(stderr, "Done."); + return 0; +} + +// CHECK: Hello world. +// CHECK: Done. +// CHECK-NOT: WARNING: ThreadSanitizer Index: compiler-rt/trunk/test/tsan/gcd-source-serial.c =================================================================== --- compiler-rt/trunk/test/tsan/gcd-source-serial.c +++ compiler-rt/trunk/test/tsan/gcd-source-serial.c @@ -0,0 +1,37 @@ +// RUN: %clang_tsan %s -o %t +// RUN: %run %t 2>&1 | FileCheck %s + +// REQUIRES: dispatch + +#include + +#include + +long global; + +int main(int argc, const char *argv[]) { + fprintf(stderr, "Hello world.\n"); + + dispatch_queue_t q = dispatch_queue_create("my.queue", DISPATCH_QUEUE_SERIAL); + dispatch_semaphore_t sem = dispatch_semaphore_create(0); + dispatch_source_t timer = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0, q); + long long interval_ms = 10; + dispatch_source_set_timer(timer, dispatch_time(DISPATCH_TIME_NOW, 0), interval_ms * NSEC_PER_MSEC, 0); + dispatch_source_set_event_handler(timer, ^{ + fprintf(stderr, "timer\n"); + global++; + + if (global > 50) { + dispatch_semaphore_signal(sem); + } + }); + dispatch_resume(timer); + + dispatch_semaphore_wait(sem, DISPATCH_TIME_FOREVER); + + fprintf(stderr, "Done.\n"); +} + +// CHECK: Hello world. +// CHECK-NOT: WARNING: ThreadSanitizer +// CHECK: Done. Index: compiler-rt/trunk/test/tsan/gcd-suspend.c =================================================================== --- compiler-rt/trunk/test/tsan/gcd-suspend.c +++ compiler-rt/trunk/test/tsan/gcd-suspend.c @@ -0,0 +1,49 @@ +// RUN: %clang_tsan %s -o %t +// RUN: %run %t 2>&1 | FileCheck %s + +// REQUIRES: dispatch + +#include + +#include + +long my_global = 0; + +int main(int argc, const char *argv[]) { + fprintf(stderr, "Hello world.\n"); + + dispatch_queue_t q1 = dispatch_queue_create("queue1", NULL); + dispatch_queue_t q2 = dispatch_queue_create("queue2", NULL); + dispatch_group_t g = dispatch_group_create(); + + dispatch_sync(q1, ^{ + dispatch_suspend(q1); + dispatch_async(q2, ^{ + my_global++; + dispatch_resume(q1); + }); + }); + + dispatch_sync(q1, ^{ + my_global++; + }); + + dispatch_sync(q1, ^{ + dispatch_suspend(q1); + dispatch_group_enter(g); + dispatch_async(q1,^{ my_global++; }); + dispatch_async(q1,^{ my_global++; }); + dispatch_async(q1,^{ my_global++; dispatch_group_leave(g); }); + my_global++; + dispatch_resume(q1); + }); + + dispatch_group_wait(g, DISPATCH_TIME_FOREVER); + + fprintf(stderr, "Done.\n"); + return 0; +} + +// CHECK: Hello world. +// CHECK-NOT: WARNING: ThreadSanitizer +// CHECK: Done.