From b6daed614e30d8377025efacb90770f9f5f6f5e7 Mon Sep 17 00:00:00 2001 From: Kuba Brecka Date: Mon, 31 Oct 2016 18:28:02 +0000 Subject: [tsan] Add support for GCD target queues MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit GCD (libdispatch) has a concept of “target queues”: Each queue has either an implicit or explicit target queue, where the task is handed over to when it’s time to execute it. For example, a concurrent queue can have a serial target queue (effectively making the first queue serial), or multiple queues can have the same serial target queue (which means tasks in all the queues are mutually excluded). Thus we need to acquire-release semantics on the full “chain” of target queues. This patch changes the way we Acquire() and Release() when executing tasks in queues. Now we’ll walk the chain of target queues and synchronize on each queue that is serial (or when dealing with a barrier block). This should avoid false positives when using dispatch_set_target_queue(). Differential Revision: https://reviews.llvm.org/D25835 git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@285613 91177308-0d34-0410-b5e6-96231b3b80d8 --- test/tsan/Darwin/gcd-target-queue-norace.mm | 41 +++++++++++++++++++++++++++++ 1 file changed, 41 insertions(+) create mode 100644 test/tsan/Darwin/gcd-target-queue-norace.mm (limited to 'test/tsan') diff --git a/test/tsan/Darwin/gcd-target-queue-norace.mm b/test/tsan/Darwin/gcd-target-queue-norace.mm new file mode 100644 index 000000000..36cb1b929 --- /dev/null +++ b/test/tsan/Darwin/gcd-target-queue-norace.mm @@ -0,0 +1,41 @@ +// RUN: %clang_tsan %s -o %t -framework Foundation +// RUN: %env_tsan_opts=ignore_interceptors_accesses=1 %run %t 2>&1 | FileCheck %s + +#import + +long global; + +int main(int argc, const char *argv[]) { + dispatch_queue_t target_queue = dispatch_queue_create(NULL, DISPATCH_QUEUE_SERIAL); + dispatch_queue_t q1 = dispatch_queue_create(NULL, DISPATCH_QUEUE_CONCURRENT); + dispatch_queue_t q2 = dispatch_queue_create(NULL, DISPATCH_QUEUE_CONCURRENT); + dispatch_set_target_queue(q1, target_queue); + dispatch_set_target_queue(q2, target_queue); + + for (int i = 0; i < 100000; i++) { + dispatch_async(q1, ^{ + global++; + + if (global == 200000) { + dispatch_sync(dispatch_get_main_queue(), ^{ + CFRunLoopStop(CFRunLoopGetCurrent()); + }); + } + }); + dispatch_async(q2, ^{ + global++; + + if (global == 200000) { + dispatch_sync(dispatch_get_main_queue(), ^{ + CFRunLoopStop(CFRunLoopGetCurrent()); + }); + } + }); + } + + CFRunLoopRun(); + NSLog(@"Done."); + return 0; +} + +// CHECK-NOT: WARNING: ThreadSanitizer -- cgit v1.2.3