Changeset 260682 in webkit


Ignore:
Timestamp:
Apr 24, 2020 4:56:38 PM (4 years ago)
Author:
ysuzuki@apple.com
Message:

[WTF] allThreads registration is racy with allThreads unregistration
https://bugs.webkit.org/show_bug.cgi?id=210995
<rdar://problem/61609690>

Reviewed by Keith Miller.

Source/WebCore:

  • page/cocoa/ResourceUsageThreadCocoa.mm:

(WebCore::ResourceUsageThread::platformCollectCPUData):

Source/WTF:

There is a race between registering a thread to allThreads and unregistering a thread from allThreads.

  1. Caller: A new thread is created, but not registering it to allThreads yet.
  2. Thread: The thread is running.
  3. Thread: The thread finishes its execution before the thread is registered into allThreads.
  4. Thread: The thread unregisters itself from allThreads.
  5. Caller: Registers the new thread to allThreads after it already finished its execution.
  6. The thread is never removed from allThreads.

This patch adds m_didUnregisterFromAllThreads flag to Thread, and add the thread to allThreads only when this flag is false.

Covered by LayoutTests/inspector/cpu-profiler/threads.html.

  • wtf/Threading.cpp:

(WTF::Thread::create):
(WTF::Thread::didExit):

  • wtf/Threading.h:

(WTF::Thread::Thread):

Location:
trunk/Source
Files:
5 edited

Legend:

Unmodified
Added
Removed
  • trunk/Source/WTF/ChangeLog

    r260679 r260682  
     12020-04-24  Yusuke Suzuki  <ysuzuki@apple.com>
     2
     3        [WTF] allThreads registration is racy with allThreads unregistration
     4        https://bugs.webkit.org/show_bug.cgi?id=210995
     5        <rdar://problem/61609690>
     6
     7        Reviewed by Keith Miller.
     8
     9        There is a race between registering a thread to allThreads and unregistering a thread from allThreads.
     10
     11            1. Caller: A new thread is created, but not registering it to allThreads yet.
     12            2. Thread: The thread is running.
     13            3. Thread: The thread finishes its execution before the thread is registered into allThreads.
     14            4. Thread: The thread unregisters itself from allThreads.
     15            5. Caller: Registers the new thread to allThreads after it already finished its execution.
     16            6. The thread is never removed from allThreads.
     17
     18        This patch adds m_didUnregisterFromAllThreads flag to Thread, and add the thread to allThreads only when this flag is false.
     19
     20        Covered by LayoutTests/inspector/cpu-profiler/threads.html.
     21
     22        * wtf/Threading.cpp:
     23        (WTF::Thread::create):
     24        (WTF::Thread::didExit):
     25        * wtf/Threading.h:
     26        (WTF::Thread::Thread):
     27
    1282020-04-24  Alex Christensen  <achristensen@webkit.org>
    229
  • trunk/Source/WTF/wtf/Threading.cpp

    r257521 r260682  
    197197    }
    198198
    199     {
    200         LockHolder lock(allThreadsMutex());
    201         allThreads(lock).add(&thread.get());
     199    // We must register threads here since threads registered in allThreads are expected to have complete thread data which can be initialized in launched thread side.
     200    // However, it is also possible that the launched thread has finished its execution before it is registered in allThreads here! In this case, the thread has already
     201    // called Thread::didExit to unregister itself from allThreads. Registering such a thread will register a stale thread pointer to allThreads, which will not be removed
     202    // even after Thread is destroyed. Register a thread only when it has not unregistered itself from allThreads yet.
     203    {
     204        auto locker = holdLock(allThreadsMutex());
     205        if (!thread->m_didUnregisterFromAllThreads)
     206            allThreads(locker).add(thread.ptr());
    202207    }
    203208
     
    223228{
    224229    {
    225         LockHolder lock(allThreadsMutex());
    226         allThreads(lock).remove(this);
     230        auto locker = holdLock(allThreadsMutex());
     231        allThreads(locker).remove(this);
     232        m_didUnregisterFromAllThreads = true;
    227233    }
    228234
  • trunk/Source/WTF/wtf/Threading.h

    r257521 r260682  
    317317    unsigned m_gcThreadType : 2;
    318318
     319    bool m_didUnregisterFromAllThreads { false };
     320
    319321    // Lock & ParkingLot rely on ThreadSpecific. But Thread object can be destroyed even after ThreadSpecific things are destroyed.
    320322    // Use WordLock since WordLock does not depend on ThreadSpecific and this "Thread".
  • trunk/Source/WebCore/ChangeLog

    r260678 r260682  
     12020-04-24  Yusuke Suzuki  <ysuzuki@apple.com>
     2
     3        [WTF] allThreads registration is racy with allThreads unregistration
     4        https://bugs.webkit.org/show_bug.cgi?id=210995
     5        <rdar://problem/61609690>
     6
     7        Reviewed by Keith Miller.
     8
     9        * page/cocoa/ResourceUsageThreadCocoa.mm:
     10        (WebCore::ResourceUsageThread::platformCollectCPUData):
     11
    1122020-04-24  Wenson Hsieh  <wenson_hsieh@apple.com>
    213
  • trunk/Source/WebCore/page/cocoa/ResourceUsageThreadCocoa.mm

    r260366 r260682  
    157157    HashSet<mach_port_t> knownWebKitThreads;
    158158    {
    159         LockHolder lock(Thread::allThreadsMutex());
    160         for (auto* thread : Thread::allThreads(lock)) {
     159        auto locker = holdLock(Thread::allThreadsMutex());
     160        for (auto* thread : Thread::allThreads(locker)) {
    161161            mach_port_t machThread = thread->machThread();
    162162            if (machThread != MACH_PORT_NULL)
Note: See TracChangeset for help on using the changeset viewer.