summaryrefslogtreecommitdiff
path: root/test/tsan/libdispatch
diff options
context:
space:
mode:
authorJulian Lettner <jlettner@apple.com>2019-03-14 20:59:41 +0000
committerJulian Lettner <jlettner@apple.com>2019-03-14 20:59:41 +0000
commit4d0745cad5835866631e43d024fd61081adf3e8c (patch)
treecf2a512abc2392170c4106309085500020ae3fc9 /test/tsan/libdispatch
parentc90e46e7d4ba2f556a765a5808989d1eb36fb001 (diff)
downloadcompiler-rt-4d0745cad5835866631e43d024fd61081adf3e8c.tar.gz
[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
Diffstat (limited to 'test/tsan/libdispatch')
-rw-r--r--test/tsan/libdispatch/apply-race.c30
-rw-r--r--test/tsan/libdispatch/apply.c52
-rw-r--r--test/tsan/libdispatch/data.c41
-rw-r--r--test/tsan/libdispatch/dispatch_main.c41
-rw-r--r--test/tsan/libdispatch/dispatch_once_deadlock.c43
-rw-r--r--test/tsan/libdispatch/groups-destructor.c43
-rw-r--r--test/tsan/libdispatch/groups-leave.c56
-rw-r--r--test/tsan/libdispatch/groups-stress.c45
-rw-r--r--test/tsan/libdispatch/lit.local.cfg11
-rw-r--r--test/tsan/libdispatch/once.c55
-rw-r--r--test/tsan/libdispatch/semaphore-norace.c31
-rw-r--r--test/tsan/libdispatch/source-serial.c38
-rw-r--r--test/tsan/libdispatch/suspend.c47
13 files changed, 533 insertions, 0 deletions
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 <dispatch/dispatch.h>
+
+#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 <dispatch/dispatch.h>
+
+#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 <dispatch/dispatch.h>
+
+#include <stdio.h>
+
+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 <dispatch/dispatch.h>
+
+#include <stdio.h>
+#include <stdlib.h>
+
+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 <dispatch/dispatch.h>
+
+#include <pthread.h>
+#include <stdio.h>
+
+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 <dispatch/dispatch.h>
+
+#import <memory>
+#import <stdatomic.h>
+
+_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<MyStruct> 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 <dispatch/dispatch.h>
+
+#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 <dispatch/dispatch.h>
+
+#include <stdio.h>
+
+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, &notify_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 <dispatch/dispatch.h>
+
+#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 <dispatch/dispatch.h>
+
+#include <stdio.h>
+
+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 <dispatch/dispatch.h>
+
+#include <stdio.h>
+
+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 <dispatch/dispatch.h>
+
+#include <stdio.h>
+
+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.