OSDN Git Service

malloc_debug: reset TrackData mutex after fork
authorColin Cross <ccross@android.com>
Mon, 8 Feb 2016 06:51:15 +0000 (22:51 -0800)
committerColin Cross <ccross@android.com>
Sat, 13 Feb 2016 00:41:14 +0000 (16:41 -0800)
Add a pthread_atfork handler to malloc_debug to lock the TrackData mutex
during fork and reset it in the child.  Ensures that the TrackData is
consistent when forking from a multi-threaded process, and that the
mutex is in a defined state in the child.

Change-Id: I0dfed30045a28551217ceac227d33b2e18894932

libc/malloc_debug/DebugData.cpp
libc/malloc_debug/DebugData.h
libc/malloc_debug/TrackData.h
libc/malloc_debug/malloc_debug.cpp

index bf2a0f5..cf16c29 100644 (file)
@@ -82,3 +82,21 @@ bool DebugData::Initialize() {
   }
   return true;
 }
+
+void DebugData::PrepareFork() {
+  if (track != nullptr) {
+    track->PrepareFork();
+  }
+}
+
+void DebugData::PostForkParent() {
+  if (track != nullptr) {
+    track->PostForkParent();
+  }
+}
+
+void DebugData::PostForkChild() {
+  if (track != nullptr) {
+    track->PostForkChild();
+  }
+}
index 40978db..4600b33 100644 (file)
@@ -82,6 +82,10 @@ class DebugData {
   bool need_header() { return need_header_; }
   size_t extra_bytes() { return extra_bytes_; }
 
+  void PrepareFork();
+  void PostForkParent();
+  void PostForkChild();
+
   std::unique_ptr<BacktraceData> backtrace;
   std::unique_ptr<TrackData> track;
   std::unique_ptr<FrontGuardData> front_guard;
index 45e6892..dcf0ede 100644 (file)
@@ -58,6 +58,10 @@ class TrackData {
 
   void DisplayLeaks(DebugData& debug);
 
+  void PrepareFork() { pthread_mutex_lock(&mutex_); }
+  void PostForkParent() { pthread_mutex_unlock(&mutex_); }
+  void PostForkChild() { pthread_mutex_init(&mutex_, NULL); }
+
  private:
   pthread_mutex_t mutex_ = PTHREAD_MUTEX_INITIALIZER;
   std::unordered_set<Header*> headers_;
index 4f86579..8562900 100644 (file)
@@ -84,6 +84,28 @@ void* debug_valloc(size_t size);
 __END_DECLS
 // ------------------------------------------------------------------------
 
+static void InitAtfork() {
+  static pthread_once_t atfork_init = PTHREAD_ONCE_INIT;
+  pthread_once(&atfork_init, [](){
+    pthread_atfork(
+        [](){
+          if (g_debug != nullptr) {
+            g_debug->PrepareFork();
+          }
+        },
+        [](){
+          if (g_debug != nullptr) {
+            g_debug->PostForkParent();
+          }
+        },
+        [](){
+          if (g_debug != nullptr) {
+            g_debug->PostForkChild();
+          }
+        }
+    );
+  });
+}
 static void LogTagError(const Header* header, const void* pointer, const char* name) {
   ScopedDisableDebugCalls disable;
 
@@ -155,6 +177,9 @@ bool debug_initialize(const MallocDispatch* malloc_dispatch, int* malloc_zygote_
   if (malloc_zygote_child == nullptr) {
     return false;
   }
+
+  InitAtfork();
+
   g_malloc_zygote_child = malloc_zygote_child;
 
   g_dispatch = malloc_dispatch;