[compiler-rt] r265665 - [tsan] Add support for OS X OSAtomic* functions

Kuba Brecka via llvm-commits llvm-commits at lists.llvm.org
Thu Apr 7 05:05:09 PDT 2016


Author: kuba.brecka
Date: Thu Apr  7 07:05:09 2016
New Revision: 265665

URL: http://llvm.org/viewvc/llvm-project?rev=265665&view=rev
Log:
[tsan] Add support for OS X OSAtomic* functions

OS X provides atomic functions in libkern/OSAtomic.h. These provide atomic guarantees and they have alternatives which have barrier semantics. This patch adds proper TSan support for the functions from libkern/OSAtomic.h.

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


Added:
    compiler-rt/trunk/test/tsan/Darwin/osatomics-add.mm
    compiler-rt/trunk/test/tsan/Darwin/osatomics-list.mm
Modified:
    compiler-rt/trunk/lib/tsan/rtl/tsan_interceptors_mac.cc

Modified: compiler-rt/trunk/lib/tsan/rtl/tsan_interceptors_mac.cc
URL: http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/lib/tsan/rtl/tsan_interceptors_mac.cc?rev=265665&r1=265664&r2=265665&view=diff
==============================================================================
--- compiler-rt/trunk/lib/tsan/rtl/tsan_interceptors_mac.cc (original)
+++ compiler-rt/trunk/lib/tsan/rtl/tsan_interceptors_mac.cc Thu Apr  7 07:05:09 2016
@@ -17,12 +17,152 @@
 
 #include "interception/interception.h"
 #include "tsan_interceptors.h"
+#include "tsan_interface.h"
+#include "tsan_interface_ann.h"
 
 #include <libkern/OSAtomic.h>
 #include <xpc/xpc.h>
 
+typedef long long_t;  // NOLINT
+
 namespace __tsan {
 
+#define OSATOMIC_INTERCEPTOR(return_t, t, tsan_t, f, tsan_atomic_f, mo) \
+  TSAN_INTERCEPTOR(return_t, f, t x, volatile t *ptr) {                 \
+    SCOPED_TSAN_INTERCEPTOR(f, x, ptr);                                 \
+    return tsan_atomic_f((volatile tsan_t *)ptr, x, mo);                \
+  }
+
+#define OSATOMIC_INTERCEPTOR_PLUS_X(return_t, t, tsan_t, f, tsan_atomic_f, mo) \
+  TSAN_INTERCEPTOR(return_t, f, t x, volatile t *ptr) {                        \
+    SCOPED_TSAN_INTERCEPTOR(f, x, ptr);                                        \
+    return tsan_atomic_f((volatile tsan_t *)ptr, x, mo) + x;                   \
+  }
+
+#define OSATOMIC_INTERCEPTOR_PLUS_1(return_t, t, tsan_t, f, tsan_atomic_f, mo) \
+  TSAN_INTERCEPTOR(return_t, f, volatile t *ptr) {                             \
+    SCOPED_TSAN_INTERCEPTOR(f, ptr);                                           \
+    return tsan_atomic_f((volatile tsan_t *)ptr, 1, mo) + 1;                   \
+  }
+
+#define OSATOMIC_INTERCEPTOR_MINUS_1(return_t, t, tsan_t, f, tsan_atomic_f, \
+                                     mo)                                    \
+  TSAN_INTERCEPTOR(return_t, f, volatile t *ptr) {                          \
+    SCOPED_TSAN_INTERCEPTOR(f, ptr);                                        \
+    return tsan_atomic_f((volatile tsan_t *)ptr, 1, mo) - 1;                \
+  }
+
+#define OSATOMIC_INTERCEPTORS_ARITHMETIC(f, tsan_atomic_f, m)                  \
+  m(int32_t, int32_t, a32, f##32, __tsan_atomic32_##tsan_atomic_f, mo_relaxed) \
+  m(int32_t, int32_t, a32, f##32##Barrier, __tsan_atomic32_##tsan_atomic_f,    \
+    mo_acq_rel)                                                                \
+  m(int64_t, int64_t, a64, f##64, __tsan_atomic64_##tsan_atomic_f,             \
+    mo_relaxed)                                                                \
+  m(int64_t, int64_t, a64, f##64##Barrier, __tsan_atomic64_##tsan_atomic_f,    \
+    mo_acq_rel)
+
+#define OSATOMIC_INTERCEPTORS_BITWISE(f, tsan_atomic_f, m, m_orig)             \
+  m(int32_t, uint32_t, a32, f##32, __tsan_atomic32_##tsan_atomic_f,            \
+    mo_relaxed)                                                                \
+  m(int32_t, uint32_t, a32, f##32##Barrier, __tsan_atomic32_##tsan_atomic_f,   \
+    mo_acq_rel)                                                                \
+  m_orig(int32_t, uint32_t, a32, f##32##Orig, __tsan_atomic32_##tsan_atomic_f, \
+    mo_relaxed)                                                                \
+  m_orig(int32_t, uint32_t, a32, f##32##OrigBarrier,                           \
+    __tsan_atomic32_##tsan_atomic_f, mo_acq_rel)
+
+OSATOMIC_INTERCEPTORS_ARITHMETIC(OSAtomicAdd, fetch_add,
+                                 OSATOMIC_INTERCEPTOR_PLUS_X)
+OSATOMIC_INTERCEPTORS_ARITHMETIC(OSAtomicIncrement, fetch_add,
+                                 OSATOMIC_INTERCEPTOR_PLUS_1)
+OSATOMIC_INTERCEPTORS_ARITHMETIC(OSAtomicDecrement, fetch_sub,
+                                 OSATOMIC_INTERCEPTOR_MINUS_1)
+OSATOMIC_INTERCEPTORS_BITWISE(OSAtomicOr, fetch_or, OSATOMIC_INTERCEPTOR_PLUS_X,
+                              OSATOMIC_INTERCEPTOR)
+OSATOMIC_INTERCEPTORS_BITWISE(OSAtomicAnd, fetch_and,
+                              OSATOMIC_INTERCEPTOR_PLUS_X, OSATOMIC_INTERCEPTOR)
+OSATOMIC_INTERCEPTORS_BITWISE(OSAtomicXor, fetch_xor,
+                              OSATOMIC_INTERCEPTOR_PLUS_X, OSATOMIC_INTERCEPTOR)
+
+#define OSATOMIC_INTERCEPTORS_CAS(f, tsan_atomic_f, tsan_t, t)              \
+  TSAN_INTERCEPTOR(bool, f, t old_value, t new_value, t volatile *ptr) {    \
+    SCOPED_TSAN_INTERCEPTOR(f, old_value, new_value, ptr);                  \
+    return tsan_atomic_f##_compare_exchange_strong(                         \
+        (tsan_t *)ptr, (tsan_t *)&old_value, (tsan_t)new_value, mo_relaxed, \
+        mo_relaxed);                                                        \
+  }                                                                         \
+                                                                            \
+  TSAN_INTERCEPTOR(bool, f##Barrier, t old_value, t new_value,              \
+                   t volatile *ptr) {                                       \
+    SCOPED_TSAN_INTERCEPTOR(f##Barrier, old_value, new_value, ptr);         \
+    return tsan_atomic_f##_compare_exchange_strong(                         \
+        (tsan_t *)ptr, (tsan_t *)&old_value, (tsan_t)new_value, mo_acq_rel, \
+        mo_relaxed);                                                        \
+  }
+
+OSATOMIC_INTERCEPTORS_CAS(OSAtomicCompareAndSwapInt, __tsan_atomic32, a32, int)
+OSATOMIC_INTERCEPTORS_CAS(OSAtomicCompareAndSwapLong, __tsan_atomic64, a64,
+                          long_t)
+OSATOMIC_INTERCEPTORS_CAS(OSAtomicCompareAndSwapPtr, __tsan_atomic64, a64,
+                          void *)
+OSATOMIC_INTERCEPTORS_CAS(OSAtomicCompareAndSwap32, __tsan_atomic32, a32,
+                          int32_t)
+OSATOMIC_INTERCEPTORS_CAS(OSAtomicCompareAndSwap64, __tsan_atomic64, a64,
+                          int64_t)
+
+#define OSATOMIC_INTERCEPTOR_BITOP(f, op, m, mo)              \
+  TSAN_INTERCEPTOR(bool, f, uint32_t n, volatile void *ptr) { \
+    SCOPED_TSAN_INTERCEPTOR(f, n, ptr);                       \
+    char *byte_ptr = ((char *)ptr) + (n >> 3);                \
+    char bit_index = n & 7;                                   \
+    char mask = m;                                            \
+    char orig_byte = op((a8 *)byte_ptr, mask, mo);            \
+    return orig_byte & mask;                                  \
+  }
+
+#define OSATOMIC_INTERCEPTORS_BITOP(f, op, m)      \
+  OSATOMIC_INTERCEPTOR_BITOP(f, op, m, mo_relaxed) \
+  OSATOMIC_INTERCEPTOR_BITOP(f##Barrier, op, m, mo_acq_rel)
+
+OSATOMIC_INTERCEPTORS_BITOP(OSAtomicTestAndSet, __tsan_atomic8_fetch_or,
+                            0x80u >> bit_index)
+OSATOMIC_INTERCEPTORS_BITOP(OSAtomicTestAndClear, __tsan_atomic8_fetch_and,
+                            ~(0x80u >> bit_index))
+
+TSAN_INTERCEPTOR(void, OSAtomicEnqueue, OSQueueHead *list, void *item,
+                 size_t offset) {
+  SCOPED_TSAN_INTERCEPTOR(OSAtomicEnqueue, list, item, offset);
+  __tsan_release(item);
+  REAL(OSAtomicEnqueue)(list, item, offset);
+}
+
+TSAN_INTERCEPTOR(void *, OSAtomicDequeue, OSQueueHead *list, size_t offset) {
+  SCOPED_TSAN_INTERCEPTOR(OSAtomicDequeue, list, offset);
+  void *item = REAL(OSAtomicDequeue)(list, offset);
+  if (item) __tsan_acquire(item);
+  return item;
+}
+
+// OSAtomicFifoEnqueue and OSAtomicFifoDequeue are only on OS X.
+#if !SANITIZER_IOS
+
+TSAN_INTERCEPTOR(void, OSAtomicFifoEnqueue, OSFifoQueueHead *list, void *item,
+                 size_t offset) {
+  SCOPED_TSAN_INTERCEPTOR(OSAtomicFifoEnqueue, list, item, offset);
+  __tsan_release(item);
+  REAL(OSAtomicFifoEnqueue)(list, item, offset);
+}
+
+TSAN_INTERCEPTOR(void *, OSAtomicFifoDequeue, OSFifoQueueHead *list,
+                 size_t offset) {
+  SCOPED_TSAN_INTERCEPTOR(OSAtomicFifoDequeue, list, offset);
+  void *item = REAL(OSAtomicFifoDequeue)(list, offset);
+  if (item) __tsan_acquire(item);
+  return item;
+}
+
+#endif
+
 TSAN_INTERCEPTOR(void, OSSpinLockLock, volatile OSSpinLock *lock) {
   CHECK(!cur_thread()->is_dead);
   if (!cur_thread()->is_inited) {

Added: compiler-rt/trunk/test/tsan/Darwin/osatomics-add.mm
URL: http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/test/tsan/Darwin/osatomics-add.mm?rev=265665&view=auto
==============================================================================
--- compiler-rt/trunk/test/tsan/Darwin/osatomics-add.mm (added)
+++ compiler-rt/trunk/test/tsan/Darwin/osatomics-add.mm Thu Apr  7 07:05:09 2016
@@ -0,0 +1,48 @@
+// RUN: %clang_tsan %s -o %t -framework Foundation -std=c++11
+// RUN: %run %t 2>&1 | FileCheck %s
+
+#import <Foundation/Foundation.h>
+#import <libkern/OSAtomic.h>
+
+#include <thread>
+
+volatile int64_t retainCount = 0;
+
+long g = 0;
+
+void dealloc() {
+  g = 42;
+}
+
+void release() {
+  if (OSAtomicAdd64Barrier(-1, &retainCount) == 0) {
+    dealloc();
+  }
+}
+
+void retain() {
+  OSAtomicAdd64Barrier(1, &retainCount);
+}
+
+int main(int argc, const char * argv[]) {
+  fprintf(stderr, "start\n");
+  retain();
+  retain();
+  
+  std::thread t([]{
+    release();
+  });
+
+  g = 47;
+
+  release();
+  t.join();
+
+  fprintf(stderr, "end, g = %ld\n", g);
+
+  return 0;
+}
+
+// CHECK: start
+// CHECK: end, g = 42
+// CHECK-NOT: WARNING: ThreadSanitizer

Added: compiler-rt/trunk/test/tsan/Darwin/osatomics-list.mm
URL: http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/test/tsan/Darwin/osatomics-list.mm?rev=265665&view=auto
==============================================================================
--- compiler-rt/trunk/test/tsan/Darwin/osatomics-list.mm (added)
+++ compiler-rt/trunk/test/tsan/Darwin/osatomics-list.mm Thu Apr  7 07:05:09 2016
@@ -0,0 +1,43 @@
+// RUN: %clang_tsan %s -o %t -framework Foundation -std=c++11
+// RUN: %run %t 2>&1 | FileCheck %s
+
+#import <Foundation/Foundation.h>
+#import <libkern/OSAtomic.h>
+
+#include <thread>
+
+#include "../test.h"
+
+typedef struct {
+  void *next;
+  long data;
+} ListItem;
+
+OSQueueHead q;
+
+int main(int argc, const char *argv[]) {
+  barrier_init(&barrier, 2);
+
+  std::thread t1([] {
+    ListItem *li = new ListItem{nullptr, 42};
+    OSAtomicEnqueue(&q, li, 0);
+    barrier_wait(&barrier);
+  });
+
+  std::thread t2([] {
+    barrier_wait(&barrier);
+    ListItem *li = (ListItem *)OSAtomicDequeue(&q, 0);
+    fprintf(stderr, "data = %ld\n", li->data);
+  });
+
+  t1.join();
+  t2.join();
+
+  fprintf(stderr, "done\n");
+
+  return 0;
+}
+
+// CHECK: data = 42
+// CHECK: done
+// CHECK-NOT: WARNING: ThreadSanitizer




More information about the llvm-commits mailing list