[compiler-rt] r254229 - [tsan] Add release+acquire semantics for serial dispatch queues

Kuba Brecka via llvm-commits llvm-commits at lists.llvm.org
Sat Nov 28 04:53:57 PST 2015


Author: kuba.brecka
Date: Sat Nov 28 06:53:57 2015
New Revision: 254229

URL: http://llvm.org/viewvc/llvm-project?rev=254229&view=rev
Log:
[tsan] Add release+acquire semantics for serial dispatch queues

Serial queues need extra happens-before between individual tasks executed in the same queue. This patch adds `Acquire(queue)` before the executed task and `Release(queue)` just after it (for serial queues only). Added a test case.

Differential Revision: http://reviews.llvm.org/D15011


Added:
    compiler-rt/trunk/test/tsan/Darwin/gcd-serial-queue-norace.mm
Modified:
    compiler-rt/trunk/lib/tsan/rtl/tsan_libdispatch_mac.cc

Modified: compiler-rt/trunk/lib/tsan/rtl/tsan_libdispatch_mac.cc
URL: http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/lib/tsan/rtl/tsan_libdispatch_mac.cc?rev=254229&r1=254228&r2=254229&view=diff
==============================================================================
--- compiler-rt/trunk/lib/tsan/rtl/tsan_libdispatch_mac.cc (original)
+++ compiler-rt/trunk/lib/tsan/rtl/tsan_libdispatch_mac.cc Sat Nov 28 06:53:57 2015
@@ -33,6 +33,35 @@ typedef struct {
   dispatch_function_t orig_work;
 } tsan_block_context_t;
 
+// The offsets of different fields of the dispatch_queue_t structure, exported
+// by libdispatch.dylib.
+extern "C" struct dispatch_queue_offsets_s {
+  const uint16_t dqo_version;
+  const uint16_t dqo_label;
+  const uint16_t dqo_label_size;
+  const uint16_t dqo_flags;
+  const uint16_t dqo_flags_size;
+  const uint16_t dqo_serialnum;
+  const uint16_t dqo_serialnum_size;
+  const uint16_t dqo_width;
+  const uint16_t dqo_width_size;
+  const uint16_t dqo_running;
+  const uint16_t dqo_running_size;
+  const uint16_t dqo_suspend_cnt;
+  const uint16_t dqo_suspend_cnt_size;
+  const uint16_t dqo_target_queue;
+  const uint16_t dqo_target_queue_size;
+  const uint16_t dqo_priority;
+  const uint16_t dqo_priority_size;
+} dispatch_queue_offsets;
+
+static bool IsQueueSerial(dispatch_queue_t q) {
+  CHECK_EQ(dispatch_queue_offsets.dqo_width_size, 2);
+  uptr width = *(uint16_t *)(((uptr)q) + dispatch_queue_offsets.dqo_width);
+  CHECK_NE(width, 0);
+  return width == 1;
+}
+
 static tsan_block_context_t *AllocContext(ThreadState *thr, uptr pc,
                                           dispatch_queue_t queue,
                                           void *orig_context,
@@ -49,7 +78,11 @@ static void dispatch_callback_wrap_acqui
   SCOPED_INTERCEPTOR_RAW(dispatch_async_f_callback_wrap);
   tsan_block_context_t *context = (tsan_block_context_t *)param;
   Acquire(thr, pc, (uptr)context);
+  // In serial queues, work items can be executed on different threads, we need
+  // to explicitly synchronize on the queue itself.
+  if (IsQueueSerial(context->queue)) Acquire(thr, pc, (uptr)context->queue);
   context->orig_work(context->orig_context);
+  if (IsQueueSerial(context->queue)) Release(thr, pc, (uptr)context->queue);
   user_free(thr, pc, context);
 }
 

Added: compiler-rt/trunk/test/tsan/Darwin/gcd-serial-queue-norace.mm
URL: http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/test/tsan/Darwin/gcd-serial-queue-norace.mm?rev=254229&view=auto
==============================================================================
--- compiler-rt/trunk/test/tsan/Darwin/gcd-serial-queue-norace.mm (added)
+++ compiler-rt/trunk/test/tsan/Darwin/gcd-serial-queue-norace.mm Sat Nov 28 06:53:57 2015
@@ -0,0 +1,40 @@
+// RUN: %clang_tsan %s -o %t -framework Foundation
+// RUN: %run %t 2>&1
+
+#import <Foundation/Foundation.h>
+
+#import "../test.h"
+
+long global;
+
+int main() {
+  NSLog(@"Hello world.");
+  NSLog(@"addr=%p\n", &global);
+
+  dispatch_queue_t q1 = dispatch_queue_create("my.queue1", DISPATCH_QUEUE_CONCURRENT);
+  dispatch_queue_t q2 = dispatch_queue_create("my.queue2", DISPATCH_QUEUE_SERIAL);
+
+  global = 42;
+  for (int i = 0; i < 10; i++) {
+    dispatch_async(q1, ^{
+      for (int i = 0; i < 100; i++) {
+        dispatch_sync(q2, ^{
+          global++;
+        });
+      }
+    });
+  }
+
+  dispatch_barrier_async(q1, ^{
+    dispatch_sync(dispatch_get_main_queue(), ^{
+      CFRunLoopStop(CFRunLoopGetCurrent());
+    });
+  });
+
+  CFRunLoopRun();
+  NSLog(@"Done.");
+}
+
+// CHECK: Hello world.
+// CHECK: Done.
+// CHECK-NOT: WARNING: ThreadSanitizer




More information about the llvm-commits mailing list