[compiler-rt] 2f46983 - [Sanitizer][Darwin] Factor out code for GCD worker registration

Julian Lettner via llvm-commits llvm-commits at lists.llvm.org
Fri Jul 22 13:29:34 PDT 2022


Author: Julian Lettner
Date: 2022-07-22T13:29:28-07:00
New Revision: 2f469839817ac673803eaa6a22e51c56e82c7c12

URL: https://github.com/llvm/llvm-project/commit/2f469839817ac673803eaa6a22e51c56e82c7c12
DIFF: https://github.com/llvm/llvm-project/commit/2f469839817ac673803eaa6a22e51c56e82c7c12.diff

LOG: [Sanitizer][Darwin] Factor out code for GCD worker registration

This is a NFC change to factor out GCD worker thread registration via
the pthread introspection hook.

In a follow-up change we also want to register GCD workers for ASan to
make sure threads are registered before we attempt to print reports on
them.

rdar://93276353

Differential Revision: https://reviews.llvm.org/D126351

Added: 
    

Modified: 
    compiler-rt/lib/sanitizer_common/sanitizer_mac.cpp
    compiler-rt/lib/sanitizer_common/sanitizer_mac.h
    compiler-rt/lib/tsan/rtl/tsan_platform_mac.cpp

Removed: 
    


################################################################################
diff  --git a/compiler-rt/lib/sanitizer_common/sanitizer_mac.cpp b/compiler-rt/lib/sanitizer_common/sanitizer_mac.cpp
index 7ce6eff832e54..1ae69e14b2371 100644
--- a/compiler-rt/lib/sanitizer_common/sanitizer_mac.cpp
+++ b/compiler-rt/lib/sanitizer_common/sanitizer_mac.cpp
@@ -73,6 +73,7 @@ extern "C" {
 #include <malloc/malloc.h>
 #include <os/log.h>
 #include <pthread.h>
+#include <pthread/introspection.h>
 #include <sched.h>
 #include <signal.h>
 #include <spawn.h>
@@ -1395,6 +1396,61 @@ u32 GetNumberOfCPUs() {
 
 void InitializePlatformCommonFlags(CommonFlags *cf) {}
 
+// Pthread introspection hook
+//
+// * GCD worker threads are created without a call to pthread_create(), but we
+//   still need to register these threads (with ThreadCreate/Start()).
+// * We use the "pthread introspection hook" below to observe the creation of
+//   such threads.
+// * GCD worker threads don't have parent threads and the CREATE event is
+//   delivered in the context of the thread itself.  CREATE events for regular
+//   threads, are delivered on the parent.  We use this to tell apart which
+//   threads are GCD workers with `thread == pthread_self()`.
+//
+static pthread_introspection_hook_t prev_pthread_introspection_hook;
+static ThreadEventCallbacks thread_event_callbacks;
+
+static void sanitizer_pthread_introspection_hook(unsigned int event,
+                                                 pthread_t thread, void *addr,
+                                                 size_t size) {
+  // create -> start -> terminate -> destroy
+  // * create/destroy are usually (not guaranteed) delivered on the parent and
+  //   track resource allocation/reclamation
+  // * start/terminate are guaranteed to be delivered in the context of the
+  //   thread and give hooks into "just after (before) thread starts (stops)
+  //   executing"
+  DCHECK(event >= PTHREAD_INTROSPECTION_THREAD_CREATE &&
+         event <= PTHREAD_INTROSPECTION_THREAD_DESTROY);
+
+  if (event == PTHREAD_INTROSPECTION_THREAD_CREATE) {
+    bool gcd_worker = (thread == pthread_self());
+    if (thread_event_callbacks.create)
+      thread_event_callbacks.create((uptr)thread, gcd_worker);
+  } else if (event == PTHREAD_INTROSPECTION_THREAD_START) {
+    CHECK_EQ(thread, pthread_self());
+    if (thread_event_callbacks.start)
+      thread_event_callbacks.start((uptr)thread);
+  }
+
+  if (prev_pthread_introspection_hook)
+    prev_pthread_introspection_hook(event, thread, addr, size);
+
+  if (event == PTHREAD_INTROSPECTION_THREAD_TERMINATE) {
+    CHECK_EQ(thread, pthread_self());
+    if (thread_event_callbacks.terminate)
+      thread_event_callbacks.terminate((uptr)thread);
+  } else if (event == PTHREAD_INTROSPECTION_THREAD_DESTROY) {
+    if (thread_event_callbacks.destroy)
+      thread_event_callbacks.destroy((uptr)thread);
+  }
+}
+
+void InstallPthreadIntrospectionHook(const ThreadEventCallbacks &callbacks) {
+  thread_event_callbacks = callbacks;
+  prev_pthread_introspection_hook =
+      pthread_introspection_hook_install(&sanitizer_pthread_introspection_hook);
+}
+
 }  // namespace __sanitizer
 
 #endif  // SANITIZER_APPLE

diff  --git a/compiler-rt/lib/sanitizer_common/sanitizer_mac.h b/compiler-rt/lib/sanitizer_common/sanitizer_mac.h
index a8b274e8c82c0..f0a97d098eea0 100644
--- a/compiler-rt/lib/sanitizer_common/sanitizer_mac.h
+++ b/compiler-rt/lib/sanitizer_common/sanitizer_mac.h
@@ -62,6 +62,17 @@ char **GetEnviron();
 
 void RestrictMemoryToMaxAddress(uptr max_address);
 
+using ThreadEventCallback = void (*)(uptr thread);
+using ThreadCreateEventCallback = void (*)(uptr thread, bool gcd_worker);
+struct ThreadEventCallbacks {
+  ThreadCreateEventCallback create;
+  ThreadEventCallback start;
+  ThreadEventCallback terminate;
+  ThreadEventCallback destroy;
+};
+
+void InstallPthreadIntrospectionHook(const ThreadEventCallbacks &callbacks);
+
 }  // namespace __sanitizer
 
 #endif  // SANITIZER_APPLE

diff  --git a/compiler-rt/lib/tsan/rtl/tsan_platform_mac.cpp b/compiler-rt/lib/tsan/rtl/tsan_platform_mac.cpp
index 68ce5f83bdbd2..1aac0fb27520c 100644
--- a/compiler-rt/lib/tsan/rtl/tsan_platform_mac.cpp
+++ b/compiler-rt/lib/tsan/rtl/tsan_platform_mac.cpp
@@ -200,44 +200,26 @@ void WriteMemoryProfile(char *buf, uptr buf_size, u64 uptime_ns) {
 #  if !SANITIZER_GO
 void InitializeShadowMemoryPlatform() { }
 
-// 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_TERMINATE = 3;
-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 *thr = cur_thread();
-      Processor *proc = ProcCreate();
-      ProcWire(proc, thr);
-      ThreadState *parent_thread_state = nullptr;  // No parent.
-      Tid tid = ThreadCreate(parent_thread_state, 0, (uptr)thread, true);
-      CHECK_NE(tid, kMainTid);
-      ThreadStart(thr, tid, GetTid(), ThreadType::Worker);
-    }
-  } else if (event == PTHREAD_INTROSPECTION_THREAD_TERMINATE) {
-    CHECK_EQ(thread, pthread_self());
+// Register GCD worker threads, which are created without an observable call to
+// pthread_create().
+static void ThreadCreateCallback(uptr thread, bool gcd_worker) {
+  if (gcd_worker) {
     ThreadState *thr = cur_thread();
-    if (thr->tctx) {
-      DestroyThreadState();
-    }
+    Processor *proc = ProcCreate();
+    ProcWire(proc, thr);
+    ThreadState *parent_thread_state = nullptr;  // No parent.
+    Tid tid = ThreadCreate(parent_thread_state, 0, (uptr)thread, true);
+    CHECK_NE(tid, kMainTid);
+    ThreadStart(thr, tid, GetTid(), ThreadType::Worker);
   }
+}
 
-  if (prev_pthread_introspection_hook != nullptr)
-    prev_pthread_introspection_hook(event, thread, addr, size);
+// Destroy thread state for *all* threads.
+static void ThreadTerminateCallback(uptr thread) {
+  ThreadState *thr = cur_thread();
+  if (thr->tctx) {
+    DestroyThreadState();
+  }
 }
 #endif
 
@@ -261,8 +243,11 @@ void InitializePlatform() {
 
   InitializeThreadStateStorage();
 
-  prev_pthread_introspection_hook =
-      pthread_introspection_hook_install(&my_pthread_introspection_hook);
+  ThreadEventCallbacks callbacks = {
+      .create = ThreadCreateCallback,
+      .terminate = ThreadTerminateCallback,
+  };
+  InstallPthreadIntrospectionHook(callbacks);
 #endif
 
   if (GetMacosAlignedVersion() >= MacosVersion(10, 14)) {


        


More information about the llvm-commits mailing list