From 4d0745cad5835866631e43d024fd61081adf3e8c Mon Sep 17 00:00:00 2001 From: Julian Lettner Date: Thu, 14 Mar 2019 20:59:41 +0000 Subject: [NFC][TSan] Move libdispatch tests into their own subfolder Remove 'gcd' file prefix. GCD stands for Grand Central Dispatch, which is another name for libdispatch. https://apple.github.io/swift-corelibs-libdispatch/ Remove `REQUIRE: dispatch` from tests. Also rename lit feature 'dispatch' -> 'libdispatch' to be more explicit what this is about. Reviewed By: kubamracek Differential Revision: https://reviews.llvm.org/D59341 git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@356202 91177308-0d34-0410-b5e6-96231b3b80d8 --- test/lit.common.cfg | 6 +-- test/tsan/gcd-apply-race.c | 32 -------------- test/tsan/gcd-apply.c | 54 ------------------------ test/tsan/gcd-data.c | 43 ------------------- test/tsan/gcd-dispatch_main.c | 43 ------------------- test/tsan/gcd-dispatch_once_deadlock.c | 45 -------------------- test/tsan/gcd-groups-destructor.c | 45 -------------------- test/tsan/gcd-groups-leave.c | 58 -------------------------- test/tsan/gcd-groups-stress.c | 47 --------------------- test/tsan/gcd-once.c | 57 ------------------------- test/tsan/gcd-semaphore-norace.c | 33 --------------- test/tsan/gcd-source-serial.c | 40 ------------------ test/tsan/gcd-suspend.c | 49 ---------------------- test/tsan/libdispatch/apply-race.c | 30 +++++++++++++ test/tsan/libdispatch/apply.c | 52 +++++++++++++++++++++++ test/tsan/libdispatch/data.c | 41 ++++++++++++++++++ test/tsan/libdispatch/dispatch_main.c | 41 ++++++++++++++++++ test/tsan/libdispatch/dispatch_once_deadlock.c | 43 +++++++++++++++++++ test/tsan/libdispatch/groups-destructor.c | 43 +++++++++++++++++++ test/tsan/libdispatch/groups-leave.c | 56 +++++++++++++++++++++++++ test/tsan/libdispatch/groups-stress.c | 45 ++++++++++++++++++++ test/tsan/libdispatch/lit.local.cfg | 11 +++++ test/tsan/libdispatch/once.c | 55 ++++++++++++++++++++++++ test/tsan/libdispatch/semaphore-norace.c | 31 ++++++++++++++ test/tsan/libdispatch/source-serial.c | 38 +++++++++++++++++ test/tsan/libdispatch/suspend.c | 47 +++++++++++++++++++++ 26 files changed, 536 insertions(+), 549 deletions(-) delete mode 100644 test/tsan/gcd-apply-race.c delete mode 100644 test/tsan/gcd-apply.c delete mode 100644 test/tsan/gcd-data.c delete mode 100644 test/tsan/gcd-dispatch_main.c delete mode 100644 test/tsan/gcd-dispatch_once_deadlock.c delete mode 100644 test/tsan/gcd-groups-destructor.c delete mode 100644 test/tsan/gcd-groups-leave.c delete mode 100644 test/tsan/gcd-groups-stress.c delete mode 100644 test/tsan/gcd-once.c delete mode 100644 test/tsan/gcd-semaphore-norace.c delete mode 100644 test/tsan/gcd-source-serial.c delete mode 100644 test/tsan/gcd-suspend.c create mode 100644 test/tsan/libdispatch/apply-race.c create mode 100644 test/tsan/libdispatch/apply.c create mode 100644 test/tsan/libdispatch/data.c create mode 100644 test/tsan/libdispatch/dispatch_main.c create mode 100644 test/tsan/libdispatch/dispatch_once_deadlock.c create mode 100644 test/tsan/libdispatch/groups-destructor.c create mode 100644 test/tsan/libdispatch/groups-leave.c create mode 100644 test/tsan/libdispatch/groups-stress.c create mode 100644 test/tsan/libdispatch/lit.local.cfg create mode 100644 test/tsan/libdispatch/once.c create mode 100644 test/tsan/libdispatch/semaphore-norace.c create mode 100644 test/tsan/libdispatch/source-serial.c create mode 100644 test/tsan/libdispatch/suspend.c diff --git a/test/lit.common.cfg b/test/lit.common.cfg index 1f67e5a2b..37132c3d0 100644 --- a/test/lit.common.cfg +++ b/test/lit.common.cfg @@ -222,9 +222,9 @@ compiler_rt_debug = getattr(config, 'compiler_rt_debug', False) if not compiler_rt_debug: config.available_features.add('compiler-rt-optimized') -dispatch = getattr(config, 'compiler_rt_intercept_libdispatch') -if dispatch: - config.available_features.add('dispatch') +libdispatch = getattr(config, 'compiler_rt_intercept_libdispatch') +if libdispatch: + config.available_features.add('libdispatch') sanitizer_can_use_cxxabi = getattr(config, 'sanitizer_can_use_cxxabi', True) if sanitizer_can_use_cxxabi: diff --git a/test/tsan/gcd-apply-race.c b/test/tsan/gcd-apply-race.c deleted file mode 100644 index bfdf99837..000000000 --- a/test/tsan/gcd-apply-race.c +++ /dev/null @@ -1,32 +0,0 @@ -// 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 diff --git a/test/tsan/gcd-apply.c b/test/tsan/gcd-apply.c deleted file mode 100644 index 90dc35965..000000000 --- a/test/tsan/gcd-apply.c +++ /dev/null @@ -1,54 +0,0 @@ -// 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 diff --git a/test/tsan/gcd-data.c b/test/tsan/gcd-data.c deleted file mode 100644 index 87dd2d9cd..000000000 --- a/test/tsan/gcd-data.c +++ /dev/null @@ -1,43 +0,0 @@ -// RUN: %clang_tsan %s -o %t -// RUN: %run %t 2>&1 | FileCheck %s - -// REQUIRES: dispatch - -// TODO(yln): fails on one of our bots, need to investigate -// REQUIRES: disabled - -#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. diff --git a/test/tsan/gcd-dispatch_main.c b/test/tsan/gcd-dispatch_main.c deleted file mode 100644 index 2023ba0c7..000000000 --- a/test/tsan/gcd-dispatch_main.c +++ /dev/null @@ -1,43 +0,0 @@ -// 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 diff --git a/test/tsan/gcd-dispatch_once_deadlock.c b/test/tsan/gcd-dispatch_once_deadlock.c deleted file mode 100644 index fd2cdc529..000000000 --- a/test/tsan/gcd-dispatch_once_deadlock.c +++ /dev/null @@ -1,45 +0,0 @@ -// 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. diff --git a/test/tsan/gcd-groups-destructor.c b/test/tsan/gcd-groups-destructor.c deleted file mode 100644 index a2c7eac83..000000000 --- a/test/tsan/gcd-groups-destructor.c +++ /dev/null @@ -1,45 +0,0 @@ -// 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. diff --git a/test/tsan/gcd-groups-leave.c b/test/tsan/gcd-groups-leave.c deleted file mode 100644 index d51edcfd7..000000000 --- a/test/tsan/gcd-groups-leave.c +++ /dev/null @@ -1,58 +0,0 @@ -// 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. diff --git a/test/tsan/gcd-groups-stress.c b/test/tsan/gcd-groups-stress.c deleted file mode 100644 index 0ae373cbd..000000000 --- a/test/tsan/gcd-groups-stress.c +++ /dev/null @@ -1,47 +0,0 @@ -// 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 diff --git a/test/tsan/gcd-once.c b/test/tsan/gcd-once.c deleted file mode 100644 index 5a62c4260..000000000 --- a/test/tsan/gcd-once.c +++ /dev/null @@ -1,57 +0,0 @@ -// 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 diff --git a/test/tsan/gcd-semaphore-norace.c b/test/tsan/gcd-semaphore-norace.c deleted file mode 100644 index 85792f6a8..000000000 --- a/test/tsan/gcd-semaphore-norace.c +++ /dev/null @@ -1,33 +0,0 @@ -// 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 diff --git a/test/tsan/gcd-source-serial.c b/test/tsan/gcd-source-serial.c deleted file mode 100644 index 7ce52bb3e..000000000 --- a/test/tsan/gcd-source-serial.c +++ /dev/null @@ -1,40 +0,0 @@ -// RUN: %clang_tsan %s -o %t -// RUN: %run %t 2>&1 | FileCheck %s - -// REQUIRES: dispatch - -// TODO(yln): fails on one of our bots, need to investigate -// REQUIRES: disabled - -#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. diff --git a/test/tsan/gcd-suspend.c b/test/tsan/gcd-suspend.c deleted file mode 100644 index ebca4c1dd..000000000 --- a/test/tsan/gcd-suspend.c +++ /dev/null @@ -1,49 +0,0 @@ -// 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. diff --git a/test/tsan/libdispatch/apply-race.c b/test/tsan/libdispatch/apply-race.c new file mode 100644 index 000000000..10e954c23 --- /dev/null +++ b/test/tsan/libdispatch/apply-race.c @@ -0,0 +1,30 @@ +// RUN: %clang_tsan %s -o %t +// RUN: %deflake %run %t 2>&1 | FileCheck %s + +#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 diff --git a/test/tsan/libdispatch/apply.c b/test/tsan/libdispatch/apply.c new file mode 100644 index 000000000..d5c991f32 --- /dev/null +++ b/test/tsan/libdispatch/apply.c @@ -0,0 +1,52 @@ +// RUN: %clang_tsan %s -o %t +// RUN: %run %t 2>&1 | FileCheck %s + +// 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 diff --git a/test/tsan/libdispatch/data.c b/test/tsan/libdispatch/data.c new file mode 100644 index 000000000..7a6975bdc --- /dev/null +++ b/test/tsan/libdispatch/data.c @@ -0,0 +1,41 @@ +// RUN: %clang_tsan %s -o %t +// RUN: %run %t 2>&1 | FileCheck %s + +// TODO(yln): fails on one of our bots, need to investigate +// REQUIRES: disabled + +#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. diff --git a/test/tsan/libdispatch/dispatch_main.c b/test/tsan/libdispatch/dispatch_main.c new file mode 100644 index 000000000..43b0d08cc --- /dev/null +++ b/test/tsan/libdispatch/dispatch_main.c @@ -0,0 +1,41 @@ +// 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 + +#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 diff --git a/test/tsan/libdispatch/dispatch_once_deadlock.c b/test/tsan/libdispatch/dispatch_once_deadlock.c new file mode 100644 index 000000000..1e9e7d139 --- /dev/null +++ b/test/tsan/libdispatch/dispatch_once_deadlock.c @@ -0,0 +1,43 @@ +// Check that calling dispatch_once from a report callback works. + +// RUN: %clang_tsan %s -o %t +// RUN: not %run %t 2>&1 | FileCheck %s + +#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. diff --git a/test/tsan/libdispatch/groups-destructor.c b/test/tsan/libdispatch/groups-destructor.c new file mode 100644 index 000000000..100f6fc7c --- /dev/null +++ b/test/tsan/libdispatch/groups-destructor.c @@ -0,0 +1,43 @@ +// RUN: %clangxx_tsan %s -o %t +// RUN: %run %t 2>&1 | FileCheck %s + +#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. diff --git a/test/tsan/libdispatch/groups-leave.c b/test/tsan/libdispatch/groups-leave.c new file mode 100644 index 000000000..0e487870a --- /dev/null +++ b/test/tsan/libdispatch/groups-leave.c @@ -0,0 +1,56 @@ +// RUN: %clang_tsan %s -o %t +// RUN: %run %t 2>&1 | FileCheck %s + +#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. diff --git a/test/tsan/libdispatch/groups-stress.c b/test/tsan/libdispatch/groups-stress.c new file mode 100644 index 000000000..0fdaac050 --- /dev/null +++ b/test/tsan/libdispatch/groups-stress.c @@ -0,0 +1,45 @@ +// RUN: %clang_tsan %s -o %t +// RUN: %run %t 2>&1 | FileCheck %s + +#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 diff --git a/test/tsan/libdispatch/lit.local.cfg b/test/tsan/libdispatch/lit.local.cfg new file mode 100644 index 000000000..b312a3a1f --- /dev/null +++ b/test/tsan/libdispatch/lit.local.cfg @@ -0,0 +1,11 @@ +def getRoot(config): + if not config.parent: + return config + return getRoot(config.parent) + +root = getRoot(config) + +if 'libdispatch' not in root.available_features: + config.unsupported = True + +config.target_cflags += ' -fblocks' diff --git a/test/tsan/libdispatch/once.c b/test/tsan/libdispatch/once.c new file mode 100644 index 000000000..00227b88e --- /dev/null +++ b/test/tsan/libdispatch/once.c @@ -0,0 +1,55 @@ +// RUN: %clang_tsan %s -o %t +// RUN: %run %t 2>&1 | FileCheck %s + +#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 diff --git a/test/tsan/libdispatch/semaphore-norace.c b/test/tsan/libdispatch/semaphore-norace.c new file mode 100644 index 000000000..ce94a3cbf --- /dev/null +++ b/test/tsan/libdispatch/semaphore-norace.c @@ -0,0 +1,31 @@ +// RUN: %clang_tsan %s -o %t +// RUN: %run %t 2>&1 | FileCheck %s + +#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 diff --git a/test/tsan/libdispatch/source-serial.c b/test/tsan/libdispatch/source-serial.c new file mode 100644 index 000000000..79dc1afea --- /dev/null +++ b/test/tsan/libdispatch/source-serial.c @@ -0,0 +1,38 @@ +// RUN: %clang_tsan %s -o %t +// RUN: %run %t 2>&1 | FileCheck %s + +// TODO(yln): fails on one of our bots, need to investigate +// REQUIRES: disabled + +#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. diff --git a/test/tsan/libdispatch/suspend.c b/test/tsan/libdispatch/suspend.c new file mode 100644 index 000000000..5566faf0c --- /dev/null +++ b/test/tsan/libdispatch/suspend.c @@ -0,0 +1,47 @@ +// RUN: %clang_tsan %s -o %t +// RUN: %run %t 2>&1 | FileCheck %s + +#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. -- cgit v1.2.1