tsan: include internal allocator into deadlock detection

Now that we lock the internal allocator around fork,
it's possible it will create additional deadlocks.
Add a fake mutex that substitutes the internal allocator
for the purposes of deadlock detection.

Depends on D114531.

Reviewed By: melver

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

GitOrigin-RevId: 6f85d68e6ab29e544b301d7ac84de2819b8d4b7a
diff --git a/lib/tsan/rtl/tsan_defs.h b/lib/tsan/rtl/tsan_defs.h
index fe0c1da..4712c2b 100644
--- a/lib/tsan/rtl/tsan_defs.h
+++ b/lib/tsan/rtl/tsan_defs.h
@@ -228,6 +228,7 @@
   MutexTypeFired,
   MutexTypeRacy,
   MutexTypeGlobalProc,
+  MutexTypeInternalAlloc,
 };
 
 }  // namespace __tsan
diff --git a/lib/tsan/rtl/tsan_mman.cpp b/lib/tsan/rtl/tsan_mman.cpp
index 8f87fff..a31bebc 100644
--- a/lib/tsan/rtl/tsan_mman.cpp
+++ b/lib/tsan/rtl/tsan_mman.cpp
@@ -69,8 +69,17 @@
 struct GlobalProc {
   Mutex mtx;
   Processor *proc;
+  // This mutex represents the internal allocator combined for
+  // the purposes of deadlock detection. The internal allocator
+  // uses multiple mutexes, moreover they are locked only occasionally
+  // and they are spin mutexes which don't support deadlock detection.
+  // So we use this fake mutex to serve as a substitute for these mutexes.
+  CheckedMutex internal_alloc_mtx;
 
-  GlobalProc() : mtx(MutexTypeGlobalProc), proc(ProcCreate()) {}
+  GlobalProc()
+      : mtx(MutexTypeGlobalProc),
+        proc(ProcCreate()),
+        internal_alloc_mtx(MutexTypeInternalAlloc) {}
 };
 
 static char global_proc_placeholder[sizeof(GlobalProc)] ALIGNED(64);
@@ -78,6 +87,11 @@
   return reinterpret_cast<GlobalProc*>(&global_proc_placeholder);
 }
 
+static void InternalAllocAccess() {
+  global_proc()->internal_alloc_mtx.Lock();
+  global_proc()->internal_alloc_mtx.Unlock();
+}
+
 ScopedGlobalProcessor::ScopedGlobalProcessor() {
   GlobalProc *gp = global_proc();
   ThreadState *thr = cur_thread();
@@ -112,11 +126,13 @@
 
 void AllocatorLock() NO_THREAD_SAFETY_ANALYSIS {
   global_proc()->mtx.Lock();
+  global_proc()->internal_alloc_mtx.Lock();
   InternalAllocatorLock();
 }
 
 void AllocatorUnlock() NO_THREAD_SAFETY_ANALYSIS {
   InternalAllocatorUnlock();
+  global_proc()->internal_alloc_mtx.Unlock();
   global_proc()->mtx.Unlock();
 }
 
@@ -352,6 +368,7 @@
     thr->nomalloc = 0;  // CHECK calls internal_malloc().
     CHECK(0);
   }
+  InternalAllocAccess();
   return InternalAlloc(sz, &thr->proc()->internal_alloc_cache);
 }
 
@@ -361,6 +378,7 @@
     thr->nomalloc = 0;  // CHECK calls internal_malloc().
     CHECK(0);
   }
+  InternalAllocAccess();
   InternalFree(p, &thr->proc()->internal_alloc_cache);
 }
 
diff --git a/lib/tsan/rtl/tsan_rtl.cpp b/lib/tsan/rtl/tsan_rtl.cpp
index 4e45042..e93e50c 100644
--- a/lib/tsan/rtl/tsan_rtl.cpp
+++ b/lib/tsan/rtl/tsan_rtl.cpp
@@ -757,14 +757,17 @@
 MutexMeta mutex_meta[] = {
     {MutexInvalid, "Invalid", {}},
     {MutexThreadRegistry, "ThreadRegistry", {}},
-    {MutexTypeTrace, "Trace", {MutexLeaf}},
-    {MutexTypeReport, "Report", {MutexTypeSyncVar, MutexTypeGlobalProc}},
-    {MutexTypeSyncVar, "SyncVar", {}},
+    {MutexTypeTrace, "Trace", {}},
+    {MutexTypeReport,
+     "Report",
+     {MutexTypeSyncVar, MutexTypeGlobalProc, MutexTypeTrace}},
+    {MutexTypeSyncVar, "SyncVar", {MutexTypeTrace}},
     {MutexTypeAnnotations, "Annotations", {}},
     {MutexTypeAtExit, "AtExit", {MutexTypeSyncVar}},
     {MutexTypeFired, "Fired", {MutexLeaf}},
     {MutexTypeRacy, "Racy", {MutexLeaf}},
     {MutexTypeGlobalProc, "GlobalProc", {}},
+    {MutexTypeInternalAlloc, "InternalAlloc", {MutexLeaf}},
     {},
 };