Changeset 179648 in webkit


Ignore:
Timestamp:
Feb 4, 2015 4:32:47 PM (9 years ago)
Author:
mark.lam@apple.com
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:
Location:
trunk/Source/JavaScriptCore
Files:
3 edited

Legend:

Unmodified
Added
Removed
  • trunk/Source/JavaScriptCore/ChangeLog

    r179640 r179648  
     12015-02-04  Mark Lam  <mark.lam@apple.com>
     2
     3        r179576 introduce a deadlock potential during GC thread suspension.
     4        <https://webkit.org/b/141268>
     5
     6        Reviewed by Michael Saboff.
     7
     8        http://trac.webkit.org/r179576 introduced a potential for deadlocking.
     9        In the GC thread suspension loop, we currently delete
     10        MachineThreads::Thread that we detect to be invalid.  This is unsafe
     11        because we may have already suspended some threads, and one of those
     12        suspended threads may still be holding the C heap lock which we need
     13        for deleting the invalid thread.
     14
     15        The fix is to put the invalid threads in a separate toBeDeleted list,
     16        and delete them only after GC has resumed all threads.
     17
     18        * heap/MachineStackMarker.cpp:
     19        (JSC::MachineThreads::removeCurrentThread):
     20        - Undo refactoring removeThreadWithLockAlreadyAcquired() out of
     21          removeCurrentThread() since it is no longer needed.
     22
     23        (JSC::MachineThreads::tryCopyOtherThreadStacks):
     24        - Put invalid Threads on a threadsToBeDeleted list, and delete those
     25          Threads only after all threads have been resumed.
     26
     27        (JSC::MachineThreads::removeThreadWithLockAlreadyAcquired): Deleted.
     28        * heap/MachineStackMarker.h:
     29
    1302015-02-04  Joseph Pecoraro  <pecoraro@apple.com>
    231
  • trunk/Source/JavaScriptCore/heap/MachineStackMarker.cpp

    r179609 r179648  
    184184}
    185185
    186 template<typename PlatformThread>
    187 void MachineThreads::removeThreadWithLockAlreadyAcquired(PlatformThread threadToRemove)
    188 {
    189     if (equalThread(threadToRemove, m_registeredThreads->platformThread)) {
     186void MachineThreads::removeCurrentThread()
     187{
     188    PlatformThread currentPlatformThread = getCurrentPlatformThread();
     189
     190    MutexLocker lock(m_registeredThreadsMutex);
     191    if (equalThread(currentPlatformThread, m_registeredThreads->platformThread)) {
    190192        Thread* t = m_registeredThreads;
    191193        m_registeredThreads = m_registeredThreads->next;
     
    195197        Thread* t;
    196198        for (t = m_registeredThreads->next; t; t = t->next) {
    197             if (equalThread(t->platformThread, threadToRemove)) {
     199            if (equalThread(t->platformThread, currentPlatformThread)) {
    198200                last->next = t->next;
    199201                break;
     
    204206        delete t;
    205207    }
    206 }
    207    
    208 void MachineThreads::removeCurrentThread()
    209 {
    210     PlatformThread currentPlatformThread = getCurrentPlatformThread();
    211 
    212     MutexLocker lock(m_registeredThreadsMutex);
    213     removeThreadWithLockAlreadyAcquired(currentPlatformThread);
    214208}
    215209   
     
    457451    int numberOfThreads = 0; // Using 0 to denote that we haven't counted the number of threads yet.
    458452    int index = 1;
    459 
     453    Thread* threadsToBeDeleted = nullptr;
     454
     455    Thread* previousThread = nullptr;
    460456    for (Thread* thread = m_registeredThreads; thread; index++) {
    461457        if (!equalThread(thread->platformThread, currentPlatformThread)) {
     
    475471                    "JavaScript garbage collection encountered an invalid thread (err 0x%x): Thread [%d/%d: %p] platformThread %p.",
    476472                    error, index, numberOfThreads, thread, reinterpret_cast<void*>(thread->platformThread));
    477                
     473
     474                // Put the invalid thread on the threadsToBeDeleted list.
     475                // We can't just delete it here because we have suspended other
     476                // threads, and they may still be holding the C heap lock which
     477                // we need for deleting the invalid thread. Hence, we need to
     478                // defer the deletion till after we have resumed all threads.
    478479                Thread* nextThread = thread->next;
    479                 removeThreadWithLockAlreadyAcquired(thread->platformThread);
     480                thread->next = threadsToBeDeleted;
     481                threadsToBeDeleted = thread;
     482
     483                if (previousThread)
     484                    previousThread->next = nextThread;
     485                else
     486                    m_registeredThreads = nextThread;
    480487                thread = nextThread;
    481488                continue;
     
    486493#endif
    487494        }
     495        previousThread = thread;
    488496        thread = thread->next;
    489497    }
     
    499507    }
    500508
     509    for (Thread* thread = threadsToBeDeleted; thread; ) {
     510        Thread* nextThread = thread->next;
     511        delete thread;
     512        thread = nextThread;
     513    }
     514   
    501515    return *size <= capacity;
    502516}
  • trunk/Source/JavaScriptCore/heap/MachineStackMarker.h

    r179609 r179648  
    5858        void removeCurrentThread();
    5959
    60         template<typename PlatformThread>
    61         void removeThreadWithLockAlreadyAcquired(PlatformThread);
    62 
    6360        Mutex m_registeredThreadsMutex;
    6461        Thread* m_registeredThreads;
Note: See TracChangeset for help on using the changeset viewer.