[compiler-rt] r252049 - [tsan] Handle libdispatch worker threads on OS X

Kuba Brecka via llvm-commits llvm-commits at lists.llvm.org
Wed Nov 4 07:09:15 PST 2015


Author: kuba.brecka
Date: Wed Nov  4 09:09:14 2015
New Revision: 252049

URL: http://llvm.org/viewvc/llvm-project?rev=252049&view=rev
Log:
[tsan] Handle libdispatch worker threads on OS X

On OS X, GCD worker threads are created without a call to pthread_create. We need to properly register these threads with ThreadCreate and ThreadStart. This patch uses a libpthread API (`pthread_introspection_hook_install`) to get notifications about new threads and about threads that are about to be destroyed.

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


Modified:
    compiler-rt/trunk/lib/tsan/rtl/tsan_clock.cc
    compiler-rt/trunk/lib/tsan/rtl/tsan_defs.h
    compiler-rt/trunk/lib/tsan/rtl/tsan_interceptors.cc
    compiler-rt/trunk/lib/tsan/rtl/tsan_platform.h
    compiler-rt/trunk/lib/tsan/rtl/tsan_platform_mac.cc
    compiler-rt/trunk/lib/tsan/rtl/tsan_rtl_thread.cc

Modified: compiler-rt/trunk/lib/tsan/rtl/tsan_clock.cc
URL: http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/lib/tsan/rtl/tsan_clock.cc?rev=252049&r1=252048&r2=252049&view=diff
==============================================================================
--- compiler-rt/trunk/lib/tsan/rtl/tsan_clock.cc (original)
+++ compiler-rt/trunk/lib/tsan/rtl/tsan_clock.cc Wed Nov  4 09:09:14 2015
@@ -90,8 +90,6 @@
 
 namespace __tsan {
 
-const unsigned kInvalidTid = (unsigned)-1;
-
 ThreadClock::ThreadClock(unsigned tid, unsigned reused)
     : tid_(tid)
     , reused_(reused + 1) {  // 0 has special meaning

Modified: compiler-rt/trunk/lib/tsan/rtl/tsan_defs.h
URL: http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/lib/tsan/rtl/tsan_defs.h?rev=252049&r1=252048&r2=252049&view=diff
==============================================================================
--- compiler-rt/trunk/lib/tsan/rtl/tsan_defs.h (original)
+++ compiler-rt/trunk/lib/tsan/rtl/tsan_defs.h Wed Nov  4 09:09:14 2015
@@ -83,6 +83,8 @@ const bool kCollectHistory = false;
 const bool kCollectHistory = true;
 #endif
 
+const unsigned kInvalidTid = (unsigned)-1;
+
 // The following "build consistency" machinery ensures that all source files
 // are built in the same configuration. Inconsistent builds lead to
 // hard to debug crashes.

Modified: compiler-rt/trunk/lib/tsan/rtl/tsan_interceptors.cc
URL: http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/lib/tsan/rtl/tsan_interceptors.cc?rev=252049&r1=252048&r2=252049&view=diff
==============================================================================
--- compiler-rt/trunk/lib/tsan/rtl/tsan_interceptors.cc (original)
+++ compiler-rt/trunk/lib/tsan/rtl/tsan_interceptors.cc Wed Nov  4 09:09:14 2015
@@ -812,6 +812,18 @@ extern "C" void INTERFACE_ATTRIBUTE __cx
   atomic_store(g, 0, memory_order_relaxed);
 }
 
+namespace __tsan {
+void DestroyThreadState() {
+  ThreadState *thr = cur_thread();
+  ThreadFinish(thr);
+  ThreadSignalContext *sctx = thr->signal_ctx;
+  if (sctx) {
+    thr->signal_ctx = 0;
+    UnmapOrDie(sctx, sizeof(*sctx));
+  }
+}
+}  // namespace __tsan
+
 static void thread_finalize(void *v) {
   uptr iter = (uptr)v;
   if (iter > 1) {
@@ -821,15 +833,7 @@ static void thread_finalize(void *v) {
     }
     return;
   }
-  {
-    ThreadState *thr = cur_thread();
-    ThreadFinish(thr);
-    ThreadSignalContext *sctx = thr->signal_ctx;
-    if (sctx) {
-      thr->signal_ctx = 0;
-      UnmapOrDie(sctx, sizeof(*sctx));
-    }
-  }
+  DestroyThreadState();
 }
 
 

Modified: compiler-rt/trunk/lib/tsan/rtl/tsan_platform.h
URL: http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/lib/tsan/rtl/tsan_platform.h?rev=252049&r1=252048&r2=252049&view=diff
==============================================================================
--- compiler-rt/trunk/lib/tsan/rtl/tsan_platform.h (original)
+++ compiler-rt/trunk/lib/tsan/rtl/tsan_platform.h Wed Nov  4 09:09:14 2015
@@ -355,6 +355,8 @@ int call_pthread_cancel_with_cleanup(int
     void *abstime), void *c, void *m, void *abstime,
     void(*cleanup)(void *arg), void *arg);
 
+void DestroyThreadState();
+
 }  // namespace __tsan
 
 #endif  // TSAN_PLATFORM_H

Modified: compiler-rt/trunk/lib/tsan/rtl/tsan_platform_mac.cc
URL: http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/lib/tsan/rtl/tsan_platform_mac.cc?rev=252049&r1=252048&r2=252049&view=diff
==============================================================================
--- compiler-rt/trunk/lib/tsan/rtl/tsan_platform_mac.cc (original)
+++ compiler-rt/trunk/lib/tsan/rtl/tsan_platform_mac.cc Wed Nov  4 09:09:14 2015
@@ -54,11 +54,51 @@ void WriteMemoryProfile(char *buf, uptr
 void InitializeShadowMemoryPlatform() { }
 #endif
 
+// On OS X, GCD worker threads are created without a call to pthread_create. We
+// need to properly register these threads with ThreadCreate and ThreadStart.
+// These threads don't have a parent thread, as they are created "spuriously".
+// We're using a libpthread API that notifies us about a newly created thread.
+// The `thread == pthread_self()` check indicates this is actually a worker
+// thread. If it's just a regular thread, this hook is called on the parent
+// thread.
+typedef void (*pthread_introspection_hook_t)(unsigned int event,
+                                             pthread_t thread, void *addr,
+                                             size_t size);
+extern "C" pthread_introspection_hook_t pthread_introspection_hook_install(
+    pthread_introspection_hook_t hook);
+static const uptr PTHREAD_INTROSPECTION_THREAD_CREATE = 1;
+static const uptr PTHREAD_INTROSPECTION_THREAD_DESTROY = 4;
+static pthread_introspection_hook_t prev_pthread_introspection_hook;
+static void my_pthread_introspection_hook(unsigned int event, pthread_t thread,
+                                          void *addr, size_t size) {
+  if (event == PTHREAD_INTROSPECTION_THREAD_CREATE) {
+    if (thread == pthread_self()) {
+      // The current thread is a newly created GCD worker thread.
+      ThreadState *parent_thread_state = nullptr;  // No parent.
+      int tid = ThreadCreate(parent_thread_state, 0, (uptr)thread, true);
+      CHECK_NE(tid, 0);
+      ThreadState *thr = cur_thread();
+      ThreadStart(thr, tid, GetTid());
+    }
+  } else if (event == PTHREAD_INTROSPECTION_THREAD_DESTROY) {
+    ThreadState *thr = cur_thread();
+    if (thr->tctx->parent_tid == kInvalidTid) {
+      DestroyThreadState();
+    }
+  }
+
+  if (prev_pthread_introspection_hook != nullptr)
+    prev_pthread_introspection_hook(event, thread, addr, size);
+}
+
 void InitializePlatform() {
   DisableCoreDumperIfNecessary();
 #ifndef SANITIZER_GO
   CheckAndProtect();
 #endif
+
+  prev_pthread_introspection_hook =
+      pthread_introspection_hook_install(&my_pthread_introspection_hook);
 }
 
 #ifndef SANITIZER_GO

Modified: compiler-rt/trunk/lib/tsan/rtl/tsan_rtl_thread.cc
URL: http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/lib/tsan/rtl/tsan_rtl_thread.cc?rev=252049&r1=252048&r2=252049&view=diff
==============================================================================
--- compiler-rt/trunk/lib/tsan/rtl/tsan_rtl_thread.cc (original)
+++ compiler-rt/trunk/lib/tsan/rtl/tsan_rtl_thread.cc Wed Nov  4 09:09:14 2015
@@ -55,6 +55,8 @@ void ThreadContext::OnCreated(void *arg)
   if (tid == 0)
     return;
   OnCreatedArgs *args = static_cast<OnCreatedArgs *>(arg);
+  if (!args->thr)  // GCD workers don't have a parent thread.
+    return;
   args->thr->fast_state.IncrementEpoch();
   // Can't increment epoch w/o writing to the trace as well.
   TraceAddEvent(args->thr, args->thr->fast_state, EventTypeMop, 0);
@@ -231,8 +233,10 @@ int ThreadCount(ThreadState *thr) {
 int ThreadCreate(ThreadState *thr, uptr pc, uptr uid, bool detached) {
   StatInc(thr, StatThreadCreate);
   OnCreatedArgs args = { thr, pc };
-  int tid = ctx->thread_registry->CreateThread(uid, detached, thr->tid, &args);
-  DPrintf("#%d: ThreadCreate tid=%d uid=%zu\n", thr->tid, tid, uid);
+  u32 parent_tid = thr ? thr->tid : kInvalidTid;  // No parent for GCD workers.
+  int tid =
+      ctx->thread_registry->CreateThread(uid, detached, parent_tid, &args);
+  DPrintf("#%d: ThreadCreate tid=%d uid=%zu\n", parent_tid, tid, uid);
   StatSet(thr, StatThreadMaxAlive, ctx->thread_registry->GetMaxAliveThreads());
   return tid;
 }




More information about the llvm-commits mailing list