Title: [179648] trunk/Source/_javascript_Core
Revision
179648
Author
[email protected]
Date
2015-02-04 16:32:47 -0800 (Wed, 04 Feb 2015)

Log Message

r179576 introduce a deadlock potential during GC thread suspension.
<https://webkit.org/b/141268>

Reviewed by Michael Saboff.

http://trac.webkit.org/r179576 introduced a potential for deadlocking.
In the GC thread suspension loop, we currently delete
MachineThreads::Thread that we detect to be invalid.  This is unsafe
because we may have already suspended some threads, and one of those
suspended threads may still be holding the C heap lock which we need
for deleting the invalid thread.

The fix is to put the invalid threads in a separate toBeDeleted list,
and delete them only after GC has resumed all threads.

* heap/MachineStackMarker.cpp:
(JSC::MachineThreads::removeCurrentThread):
- Undo refactoring removeThreadWithLockAlreadyAcquired() out of
  removeCurrentThread() since it is no longer needed.

(JSC::MachineThreads::tryCopyOtherThreadStacks):
- Put invalid Threads on a threadsToBeDeleted list, and delete those
  Threads only after all threads have been resumed.

(JSC::MachineThreads::removeThreadWithLockAlreadyAcquired): Deleted.
* heap/MachineStackMarker.h:

Modified Paths

Diff

Modified: trunk/Source/_javascript_Core/ChangeLog (179647 => 179648)


--- trunk/Source/_javascript_Core/ChangeLog	2015-02-05 00:32:27 UTC (rev 179647)
+++ trunk/Source/_javascript_Core/ChangeLog	2015-02-05 00:32:47 UTC (rev 179648)
@@ -1,3 +1,32 @@
+2015-02-04  Mark Lam  <[email protected]>
+
+        r179576 introduce a deadlock potential during GC thread suspension.
+        <https://webkit.org/b/141268>
+
+        Reviewed by Michael Saboff.
+
+        http://trac.webkit.org/r179576 introduced a potential for deadlocking.
+        In the GC thread suspension loop, we currently delete
+        MachineThreads::Thread that we detect to be invalid.  This is unsafe
+        because we may have already suspended some threads, and one of those
+        suspended threads may still be holding the C heap lock which we need
+        for deleting the invalid thread.
+
+        The fix is to put the invalid threads in a separate toBeDeleted list,
+        and delete them only after GC has resumed all threads.
+
+        * heap/MachineStackMarker.cpp:
+        (JSC::MachineThreads::removeCurrentThread):
+        - Undo refactoring removeThreadWithLockAlreadyAcquired() out of
+          removeCurrentThread() since it is no longer needed.
+
+        (JSC::MachineThreads::tryCopyOtherThreadStacks):
+        - Put invalid Threads on a threadsToBeDeleted list, and delete those
+          Threads only after all threads have been resumed.
+
+        (JSC::MachineThreads::removeThreadWithLockAlreadyAcquired): Deleted.
+        * heap/MachineStackMarker.h:
+
 2015-02-04  Joseph Pecoraro  <[email protected]>
 
         Web Inspector: Clean up Object Property Descriptor Collection

Modified: trunk/Source/_javascript_Core/heap/MachineStackMarker.cpp (179647 => 179648)


--- trunk/Source/_javascript_Core/heap/MachineStackMarker.cpp	2015-02-05 00:32:27 UTC (rev 179647)
+++ trunk/Source/_javascript_Core/heap/MachineStackMarker.cpp	2015-02-05 00:32:47 UTC (rev 179648)
@@ -183,10 +183,12 @@
     static_cast<MachineThreads*>(p)->removeCurrentThread();
 }
 
-template<typename PlatformThread>
-void MachineThreads::removeThreadWithLockAlreadyAcquired(PlatformThread threadToRemove)
+void MachineThreads::removeCurrentThread()
 {
-    if (equalThread(threadToRemove, m_registeredThreads->platformThread)) {
+    PlatformThread currentPlatformThread = getCurrentPlatformThread();
+
+    MutexLocker lock(m_registeredThreadsMutex);
+    if (equalThread(currentPlatformThread, m_registeredThreads->platformThread)) {
         Thread* t = m_registeredThreads;
         m_registeredThreads = m_registeredThreads->next;
         delete t;
@@ -194,7 +196,7 @@
         Thread* last = m_registeredThreads;
         Thread* t;
         for (t = m_registeredThreads->next; t; t = t->next) {
-            if (equalThread(t->platformThread, threadToRemove)) {
+            if (equalThread(t->platformThread, currentPlatformThread)) {
                 last->next = t->next;
                 break;
             }
@@ -205,14 +207,6 @@
     }
 }
     
-void MachineThreads::removeCurrentThread()
-{
-    PlatformThread currentPlatformThread = getCurrentPlatformThread();
-
-    MutexLocker lock(m_registeredThreadsMutex);
-    removeThreadWithLockAlreadyAcquired(currentPlatformThread);
-}
-    
 void MachineThreads::gatherFromCurrentThread(ConservativeRoots& conservativeRoots, JITStubRoutineSet& jitStubRoutines, CodeBlockSet& codeBlocks, void* stackCurrent, RegisterState& registers)
 {
     void* registersBegin = &registers;
@@ -456,7 +450,9 @@
     PlatformThread currentPlatformThread = getCurrentPlatformThread();
     int numberOfThreads = 0; // Using 0 to denote that we haven't counted the number of threads yet.
     int index = 1;
+    Thread* threadsToBeDeleted = nullptr;
 
+    Thread* previousThread = nullptr;
     for (Thread* thread = m_registeredThreads; thread; index++) {
         if (!equalThread(thread->platformThread, currentPlatformThread)) {
             bool success = suspendThread(thread->platformThread);
@@ -474,9 +470,20 @@
                 WTFReportError(__FILE__, __LINE__, WTF_PRETTY_FUNCTION,
                     "_javascript_ garbage collection encountered an invalid thread (err 0x%x): Thread [%d/%d: %p] platformThread %p.",
                     error, index, numberOfThreads, thread, reinterpret_cast<void*>(thread->platformThread));
-                
+
+                // Put the invalid thread on the threadsToBeDeleted list.
+                // We can't just delete it here because we have suspended other
+                // threads, and they may still be holding the C heap lock which
+                // we need for deleting the invalid thread. Hence, we need to
+                // defer the deletion till after we have resumed all threads.
                 Thread* nextThread = thread->next;
-                removeThreadWithLockAlreadyAcquired(thread->platformThread);
+                thread->next = threadsToBeDeleted;
+                threadsToBeDeleted = thread;
+
+                if (previousThread)
+                    previousThread->next = nextThread;
+                else
+                    m_registeredThreads = nextThread;
                 thread = nextThread;
                 continue;
             }
@@ -485,6 +492,7 @@
             ASSERT_UNUSED(success, success);
 #endif
         }
+        previousThread = thread;
         thread = thread->next;
     }
 
@@ -498,6 +506,12 @@
             resumeThread(thread->platformThread);
     }
 
+    for (Thread* thread = threadsToBeDeleted; thread; ) {
+        Thread* nextThread = thread->next;
+        delete thread;
+        thread = nextThread;
+    }
+    
     return *size <= capacity;
 }
 

Modified: trunk/Source/_javascript_Core/heap/MachineStackMarker.h (179647 => 179648)


--- trunk/Source/_javascript_Core/heap/MachineStackMarker.h	2015-02-05 00:32:27 UTC (rev 179647)
+++ trunk/Source/_javascript_Core/heap/MachineStackMarker.h	2015-02-05 00:32:47 UTC (rev 179648)
@@ -57,9 +57,6 @@
         static void removeThread(void*);
         void removeCurrentThread();
 
-        template<typename PlatformThread>
-        void removeThreadWithLockAlreadyAcquired(PlatformThread);
-
         Mutex m_registeredThreadsMutex;
         Thread* m_registeredThreads;
         WTF::ThreadSpecificKey m_threadSpecific;
_______________________________________________
webkit-changes mailing list
[email protected]
https://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to