Bug 1221160 - fix AutoTraceLogLock deadlock on Windows; r=froydnj
authorVladimir Vukicevic <vladimir@pobox.com>
Tue, 03 Nov 2015 15:13:09 -0500
changeset 290756 32d19555348e3d8da52cc5b73a9232ea1de37769
parent 290755 9a135bc3752971f8a76c1cb6fa4ffefbb613d93c
child 290757 3eca091288e47d48edf843f9e73799d77e60362e
push id19656
push usergwagner@mozilla.com
push dateMon, 04 Apr 2016 13:43:23 +0000
treeherderb2g-inbound@e99061fde28a [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersfroydnj
bugs1221160
milestone48.0a1
Bug 1221160 - fix AutoTraceLogLock deadlock on Windows; r=froydnj From e3a1e57c0c8be8214a12e31c6e4950a676efd9bc Mon Sep 17 00:00:00 2001 MozReview-Commit-ID: JrPiE7eixpy
xpcom/base/nsTraceRefcnt.cpp
--- a/xpcom/base/nsTraceRefcnt.cpp
+++ b/xpcom/base/nsTraceRefcnt.cpp
@@ -56,27 +56,34 @@
 #include "prmem.h"
 
 #include "prthread.h"
 
 // We use a spin lock instead of a regular mutex because this lock is usually
 // only held for a very short time, and gets grabbed at a very high frequency
 // (~100000 times per second). On Mac, the overhead of using a regular lock
 // is very high, see bug 1137963.
-static mozilla::Atomic<bool, mozilla::ReleaseAcquire> gTraceLogLocked;
+static mozilla::Atomic<uintptr_t, mozilla::ReleaseAcquire> gTraceLogLocked;
 
 struct MOZ_STACK_CLASS AutoTraceLogLock final
 {
+  bool doRelease;
   AutoTraceLogLock()
+    : doRelease(true)
   {
-    while (!gTraceLogLocked.compareExchange(false, true)) {
-      PR_Sleep(PR_INTERVAL_NO_WAIT); /* yield */
+    uintptr_t currentThread = reinterpret_cast<uintptr_t>(PR_GetCurrentThread());
+    if (gTraceLogLocked == currentThread) {
+      doRelease = false;
+    } else {
+      while (!gTraceLogLocked.compareExchange(0, currentThread)) {
+        PR_Sleep(PR_INTERVAL_NO_WAIT); /* yield */
+      }
     }
   }
-  ~AutoTraceLogLock() { gTraceLogLocked = false; }
+  ~AutoTraceLogLock() { if (doRelease) gTraceLogLocked = 0; }
 };
 
 static PLHashTable* gBloatView;
 static PLHashTable* gTypesToLog;
 static PLHashTable* gObjectsToLog;
 static PLHashTable* gSerialNumbers;
 static intptr_t gNextSerialNumber;
 
@@ -1114,24 +1121,24 @@ NS_LogAddRef(void* aPtr, nsrefcnt aRefcn
       if (count) {
         (*count)++;
       }
 
     }
 
     bool loggingThisObject = (!gObjectsToLog || LogThisObj(serialno));
     if (aRefcnt == 1 && gAllocLog && loggingThisType && loggingThisObject) {
-      fprintf(gAllocLog, "\n<%s> %p %" PRIdPTR " Create\n", aClass, aPtr, serialno);
+      fprintf(gAllocLog, "\n<%s> %p %" PRIdPTR " Create [thread %p]\n", aClass, aPtr, serialno, PR_GetCurrentThread());
       nsTraceRefcnt::WalkTheStackCached(gAllocLog);
     }
 
     if (gRefcntsLog && loggingThisType && loggingThisObject) {
       // Can't use MOZ_LOG(), b/c it truncates the line
-      fprintf(gRefcntsLog, "\n<%s> %p %" PRIuPTR " AddRef %" PRIuPTR "\n",
-              aClass, aPtr, serialno, aRefcnt);
+      fprintf(gRefcntsLog, "\n<%s> %p %" PRIuPTR " AddRef %" PRIuPTR " [thread %p]\n",
+              aClass, aPtr, serialno, aRefcnt, PR_GetCurrentThread());
       nsTraceRefcnt::WalkTheStackCached(gRefcntsLog);
       fflush(gRefcntsLog);
     }
   }
 #endif
 }
 
 EXPORT_XPCOM_API(void)
@@ -1168,27 +1175,27 @@ NS_LogRelease(void* aPtr, nsrefcnt aRefc
       }
 
     }
 
     bool loggingThisObject = (!gObjectsToLog || LogThisObj(serialno));
     if (gRefcntsLog && loggingThisType && loggingThisObject) {
       // Can't use MOZ_LOG(), b/c it truncates the line
       fprintf(gRefcntsLog,
-              "\n<%s> %p %" PRIuPTR " Release %" PRIuPTR "\n",
-              aClass, aPtr, serialno, aRefcnt);
+              "\n<%s> %p %" PRIuPTR " Release %" PRIuPTR " [thread %p]\n",
+              aClass, aPtr, serialno, aRefcnt, PR_GetCurrentThread());
       nsTraceRefcnt::WalkTheStackCached(gRefcntsLog);
       fflush(gRefcntsLog);
     }
 
     // Here's the case where MOZ_COUNT_DTOR was not used,
     // yet we still want to see deletion information:
 
     if (aRefcnt == 0 && gAllocLog && loggingThisType && loggingThisObject) {
-      fprintf(gAllocLog, "\n<%s> %p %" PRIdPTR " Destroy\n", aClass, aPtr, serialno);
+      fprintf(gAllocLog, "\n<%s> %p %" PRIdPTR " Destroy [thread %p]\n", aClass, aPtr, serialno, PR_GetCurrentThread());
       nsTraceRefcnt::WalkTheStackCached(gAllocLog);
     }
 
     if (aRefcnt == 0 && gSerialNumbers && loggingThisType) {
       RecycleSerialNumberPtr(aPtr);
     }
   }
 #endif