⚠ Archived content — this site is no longer maintained.   Current WebKit documentation is at docs.webkit.org.

Changeset 268897 in webkit


Ignore:
Timestamp:
Oct 22, 2020, 3:25:44 PM (6 years ago)
Author:
Chris Dumez
Message:

Share more code between WorkerThread and AudioWorkletThread
https://bugs.webkit.org/show_bug.cgi?id=218051

Reviewed by Geoffrey Garen.

Share more code between WorkerThread and AudioWorkletThread by moving more logic
to the WorkerOrWorklet base class.

No new tests, no web-facing behavior change.

  • Modules/webaudio/AudioWorkletMessagingProxy.cpp:

(WebCore::generateWorkletParameters):

  • Modules/webaudio/AudioWorkletThread.cpp:

(WebCore::AudioWorkletThread::AudioWorkletThread):
(WebCore::AudioWorkletThread::createGlobalScope):
(WebCore::AudioWorkletThread::workerLoaderProxy):
(WebCore::AudioWorkletThread::createThread):
(WebCore::AudioWorkletThread::globalScope const):

  • Modules/webaudio/AudioWorkletThread.h:
  • Sources.txt:
  • WebCore.xcodeproj/project.pbxproj:
  • page/MemoryRelease.cpp:

(WebCore::releaseMemory):

  • page/cocoa/ResourceUsageThreadCocoa.mm:

(WebCore::ResourceUsageThread::platformCollectCPUData):

  • page/linux/ResourceUsageThreadLinux.cpp:

(WebCore::ResourceUsageThread::platformCollectCPUData):

  • workers/DedicatedWorkerThread.cpp:

(WebCore::DedicatedWorkerThread::runEventLoop):

  • workers/WorkerGlobalScope.h:
  • workers/WorkerOrWorkletGlobalScope.h:

(WebCore::WorkerOrWorkletGlobalScope::suspend):
(WebCore::WorkerOrWorkletGlobalScope::resume):

  • workers/WorkerOrWorkletThread.cpp: Copied from Source/WebCore/workers/WorkerThread.cpp.

(WebCore::WorkerOrWorkletThread::workerOrWorkletThreadsLock):
(WebCore::WorkerOrWorkletThread::WorkerOrWorkletThread):
(WebCore::WorkerOrWorkletThread::~WorkerOrWorkletThread):
(WebCore::WorkerOrWorkletThread::startRunningDebuggerTasks):
(WebCore::WorkerOrWorkletThread::stopRunningDebuggerTasks):
(WebCore::WorkerOrWorkletThread::runEventLoop):
(WebCore::WorkerOrWorkletThread::workerOrWorkletThread):
(WebCore::WorkerOrWorkletThread::start):
(WebCore::WorkerOrWorkletThread::stop):
(WebCore::WorkerOrWorkletThread::suspend):
(WebCore::WorkerOrWorkletThread::resume):
(WebCore::WorkerOrWorkletThread::releaseFastMallocFreeMemoryInAllThreads):

  • workers/WorkerOrWorkletThread.h:

(WebCore::WorkerOrWorkletThread::thread const):
(WebCore::WorkerOrWorkletThread::globalScope const):
(WebCore::WorkerOrWorkletThread::runLoop):
(WebCore::WorkerOrWorkletThread::start):
(WebCore::WorkerOrWorkletThread::stop):
(WebCore::WorkerOrWorkletThread::identifier const):
(WebCore::WorkerOrWorkletThread::evaluateScriptIfNecessary):
(WebCore::WorkerOrWorkletThread::shouldWaitForWebInspectorOnStartup const):

  • workers/WorkerThread.cpp:

(WebCore::WorkerThread::workerThreadCount):
(WebCore::WorkerThread::WorkerThread):
(WebCore::WorkerThread::~WorkerThread):
(WebCore::WorkerThread::createThread):
(WebCore::WorkerThread::createGlobalScope):
(WebCore::WorkerThread::shouldWaitForWebInspectorOnStartup const):
(WebCore::WorkerThread::evaluateScriptIfNecessary):
(WebCore::WorkerThread::globalScope):

  • workers/WorkerThread.h:
  • workers/service/context/ServiceWorkerThread.cpp:

(WebCore::ServiceWorkerThread::queueTaskToFireFetchEvent):
(WebCore::ServiceWorkerThread::queueTaskToPostMessage):
(WebCore::ServiceWorkerThread::queueTaskToFireInstallEvent):
(WebCore::ServiceWorkerThread::queueTaskToFireActivateEvent):
(WebCore::ServiceWorkerThread::finishedEvaluatingScript):

  • worklets/Worklet.cpp:

(WebCore::Worklet::Worklet):

  • worklets/Worklet.h:

(WebCore::Worklet::identifier const):

  • worklets/WorkletParameters.h:

(WebCore::WorkletParameters::isolatedCopy const):

Location:
trunk/Source/WebCore
Files:
19 edited
1 copied

Legend:

Unmodified
Added
Removed
  • trunk/Source/WebCore/ChangeLog

    r268895 r268897  
     12020-10-22  Chris Dumez  <cdumez@apple.com>
     2
     3        Share more code between WorkerThread and AudioWorkletThread
     4        https://bugs.webkit.org/show_bug.cgi?id=218051
     5
     6        Reviewed by Geoffrey Garen.
     7
     8        Share more code between WorkerThread and AudioWorkletThread by moving more logic
     9        to the WorkerOrWorklet base class.
     10
     11        No new tests, no web-facing behavior change.
     12
     13        * Modules/webaudio/AudioWorkletMessagingProxy.cpp:
     14        (WebCore::generateWorkletParameters):
     15        * Modules/webaudio/AudioWorkletThread.cpp:
     16        (WebCore::AudioWorkletThread::AudioWorkletThread):
     17        (WebCore::AudioWorkletThread::createGlobalScope):
     18        (WebCore::AudioWorkletThread::workerLoaderProxy):
     19        (WebCore::AudioWorkletThread::createThread):
     20        (WebCore::AudioWorkletThread::globalScope const):
     21        * Modules/webaudio/AudioWorkletThread.h:
     22        * Sources.txt:
     23        * WebCore.xcodeproj/project.pbxproj:
     24        * page/MemoryRelease.cpp:
     25        (WebCore::releaseMemory):
     26        * page/cocoa/ResourceUsageThreadCocoa.mm:
     27        (WebCore::ResourceUsageThread::platformCollectCPUData):
     28        * page/linux/ResourceUsageThreadLinux.cpp:
     29        (WebCore::ResourceUsageThread::platformCollectCPUData):
     30        * workers/DedicatedWorkerThread.cpp:
     31        (WebCore::DedicatedWorkerThread::runEventLoop):
     32        * workers/WorkerGlobalScope.h:
     33        * workers/WorkerOrWorkletGlobalScope.h:
     34        (WebCore::WorkerOrWorkletGlobalScope::suspend):
     35        (WebCore::WorkerOrWorkletGlobalScope::resume):
     36        * workers/WorkerOrWorkletThread.cpp: Copied from Source/WebCore/workers/WorkerThread.cpp.
     37        (WebCore::WorkerOrWorkletThread::workerOrWorkletThreadsLock):
     38        (WebCore::WorkerOrWorkletThread::WorkerOrWorkletThread):
     39        (WebCore::WorkerOrWorkletThread::~WorkerOrWorkletThread):
     40        (WebCore::WorkerOrWorkletThread::startRunningDebuggerTasks):
     41        (WebCore::WorkerOrWorkletThread::stopRunningDebuggerTasks):
     42        (WebCore::WorkerOrWorkletThread::runEventLoop):
     43        (WebCore::WorkerOrWorkletThread::workerOrWorkletThread):
     44        (WebCore::WorkerOrWorkletThread::start):
     45        (WebCore::WorkerOrWorkletThread::stop):
     46        (WebCore::WorkerOrWorkletThread::suspend):
     47        (WebCore::WorkerOrWorkletThread::resume):
     48        (WebCore::WorkerOrWorkletThread::releaseFastMallocFreeMemoryInAllThreads):
     49        * workers/WorkerOrWorkletThread.h:
     50        (WebCore::WorkerOrWorkletThread::thread const):
     51        (WebCore::WorkerOrWorkletThread::globalScope const):
     52        (WebCore::WorkerOrWorkletThread::runLoop):
     53        (WebCore::WorkerOrWorkletThread::start):
     54        (WebCore::WorkerOrWorkletThread::stop):
     55        (WebCore::WorkerOrWorkletThread::identifier const):
     56        (WebCore::WorkerOrWorkletThread::evaluateScriptIfNecessary):
     57        (WebCore::WorkerOrWorkletThread::shouldWaitForWebInspectorOnStartup const):
     58        * workers/WorkerThread.cpp:
     59        (WebCore::WorkerThread::workerThreadCount):
     60        (WebCore::WorkerThread::WorkerThread):
     61        (WebCore::WorkerThread::~WorkerThread):
     62        (WebCore::WorkerThread::createThread):
     63        (WebCore::WorkerThread::createGlobalScope):
     64        (WebCore::WorkerThread::shouldWaitForWebInspectorOnStartup const):
     65        (WebCore::WorkerThread::evaluateScriptIfNecessary):
     66        (WebCore::WorkerThread::globalScope):
     67        * workers/WorkerThread.h:
     68        * workers/service/context/ServiceWorkerThread.cpp:
     69        (WebCore::ServiceWorkerThread::queueTaskToFireFetchEvent):
     70        (WebCore::ServiceWorkerThread::queueTaskToPostMessage):
     71        (WebCore::ServiceWorkerThread::queueTaskToFireInstallEvent):
     72        (WebCore::ServiceWorkerThread::queueTaskToFireActivateEvent):
     73        (WebCore::ServiceWorkerThread::finishedEvaluatingScript):
     74        * worklets/Worklet.cpp:
     75        (WebCore::Worklet::Worklet):
     76        * worklets/Worklet.h:
     77        (WebCore::Worklet::identifier const):
     78        * worklets/WorkletParameters.h:
     79        (WebCore::WorkletParameters::isolatedCopy const):
     80
    1812020-10-22  Adrian Perez de Castro  <aperez@igalia.com>
    282
  • trunk/Source/WebCore/Modules/webaudio/AudioWorkletMessagingProxy.cpp

    r268103 r268897  
    5252        document->url(),
    5353        jsRuntimeFlags,
    54         worklet.audioContext() ? worklet.audioContext()->sampleRate() : 0.0f
     54        worklet.audioContext() ? worklet.audioContext()->sampleRate() : 0.0f,
     55        worklet.identifier()
    5556    };
    5657}
  • trunk/Source/WebCore/Modules/webaudio/AudioWorkletThread.cpp

    r268822 r268897  
    3434#include "AudioWorkletGlobalScope.h"
    3535#include "AudioWorkletMessagingProxy.h"
    36 #include "WorkerOrWorkletScriptController.h"
    37 
    38 #if PLATFORM(IOS_FAMILY)
    39 #include "FloatingPointEnvironment.h"
    40 #endif
    41 
    42 #if USE(GLIB)
    43 #include <wtf/glib/GRefPtr.h>
    44 #endif
     36#include <wtf/Threading.h>
    4537
    4638namespace WebCore {
    4739
    4840AudioWorkletThread::AudioWorkletThread(AudioWorkletMessagingProxy& messagingProxy, const WorkletParameters& parameters)
    49     : m_messagingProxy(messagingProxy)
     41    : WorkerOrWorkletThread(parameters.identifier.isolatedCopy())
     42    , m_messagingProxy(messagingProxy)
    5043    , m_parameters(parameters.isolatedCopy())
    5144{
     
    5447AudioWorkletThread::~AudioWorkletThread() = default;
    5548
    56 void AudioWorkletThread::start()
     49Ref<WorkerOrWorkletGlobalScope> AudioWorkletThread::createGlobalScope()
    5750{
    58     auto lock = holdLock(m_threadCreationAndWorkletGlobalScopeLock);
    59 
    60     Ref<Thread> thread = Thread::create("WebCore: AudioWorklet", [this] {
    61         workletThread();
    62     }, ThreadType::Audio);
    63     // Force the Thread object to be initialized fully before storing it to m_thread (and becoming visible to other threads).
    64     WTF::storeStoreFence();
    65     m_thread = WTFMove(thread);
    66 }
    67 
    68 void AudioWorkletThread::stop()
    69 {
    70     // Mutex protection is necessary to ensure that m_workerGlobalScope isn't changed by
    71     // WorkerThread::workerThread() while we're accessing it. Note also that stop() can
    72     // be called before m_workerGlobalScope is fully created.
    73     auto locker = tryHoldLock(m_threadCreationAndWorkletGlobalScopeLock);
    74     if (!locker) {
    75         // The thread is still starting, spin the runloop and try again to avoid deadlocks if the worker thread
    76         // needs to interact with the main thread during startup.
    77         callOnMainThread([this]() mutable {
    78             stop();
    79         });
    80         return;
    81     }
    82 
    83     // Ensure that tasks are being handled by thread event loop. If script execution weren't forbidden, a while(1) loop in JS could keep the thread alive forever.
    84     if (m_workletGlobalScope) {
    85         m_workletGlobalScope->script()->scheduleExecutionTermination();
    86 
    87         m_runLoop.postTaskAndTerminate({ ScriptExecutionContext::Task::CleanupTask, [] (ScriptExecutionContext& context ) {
    88             auto& workletGlobalScope = downcast<AudioWorkletGlobalScope>(context);
    89 
    90             workletGlobalScope.prepareForDestruction();
    91 
    92             // Stick a shutdown command at the end of the queue, so that we deal
    93             // with all the cleanup tasks the databases post first.
    94             workletGlobalScope.postTask({ ScriptExecutionContext::Task::CleanupTask, [] (ScriptExecutionContext& context) {
    95                 auto& workletGlobalScope = downcast<AudioWorkletGlobalScope>(context);
    96                 // It's not safe to call clearScript until all the cleanup tasks posted by functions initiated by WorkerThreadShutdownStartTask have completed.
    97                 workletGlobalScope.clearScript();
    98             } });
    99 
    100         } });
    101         return;
    102     }
    103     m_runLoop.terminate();
    104 }
    105 
    106 void AudioWorkletThread::workletThread()
    107 {
    108     auto protectedThis = makeRef(*this);
    109 
    110     // Propagate the mainThread's fenv to workers.
    111 #if PLATFORM(IOS_FAMILY)
    112     FloatingPointEnvironment::singleton().propagateMainThreadEnvironment();
    113 #endif
    114 
    115 #if USE(GLIB)
    116     GRefPtr<GMainContext> mainContext = adoptGRef(g_main_context_new());
    117     g_main_context_push_thread_default(mainContext.get());
    118 #endif
    119 
    120     WorkerOrWorkletScriptController* scriptController;
    121     {
    122         auto lock = holdLock(m_threadCreationAndWorkletGlobalScopeLock);
    123         m_workletGlobalScope = AudioWorkletGlobalScope::create(*this, m_parameters);
    124 
    125         scriptController = m_workletGlobalScope->script();
    126 
    127         if (m_runLoop.terminated()) {
    128             // The worker was terminated before the thread had a chance to run. Since the context didn't exist yet,
    129             // forbidExecution() couldn't be called from stop().
    130             scriptController->scheduleExecutionTermination();
    131             scriptController->forbidExecution();
    132         }
    133     }
    134 
    135     runEventLoop();
    136 
    137 #if USE(GLIB)
    138     g_main_context_pop_thread_default(mainContext.get());
    139 #endif
    140 
    141     RefPtr<Thread> protector = m_thread;
    142 
    143     ASSERT(m_workletGlobalScope->hasOneRef());
    144 
    145     RefPtr<AudioWorkletGlobalScope> workletGlobalScopeToDelete;
    146     {
    147         // Mutex protection is necessary to ensure that we don't change m_workerGlobalScope
    148         // while WorkerThread::stop is accessing it.
    149         auto lock = holdLock(m_threadCreationAndWorkletGlobalScopeLock);
    150 
    151         // Delay the destruction of the WorkerGlobalScope context until after we've unlocked the
    152         // m_threadCreationAndWorkerGlobalScopeMutex. This is needed because destructing the
    153         // context will trigger the main thread to race against us to delete the WorkerThread
    154         // object, and the WorkerThread object owns the mutex we need to unlock after this.
    155         workletGlobalScopeToDelete = WTFMove(m_workletGlobalScope);
    156     }
    157 
    158     // The below assignment will destroy the context, which will in turn notify messaging proxy.
    159     // We cannot let any objects survive past thread exit, because no other thread will run GC or otherwise destroy them.
    160     workletGlobalScopeToDelete = nullptr;
    161 
    162     // Send the last WorkerThread Ref to be Deref'ed on the main thread.
    163     callOnMainThread([protectedThis = WTFMove(protectedThis)] { });
    164 
    165     // The thread object may be already destroyed from notification now, don't try to access "this".
    166     protector->detach();
    167 }
    168 
    169 void AudioWorkletThread::runEventLoop()
    170 {
    171     // Does not return until terminated.
    172     m_runLoop.run(m_workletGlobalScope.get());
     51    return AudioWorkletGlobalScope::create(*this, m_parameters);
    17352}
    17453
     
    17857}
    17958
     59Ref<Thread> AudioWorkletThread::createThread()
     60{
     61    return Thread::create("WebCore: AudioWorklet", [this] {
     62        workerOrWorkletThread();
     63    }, ThreadType::Audio);
     64}
     65
     66AudioWorkletGlobalScope* AudioWorkletThread::globalScope() const
     67{
     68    return downcast<AudioWorkletGlobalScope>(WorkerOrWorkletThread::globalScope());
     69}
     70
    18071} // namespace WebCore
    18172
  • trunk/Source/WebCore/Modules/webaudio/AudioWorkletThread.h

    r268161 r268897  
    3131#if ENABLE(WEB_AUDIO)
    3232#include "WorkerOrWorkletThread.h"
    33 #include "WorkerRunLoop.h"
    3433#include "WorkletParameters.h"
    35 #include <wtf/Forward.h>
    36 #include <wtf/Lock.h>
    37 #include <wtf/Threading.h>
    3834
    3935namespace WebCore {
     
    5046    ~AudioWorkletThread();
    5147
    52     AudioWorkletGlobalScope* globalScope() const { return m_workletGlobalScope.get(); }
    53 
    54     void start();
    55     void stop();
     48    AudioWorkletGlobalScope* globalScope() const;
    5649
    5750    // WorkerOrWorkletThread.
    58     WorkerRunLoop& runLoop() final { return m_runLoop; }
    5951    WorkerLoaderProxy& workerLoaderProxy() final;
    60     Thread* thread() const final { return m_thread.get(); }
     52
    6153    AudioWorkletMessagingProxy& messagingProxy() { return m_messagingProxy; }
    6254
     
    6456    AudioWorkletThread(AudioWorkletMessagingProxy&, const WorkletParameters&);
    6557
    66     void runEventLoop();
    67     void workletThread();
     58    // WorkerOrWorkletThread.
     59    Ref<WTF::Thread> createThread() final;
     60    Ref<WorkerOrWorkletGlobalScope> createGlobalScope() final;
    6861
    6962    AudioWorkletMessagingProxy& m_messagingProxy;
    70     RefPtr<Thread> m_thread;
    71     WorkerRunLoop m_runLoop;
    7263    WorkletParameters m_parameters;
    73     RefPtr<AudioWorkletGlobalScope> m_workletGlobalScope;
    74     Lock m_threadCreationAndWorkletGlobalScopeLock;
    7564};
    7665
  • trunk/Source/WebCore/Sources.txt

    r268886 r268897  
    25642564workers/WorkerOrWorkletGlobalScope.cpp
    25652565workers/WorkerOrWorkletScriptController.cpp
     2566workers/WorkerOrWorkletThread.cpp
    25662567workers/WorkerRunLoop.cpp
    25672568workers/WorkerScriptLoader.cpp
  • trunk/Source/WebCore/WebCore.xcodeproj/project.pbxproj

    r268886 r268897  
    1075510755                837FB3421F9EA06700D0FC31 /* ExtendableMessageEvent.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = ExtendableMessageEvent.cpp; sourceTree = "<group>"; };
    1075610756                837FB3431F9EA06800D0FC31 /* ExtendableMessageEvent.idl */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = ExtendableMessageEvent.idl; sourceTree = "<group>"; };
     10757                837FCB4D2540E3C700934D4F /* WorkerOrWorkletThread.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = WorkerOrWorkletThread.cpp; sourceTree = "<group>"; };
    1075710758                8386A96E19F61E4F00E1EC4A /* StyleBuilderGenerated.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = StyleBuilderGenerated.cpp; path = DerivedSources/WebCore/StyleBuilderGenerated.cpp; sourceTree = BUILT_PRODUCTS_DIR; };
    1075810759                838867341D13BA59003697D0 /* RenderObjectEnums.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RenderObjectEnums.h; sourceTree = "<group>"; };
     
    1888018881                                835AA388253F55BB00746554 /* WorkerOrWorkletScriptController.cpp */,
    1888118882                                839A095B2524F37600EEF328 /* WorkerOrWorkletScriptController.h */,
     18883                                837FCB4D2540E3C700934D4F /* WorkerOrWorkletThread.cpp */,
    1888218884                                83E828B2252794CD0027E0F7 /* WorkerOrWorkletThread.h */,
    1888318885                                416E29A5102FA962007FC14E /* WorkerReportingProxy.h */,
  • trunk/Source/WebCore/page/MemoryRelease.cpp

    r261494 r268897  
    148148    if (synchronous == Synchronous::Yes) {
    149149        // FastMalloc has lock-free thread specific caches that can only be cleared from the thread itself.
    150         WorkerThread::releaseFastMallocFreeMemoryInAllThreads();
     150        WorkerOrWorkletThread::releaseFastMallocFreeMemoryInAllThreads();
    151151#if ENABLE(SCROLLING_THREAD)
    152152        ScrollingThread::dispatch(WTF::releaseFastMallocFreeMemory);
  • trunk/Source/WebCore/page/cocoa/ResourceUsageThreadCocoa.mm

    r266388 r268897  
    172172    HashMap<mach_port_t, String> knownWorkerThreads;
    173173    {
    174         LockHolder lock(WorkerThread::workerThreadsMutex());
    175         for (auto* thread : WorkerThread::workerThreads(lock)) {
     174        auto locker = holdLock(WorkerOrWorkletThread::workerOrWorkletThreadsLock());
     175        for (auto* thread : WorkerOrWorkletThread::workerOrWorkletThreads()) {
    176176            // Ignore worker threads that have not been fully started yet.
    177177            if (!thread->thread())
  • trunk/Source/WebCore/page/linux/ResourceUsageThreadLinux.cpp

    r266388 r268897  
    247247    HashMap<pid_t, String> knownWorkerThreads;
    248248    {
    249         LockHolder lock(WorkerThread::workerThreadsMutex());
    250         for (auto* thread : WorkerThread::workerThreads(lock)) {
     249        auto locker = holdLock(WorkerOrWorkletThread::workerOrWorkletThreadsLock());
     250        for (auto* thread : WorkerOrWorkletThread::workerOrWorkletThreads()) {
    251251            // Ignore worker threads that have not been fully started yet.
    252252            if (!thread->thread())
  • trunk/Source/WebCore/workers/DedicatedWorkerThread.cpp

    r256012 r268897  
    5555{
    5656    // Notify the parent object of our current active state before calling the superclass to run the event loop.
    57     m_workerObjectProxy.reportPendingActivity(workerGlobalScope()->hasPendingActivity());
     57    m_workerObjectProxy.reportPendingActivity(globalScope()->hasPendingActivity());
    5858    WorkerThread::runEventLoop();
    5959}
  • trunk/Source/WebCore/workers/WorkerGlobalScope.h

    r268822 r268897  
    7272#if ENABLE(INDEXED_DATABASE)
    7373    IDBClient::IDBConnectionProxy* idbConnectionProxy() final;
    74     void suspend();
    75     void resume();
     74    void suspend() final;
     75    void resume() final;
    7676#endif
    7777
  • trunk/Source/WebCore/workers/WorkerOrWorkletGlobalScope.h

    r268868 r268897  
    6262    using RefCounted::deref;
    6363
     64    virtual void suspend() { }
     65    virtual void resume() { }
     66
    6467protected:
    6568    WorkerOrWorkletGlobalScope(Ref<JSC::VM>&&, WorkerOrWorkletThread*);
  • trunk/Source/WebCore/workers/WorkerOrWorkletThread.cpp

    r268896 r268897  
    11/*
    2  * Copyright (C) 2008-2017 Apple Inc. All Rights Reserved.
     2 * Copyright (C) 2008-2020 Apple Inc. All rights reserved.
    33 *
    44 * Redistribution and use in source and binary forms, with or without
     
    2222 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
    2323 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
    24  *
    2524 */
    2625
    2726#include "config.h"
    28 #include "WorkerThread.h"
    29 
    30 #include "IDBConnectionProxy.h"
    31 #include "ScriptSourceCode.h"
    32 #include "SecurityOrigin.h"
    33 #include "SocketProvider.h"
    34 #include "ThreadGlobalData.h"
    35 #include "WorkerGlobalScope.h"
    36 #include "WorkerInspectorController.h"
    37 #include <utility>
    38 #include <wtf/Lock.h>
    39 #include <wtf/NeverDestroyed.h>
    40 #include <wtf/Noncopyable.h>
    41 #include <wtf/text/WTFString.h>
     27#include "WorkerOrWorkletThread.h"
     28
     29#include "WorkerOrWorkletScriptController.h"
    4230
    4331#if PLATFORM(IOS_FAMILY)
    4432#include "FloatingPointEnvironment.h"
    45 #include "WebCoreThread.h"
    4633#endif
    4734
     
    5239namespace WebCore {
    5340
    54 HashSet<WorkerThread*>& WorkerThread::workerThreads(const LockHolder&)
    55 {
    56     static NeverDestroyed<HashSet<WorkerThread*>> workerThreads;
    57     return workerThreads;
    58 }
    59 
    60 Lock& WorkerThread::workerThreadsMutex()
     41Lock& WorkerOrWorkletThread::workerOrWorkletThreadsLock()
    6142{
    6243    static Lock mutex;
     
    6445}
    6546
    66 unsigned WorkerThread::workerThreadCount()
    67 {
    68     LockHolder lock(workerThreadsMutex());
    69     return workerThreads(lock).size();
    70 }
    71 
    72 WorkerParameters WorkerParameters::isolatedCopy() const
    73 {
    74     return {
    75         scriptURL.isolatedCopy(),
    76         name.isolatedCopy(),
    77         identifier.isolatedCopy(),
    78         userAgent.isolatedCopy(),
    79         isOnline,
    80         contentSecurityPolicyResponseHeaders,
    81         shouldBypassMainWorldContentSecurityPolicy,
    82         timeOrigin,
    83         referrerPolicy,
    84         requestAnimationFrameEnabled,
    85         acceleratedCompositingEnabled,
    86         webGLEnabled,
    87     };
    88 }
    89 
    90 struct WorkerThreadStartupData {
    91     WTF_MAKE_NONCOPYABLE(WorkerThreadStartupData); WTF_MAKE_FAST_ALLOCATED;
    92 public:
    93     WorkerThreadStartupData(const WorkerParameters& params, const String& sourceCode, WorkerThreadStartMode, const SecurityOrigin& topOrigin);
    94 
    95     WorkerParameters params;
    96     Ref<SecurityOrigin> origin;
    97     String sourceCode;
    98     WorkerThreadStartMode startMode;
    99     Ref<SecurityOrigin> topOrigin;
    100 };
    101 
    102 WorkerThreadStartupData::WorkerThreadStartupData(const WorkerParameters& other, const String& sourceCode, WorkerThreadStartMode startMode, const SecurityOrigin& topOrigin)
    103     : params(other.isolatedCopy())
    104     , origin(SecurityOrigin::create(other.scriptURL)->isolatedCopy())
    105     , sourceCode(sourceCode.isolatedCopy())
    106     , startMode(startMode)
    107     , topOrigin(topOrigin.isolatedCopy())
    108 {
    109 }
    110 
    111 WorkerThread::WorkerThread(const WorkerParameters& params, const String& sourceCode, WorkerLoaderProxy& workerLoaderProxy, WorkerDebuggerProxy& workerDebuggerProxy, WorkerReportingProxy& workerReportingProxy, WorkerThreadStartMode startMode, const SecurityOrigin& topOrigin, IDBClient::IDBConnectionProxy* connectionProxy, SocketProvider* socketProvider, JSC::RuntimeFlags runtimeFlags)
    112     : m_identifier(params.identifier.isolatedCopy())
    113     , m_workerLoaderProxy(workerLoaderProxy)
    114     , m_workerDebuggerProxy(workerDebuggerProxy)
    115     , m_workerReportingProxy(workerReportingProxy)
    116     , m_runtimeFlags(runtimeFlags)
    117     , m_startupData(makeUnique<WorkerThreadStartupData>(params, sourceCode, startMode, topOrigin))
    118 #if ENABLE(INDEXED_DATABASE)
    119     , m_idbConnectionProxy(connectionProxy)
    120 #endif
    121     , m_socketProvider(socketProvider)
    122 {
    123 #if !ENABLE(INDEXED_DATABASE)
    124     UNUSED_PARAM(connectionProxy);
    125 #endif
    126 
    127     LockHolder lock(workerThreadsMutex());
    128     workerThreads(lock).add(this);
    129 }
    130 
    131 WorkerThread::~WorkerThread()
    132 {
    133     LockHolder lock(workerThreadsMutex());
    134     ASSERT(workerThreads(lock).contains(this));
    135     workerThreads(lock).remove(this);
    136 }
    137 
    138 void WorkerThread::start(WTF::Function<void(const String&)>&& evaluateCallback)
    139 {
    140     // Mutex protection is necessary to ensure that m_thread is initialized when the thread starts.
    141     LockHolder lock(m_threadCreationAndWorkerGlobalScopeMutex);
    142 
    143     if (m_thread)
    144         return;
    145 
    146     m_evaluateCallback = WTFMove(evaluateCallback);
    147 
    148     Ref<Thread> thread = Thread::create(isServiceWorkerThread() ? "WebCore: Service Worker" : "WebCore: Worker", [this] {
    149         workerThread();
    150     }, ThreadType::JavaScript);
    151     // Force the Thread object to be initialized fully before storing it to m_thread (and becoming visible to other threads).
    152     WTF::storeStoreFence();
    153     m_thread = WTFMove(thread);
    154 }
    155 
    156 void WorkerThread::workerThread()
     47HashSet<WorkerOrWorkletThread*>& WorkerOrWorkletThread::workerOrWorkletThreads()
     48{
     49    ASSERT(workerOrWorkletThreadsLock().isHeld());
     50    static NeverDestroyed<HashSet<WorkerOrWorkletThread*>> workerOrWorkletThreads;
     51    return workerOrWorkletThreads;
     52}
     53
     54WorkerOrWorkletThread::WorkerOrWorkletThread(const String& identifier)
     55    : m_identifier(identifier)
     56{
     57    auto locker = holdLock(workerOrWorkletThreadsLock());
     58    workerOrWorkletThreads().add(this);
     59}
     60
     61WorkerOrWorkletThread::~WorkerOrWorkletThread()
     62{
     63    auto locker = holdLock(workerOrWorkletThreadsLock());
     64    ASSERT(workerOrWorkletThreads().contains(this));
     65    workerOrWorkletThreads().remove(this);
     66}
     67
     68void WorkerOrWorkletThread::startRunningDebuggerTasks()
     69{
     70    ASSERT(!m_pausedForDebugger);
     71    m_pausedForDebugger = true;
     72
     73    MessageQueueWaitResult result;
     74    do {
     75        result = m_runLoop.runInDebuggerMode(*m_globalScope);
     76    } while (result != MessageQueueTerminated && m_pausedForDebugger);
     77}
     78
     79void WorkerOrWorkletThread::stopRunningDebuggerTasks()
     80{
     81    m_pausedForDebugger = false;
     82}
     83
     84void WorkerOrWorkletThread::runEventLoop()
     85{
     86    // Does not return until terminated.
     87    m_runLoop.run(m_globalScope.get());
     88}
     89
     90void WorkerOrWorkletThread::workerOrWorkletThread()
    15791{
    15892    auto protectedThis = makeRef(*this);
     
    170104    WorkerOrWorkletScriptController* scriptController;
    171105    {
    172         // Mutex protection is necessary to ensure that we don't change m_workerGlobalScope
     106        // Mutex protection is necessary to ensure that we don't change m_globalScope
    173107        // while WorkerThread::stop() is accessing it. Note that WorkerThread::stop() can
    174108        // be called before we've finished creating the WorkerGlobalScope.
    175         LockHolder lock(m_threadCreationAndWorkerGlobalScopeMutex);
    176         m_workerGlobalScope = createWorkerGlobalScope(m_startupData->params, WTFMove(m_startupData->origin), WTFMove(m_startupData->topOrigin));
    177 
    178         scriptController = m_workerGlobalScope->script();
     109        auto locker = holdLock(m_threadCreationAndGlobalScopeLock);
     110        m_globalScope = createGlobalScope();
     111
     112        scriptController = m_globalScope->script();
    179113
    180114        if (m_runLoop.terminated()) {
     
    186120    }
    187121
    188     if (m_startupData->startMode == WorkerThreadStartMode::WaitForInspector) {
     122    if (shouldWaitForWebInspectorOnStartup()) {
    189123        startRunningDebuggerTasks();
    190124
     
    195129
    196130    String exceptionMessage;
    197     scriptController->evaluate(ScriptSourceCode(m_startupData->sourceCode, URL(m_startupData->params.scriptURL)), &exceptionMessage);
    198 
    199     finishedEvaluatingScript();
     131    evaluateScriptIfNecessary(exceptionMessage);
    200132
    201133    callOnMainThread([evaluateCallback = WTFMove(m_evaluateCallback), message = exceptionMessage.isolatedCopy()] {
     
    204136    });
    205137
    206     // Free the startup data to cause its member variable deref's happen on the worker's thread (since
    207     // all ref/derefs of these objects are happening on the thread at this point). Note that
    208     // WorkerThread::~WorkerThread happens on a different thread where it was created.
    209     m_startupData = nullptr;
    210 
    211138    runEventLoop();
    212139
     
    217144    RefPtr<Thread> protector = m_thread;
    218145
    219     ASSERT(m_workerGlobalScope->hasOneRef());
    220 
    221     RefPtr<WorkerGlobalScope> workerGlobalScopeToDelete;
     146    ASSERT(m_globalScope->hasOneRef());
     147
     148    RefPtr<WorkerOrWorkletGlobalScope> workerGlobalScopeToDelete;
    222149    {
    223         // Mutex protection is necessary to ensure that we don't change m_workerGlobalScope
     150        // Mutex protection is necessary to ensure that we don't change m_globalScope
    224151        // while WorkerThread::stop is accessing it.
    225         LockHolder lock(m_threadCreationAndWorkerGlobalScopeMutex);
     152        auto locker = holdLock(m_threadCreationAndGlobalScopeLock);
    226153
    227154        // Delay the destruction of the WorkerGlobalScope context until after we've unlocked the
     
    229156        // context will trigger the main thread to race against us to delete the WorkerThread
    230157        // object, and the WorkerThread object owns the mutex we need to unlock after this.
    231         workerGlobalScopeToDelete = WTFMove(m_workerGlobalScope);
     158        workerGlobalScopeToDelete = std::exchange(m_globalScope, nullptr);
    232159
    233160        if (m_stoppedCallback)
     
    249176}
    250177
    251 void WorkerThread::startRunningDebuggerTasks()
    252 {
    253     ASSERT(!m_pausedForDebugger);
    254     m_pausedForDebugger = true;
    255 
    256     MessageQueueWaitResult result;
    257     do {
    258         result = m_runLoop.runInDebuggerMode(*m_workerGlobalScope);
    259     } while (result != MessageQueueTerminated && m_pausedForDebugger);
    260 }
    261 
    262 void WorkerThread::stopRunningDebuggerTasks()
    263 {
    264     m_pausedForDebugger = false;
    265 }
    266 
    267 void WorkerThread::runEventLoop()
    268 {
    269     // Does not return until terminated.
    270     m_runLoop.run(m_workerGlobalScope.get());
    271 }
    272 
    273 void WorkerThread::suspend()
    274 {
    275     m_isSuspended = true;
    276     runLoop().postTask([&](ScriptExecutionContext&) {
    277         if (m_workerGlobalScope)
    278             m_workerGlobalScope->suspend();
    279 
    280         m_suspensionSemaphore.wait();
    281 
    282         if (m_workerGlobalScope)
    283             m_workerGlobalScope->resume();
    284     });
    285 }
    286 
    287 void WorkerThread::resume()
    288 {
    289     ASSERT(m_isSuspended);
    290     m_isSuspended = false;
    291     m_suspensionSemaphore.signal();
    292 }
    293 
    294 void WorkerThread::stop(WTF::Function<void()>&& stoppedCallback)
     178void WorkerOrWorkletThread::start(WTF::Function<void(const String&)>&& evaluateCallback)
     179{
     180    // Mutex protection is necessary to ensure that m_thread is initialized when the thread starts.
     181    auto locker = holdLock(m_threadCreationAndGlobalScopeLock);
     182
     183    if (m_thread)
     184        return;
     185
     186    m_evaluateCallback = WTFMove(evaluateCallback);
     187
     188    auto thread = createThread();
     189
     190    // Force the Thread object to be initialized fully before storing it to m_thread (and becoming visible to other threads).
     191    WTF::storeStoreFence();
     192
     193    m_thread = WTFMove(thread);
     194}
     195
     196void WorkerOrWorkletThread::stop(Function<void()>&& stoppedCallback)
    295197{
    296198    // Mutex protection is necessary to ensure that m_workerGlobalScope isn't changed by
    297199    // WorkerThread::workerThread() while we're accessing it. Note also that stop() can
    298200    // be called before m_workerGlobalScope is fully created.
    299     auto locker = Locker<Lock>::tryLock(m_threadCreationAndWorkerGlobalScopeMutex);
     201    auto locker = tryHoldLock(m_threadCreationAndGlobalScopeLock);
    300202    if (!locker) {
    301203        // The thread is still starting, spin the runloop and try again to avoid deadlocks if the worker thread
     
    315217
    316218    // Ensure that tasks are being handled by thread event loop. If script execution weren't forbidden, a while(1) loop in JS could keep the thread alive forever.
    317     if (m_workerGlobalScope) {
    318         m_workerGlobalScope->script()->scheduleExecutionTermination();
     219    if (globalScope()) {
     220        globalScope()->script()->scheduleExecutionTermination();
    319221
    320222        m_runLoop.postTaskAndTerminate({ ScriptExecutionContext::Task::CleanupTask, [] (ScriptExecutionContext& context ) {
    321             WorkerGlobalScope& workerGlobalScope = downcast<WorkerGlobalScope>(context);
    322 
    323             workerGlobalScope.prepareForDestruction();
     223            auto& globalScope = downcast<WorkerOrWorkletGlobalScope>(context);
     224
     225            globalScope.prepareForDestruction();
    324226
    325227            // Stick a shutdown command at the end of the queue, so that we deal
    326228            // with all the cleanup tasks the databases post first.
    327             workerGlobalScope.postTask({ ScriptExecutionContext::Task::CleanupTask, [] (ScriptExecutionContext& context) {
    328                 WorkerGlobalScope& workerGlobalScope = downcast<WorkerGlobalScope>(context);
     229            globalScope.postTask({ ScriptExecutionContext::Task::CleanupTask, [] (ScriptExecutionContext& context) {
     230                auto& globalScope = downcast<WorkerOrWorkletGlobalScope>(context);
    329231                // It's not safe to call clearScript until all the cleanup tasks posted by functions initiated by WorkerThreadShutdownStartTask have completed.
    330                 workerGlobalScope.clearScript();
     232                globalScope.clearScript();
    331233            } });
    332234
     
    337239}
    338240
    339 void WorkerThread::releaseFastMallocFreeMemoryInAllThreads()
    340 {
    341     LockHolder lock(workerThreadsMutex());
    342     for (auto* workerThread : workerThreads(lock)) {
    343         workerThread->runLoop().postTask([] (ScriptExecutionContext&) {
     241void WorkerOrWorkletThread::suspend()
     242{
     243    m_isSuspended = true;
     244    m_runLoop.postTask([&](ScriptExecutionContext&) {
     245        if (globalScope())
     246            globalScope()->suspend();
     247
     248        m_suspensionSemaphore.wait();
     249
     250        if (globalScope())
     251            globalScope()->resume();
     252    });
     253}
     254
     255void WorkerOrWorkletThread::resume()
     256{
     257    ASSERT(m_isSuspended);
     258    m_isSuspended = false;
     259    m_suspensionSemaphore.signal();
     260}
     261
     262void WorkerOrWorkletThread::releaseFastMallocFreeMemoryInAllThreads()
     263{
     264    auto locker = holdLock(workerOrWorkletThreadsLock());
     265    for (auto* workerOrWorkletThread : workerOrWorkletThreads()) {
     266        workerOrWorkletThread->runLoop().postTask([] (ScriptExecutionContext&) {
    344267            WTF::releaseFastMallocFreeMemory();
    345268        });
     
    347270}
    348271
    349 IDBClient::IDBConnectionProxy* WorkerThread::idbConnectionProxy()
    350 {
    351 #if ENABLE(INDEXED_DATABASE)
    352     return m_idbConnectionProxy.get();
    353 #else
    354     return nullptr;
    355 #endif
    356 }
    357 
    358 SocketProvider* WorkerThread::socketProvider()
    359 {
    360     return m_socketProvider.get();
    361 }
    362 
    363272} // namespace WebCore
  • trunk/Source/WebCore/workers/WorkerOrWorkletThread.h

    r268161 r268897  
    11/*
    2  * Copyright (C) 2020 Apple Inc. All rights reserved.
     2 * Copyright (C) 2008-2020 Apple Inc. All rights reserved.
    33 *
    44 * Redistribution and use in source and binary forms, with or without
     
    2626#pragma once
    2727
     28#include "WorkerRunLoop.h"
     29#include <wtf/Forward.h>
     30#include <wtf/Function.h>
     31#include <wtf/Lock.h>
    2832#include <wtf/ThreadSafeRefCounted.h>
     33#include <wtf/threads/BinarySemaphore.h>
    2934
    3035namespace WTF {
     
    3944class WorkerOrWorkletThread : public ThreadSafeRefCounted<WorkerOrWorkletThread> {
    4045public:
    41     virtual ~WorkerOrWorkletThread() = default;
     46    virtual ~WorkerOrWorkletThread();
    4247
    43     virtual WTF::Thread* thread() const = 0;
    44     virtual WorkerRunLoop& runLoop() = 0;
     48    WTF::Thread* thread() const { return m_thread.get(); }
    4549    virtual WorkerLoaderProxy& workerLoaderProxy() = 0;
     50
     51    WorkerOrWorkletGlobalScope* globalScope() const { return m_globalScope.get(); }
     52    WorkerRunLoop& runLoop() { return m_runLoop; }
     53
     54    void start(Function<void(const String&)>&& evaluateCallback = { });
     55    void stop(Function<void()>&& terminatedCallback = { });
     56
     57    void startRunningDebuggerTasks();
     58    void stopRunningDebuggerTasks();
     59
     60    void suspend();
     61    void resume();
     62
     63    const String& identifier() const { return m_identifier; }
     64
     65    static HashSet<WorkerOrWorkletThread*>& workerOrWorkletThreads();
     66    static Lock& workerOrWorkletThreadsLock();
     67    static void releaseFastMallocFreeMemoryInAllThreads();
     68
     69protected:
     70    explicit WorkerOrWorkletThread(const String& identifier);
     71    void workerOrWorkletThread();
     72
     73    // Executes the event loop for the worker thread. Derived classes can override to perform actions before/after entering the event loop.
     74    virtual void runEventLoop();
     75
     76private:
     77    virtual Ref<WTF::Thread> createThread() = 0;
     78    virtual Ref<WorkerOrWorkletGlobalScope> createGlobalScope() = 0;
     79    virtual void evaluateScriptIfNecessary(String&) { }
     80    virtual bool shouldWaitForWebInspectorOnStartup() const { return false; }
     81
     82    String m_identifier;
     83    Lock m_threadCreationAndGlobalScopeLock;
     84    RefPtr<WorkerOrWorkletGlobalScope> m_globalScope;
     85    RefPtr<WTF::Thread> m_thread;
     86    WorkerRunLoop m_runLoop;
     87    Function<void(const String&)> m_evaluateCallback;
     88    Function<void()> m_stoppedCallback;
     89    BinarySemaphore m_suspensionSemaphore;
     90    bool m_isSuspended { false };
     91    bool m_pausedForDebugger { false };
    4692};
    4793
  • trunk/Source/WebCore/workers/WorkerThread.cpp

    r268822 r268897  
    3232#include "SecurityOrigin.h"
    3333#include "SocketProvider.h"
    34 #include "ThreadGlobalData.h"
    3534#include "WorkerGlobalScope.h"
    36 #include "WorkerInspectorController.h"
    37 #include <utility>
    38 #include <wtf/Lock.h>
    39 #include <wtf/NeverDestroyed.h>
    40 #include <wtf/Noncopyable.h>
    41 #include <wtf/text/WTFString.h>
    42 
    43 #if PLATFORM(IOS_FAMILY)
    44 #include "FloatingPointEnvironment.h"
    45 #include "WebCoreThread.h"
    46 #endif
    47 
    48 #if USE(GLIB)
    49 #include <wtf/glib/GRefPtr.h>
    50 #endif
     35#include <wtf/Threading.h>
    5136
    5237namespace WebCore {
    5338
    54 HashSet<WorkerThread*>& WorkerThread::workerThreads(const LockHolder&)
    55 {
    56     static NeverDestroyed<HashSet<WorkerThread*>> workerThreads;
    57     return workerThreads;
    58 }
    59 
    60 Lock& WorkerThread::workerThreadsMutex()
    61 {
    62     static Lock mutex;
    63     return mutex;
    64 }
     39static std::atomic<unsigned> workerThreadCounter { 0 };
    6540
    6641unsigned WorkerThread::workerThreadCount()
    6742{
    68     LockHolder lock(workerThreadsMutex());
    69     return workerThreads(lock).size();
     43    return workerThreadCounter;
    7044}
    7145
     
    11084
    11185WorkerThread::WorkerThread(const WorkerParameters& params, const String& sourceCode, WorkerLoaderProxy& workerLoaderProxy, WorkerDebuggerProxy& workerDebuggerProxy, WorkerReportingProxy& workerReportingProxy, WorkerThreadStartMode startMode, const SecurityOrigin& topOrigin, IDBClient::IDBConnectionProxy* connectionProxy, SocketProvider* socketProvider, JSC::RuntimeFlags runtimeFlags)
    112     : m_identifier(params.identifier.isolatedCopy())
     86    : WorkerOrWorkletThread(params.identifier.isolatedCopy())
    11387    , m_workerLoaderProxy(workerLoaderProxy)
    11488    , m_workerDebuggerProxy(workerDebuggerProxy)
     
    12498    UNUSED_PARAM(connectionProxy);
    12599#endif
    126 
    127     LockHolder lock(workerThreadsMutex());
    128     workerThreads(lock).add(this);
     100    ++workerThreadCounter;
    129101}
    130102
    131103WorkerThread::~WorkerThread()
    132104{
    133     LockHolder lock(workerThreadsMutex());
    134     ASSERT(workerThreads(lock).contains(this));
    135     workerThreads(lock).remove(this);
     105    ASSERT(workerThreadCounter);
     106    --workerThreadCounter;
    136107}
    137108
    138 void WorkerThread::start(WTF::Function<void(const String&)>&& evaluateCallback)
     109Ref<Thread> WorkerThread::createThread()
    139110{
    140     // Mutex protection is necessary to ensure that m_thread is initialized when the thread starts.
    141     LockHolder lock(m_threadCreationAndWorkerGlobalScopeMutex);
    142 
    143     if (m_thread)
    144         return;
    145 
    146     m_evaluateCallback = WTFMove(evaluateCallback);
    147 
    148     Ref<Thread> thread = Thread::create(isServiceWorkerThread() ? "WebCore: Service Worker" : "WebCore: Worker", [this] {
    149         workerThread();
     111    return Thread::create(isServiceWorkerThread() ? "WebCore: Service Worker" : "WebCore: Worker", [this] {
     112        workerOrWorkletThread();
    150113    }, ThreadType::JavaScript);
    151     // Force the Thread object to be initialized fully before storing it to m_thread (and becoming visible to other threads).
    152     WTF::storeStoreFence();
    153     m_thread = WTFMove(thread);
    154114}
    155115
    156 void WorkerThread::workerThread()
     116Ref<WorkerOrWorkletGlobalScope> WorkerThread::createGlobalScope()
    157117{
    158     auto protectedThis = makeRef(*this);
     118    return createWorkerGlobalScope(m_startupData->params, WTFMove(m_startupData->origin), WTFMove(m_startupData->topOrigin));
     119}
    159120
    160     // Propagate the mainThread's fenv to workers.
    161 #if PLATFORM(IOS_FAMILY)
    162     FloatingPointEnvironment::singleton().propagateMainThreadEnvironment();
    163 #endif
     121bool WorkerThread::shouldWaitForWebInspectorOnStartup() const
     122{
     123    return m_startupData->startMode == WorkerThreadStartMode::WaitForInspector;
     124}
    164125
    165 #if USE(GLIB)
    166     GRefPtr<GMainContext> mainContext = adoptGRef(g_main_context_new());
    167     g_main_context_push_thread_default(mainContext.get());
    168 #endif
    169 
    170     WorkerOrWorkletScriptController* scriptController;
    171     {
    172         // Mutex protection is necessary to ensure that we don't change m_workerGlobalScope
    173         // while WorkerThread::stop() is accessing it. Note that WorkerThread::stop() can
    174         // be called before we've finished creating the WorkerGlobalScope.
    175         LockHolder lock(m_threadCreationAndWorkerGlobalScopeMutex);
    176         m_workerGlobalScope = createWorkerGlobalScope(m_startupData->params, WTFMove(m_startupData->origin), WTFMove(m_startupData->topOrigin));
    177 
    178         scriptController = m_workerGlobalScope->script();
    179 
    180         if (m_runLoop.terminated()) {
    181             // The worker was terminated before the thread had a chance to run. Since the context didn't exist yet,
    182             // forbidExecution() couldn't be called from stop().
    183             scriptController->scheduleExecutionTermination();
    184             scriptController->forbidExecution();
    185         }
    186     }
    187 
    188     if (m_startupData->startMode == WorkerThreadStartMode::WaitForInspector) {
    189         startRunningDebuggerTasks();
    190 
    191         // If the worker was somehow terminated while processing debugger commands.
    192         if (m_runLoop.terminated())
    193             scriptController->forbidExecution();
    194     }
    195 
    196     String exceptionMessage;
    197     scriptController->evaluate(ScriptSourceCode(m_startupData->sourceCode, URL(m_startupData->params.scriptURL)), &exceptionMessage);
     126void WorkerThread::evaluateScriptIfNecessary(String& exceptionMessage)
     127{
     128    globalScope()->script()->evaluate(ScriptSourceCode(m_startupData->sourceCode, URL(m_startupData->params.scriptURL)), &exceptionMessage);
    198129
    199130    finishedEvaluatingScript();
    200 
    201     callOnMainThread([evaluateCallback = WTFMove(m_evaluateCallback), message = exceptionMessage.isolatedCopy()] {
    202         if (evaluateCallback)
    203             evaluateCallback(message);
    204     });
    205131
    206132    // Free the startup data to cause its member variable deref's happen on the worker's thread (since
     
    208134    // WorkerThread::~WorkerThread happens on a different thread where it was created.
    209135    m_startupData = nullptr;
    210 
    211     runEventLoop();
    212 
    213 #if USE(GLIB)
    214     g_main_context_pop_thread_default(mainContext.get());
    215 #endif
    216 
    217     RefPtr<Thread> protector = m_thread;
    218 
    219     ASSERT(m_workerGlobalScope->hasOneRef());
    220 
    221     RefPtr<WorkerGlobalScope> workerGlobalScopeToDelete;
    222     {
    223         // Mutex protection is necessary to ensure that we don't change m_workerGlobalScope
    224         // while WorkerThread::stop is accessing it.
    225         LockHolder lock(m_threadCreationAndWorkerGlobalScopeMutex);
    226 
    227         // Delay the destruction of the WorkerGlobalScope context until after we've unlocked the
    228         // m_threadCreationAndWorkerGlobalScopeMutex. This is needed because destructing the
    229         // context will trigger the main thread to race against us to delete the WorkerThread
    230         // object, and the WorkerThread object owns the mutex we need to unlock after this.
    231         workerGlobalScopeToDelete = WTFMove(m_workerGlobalScope);
    232 
    233         if (m_stoppedCallback)
    234             callOnMainThread(WTFMove(m_stoppedCallback));
    235     }
    236 
    237     // The below assignment will destroy the context, which will in turn notify messaging proxy.
    238     // We cannot let any objects survive past thread exit, because no other thread will run GC or otherwise destroy them.
    239     workerGlobalScopeToDelete = nullptr;
    240 
    241     // Clean up WebCore::ThreadGlobalData before WTF::Thread goes away!
    242     threadGlobalData().destroy();
    243 
    244     // Send the last WorkerThread Ref to be Deref'ed on the main thread.
    245     callOnMainThread([protectedThis = WTFMove(protectedThis)] { });
    246 
    247     // The thread object may be already destroyed from notification now, don't try to access "this".
    248     protector->detach();
    249 }
    250 
    251 void WorkerThread::startRunningDebuggerTasks()
    252 {
    253     ASSERT(!m_pausedForDebugger);
    254     m_pausedForDebugger = true;
    255 
    256     MessageQueueWaitResult result;
    257     do {
    258         result = m_runLoop.runInDebuggerMode(*m_workerGlobalScope);
    259     } while (result != MessageQueueTerminated && m_pausedForDebugger);
    260 }
    261 
    262 void WorkerThread::stopRunningDebuggerTasks()
    263 {
    264     m_pausedForDebugger = false;
    265 }
    266 
    267 void WorkerThread::runEventLoop()
    268 {
    269     // Does not return until terminated.
    270     m_runLoop.run(m_workerGlobalScope.get());
    271 }
    272 
    273 void WorkerThread::suspend()
    274 {
    275     m_isSuspended = true;
    276     runLoop().postTask([&](ScriptExecutionContext&) {
    277         if (m_workerGlobalScope)
    278             m_workerGlobalScope->suspend();
    279 
    280         m_suspensionSemaphore.wait();
    281 
    282         if (m_workerGlobalScope)
    283             m_workerGlobalScope->resume();
    284     });
    285 }
    286 
    287 void WorkerThread::resume()
    288 {
    289     ASSERT(m_isSuspended);
    290     m_isSuspended = false;
    291     m_suspensionSemaphore.signal();
    292 }
    293 
    294 void WorkerThread::stop(WTF::Function<void()>&& stoppedCallback)
    295 {
    296     // Mutex protection is necessary to ensure that m_workerGlobalScope isn't changed by
    297     // WorkerThread::workerThread() while we're accessing it. Note also that stop() can
    298     // be called before m_workerGlobalScope is fully created.
    299     auto locker = Locker<Lock>::tryLock(m_threadCreationAndWorkerGlobalScopeMutex);
    300     if (!locker) {
    301         // The thread is still starting, spin the runloop and try again to avoid deadlocks if the worker thread
    302         // needs to interact with the main thread during startup.
    303         callOnMainThread([this, stoppedCallback = WTFMove(stoppedCallback)]() mutable {
    304             stop(WTFMove(stoppedCallback));
    305         });
    306         return;
    307     }
    308 
    309     // If the thread is suspended, resume it now so that we can dispatch the cleanup tasks below.
    310     if (m_isSuspended)
    311         resume();
    312 
    313     ASSERT(!m_stoppedCallback);
    314     m_stoppedCallback = WTFMove(stoppedCallback);
    315 
    316     // Ensure that tasks are being handled by thread event loop. If script execution weren't forbidden, a while(1) loop in JS could keep the thread alive forever.
    317     if (m_workerGlobalScope) {
    318         m_workerGlobalScope->script()->scheduleExecutionTermination();
    319 
    320         m_runLoop.postTaskAndTerminate({ ScriptExecutionContext::Task::CleanupTask, [] (ScriptExecutionContext& context ) {
    321             WorkerGlobalScope& workerGlobalScope = downcast<WorkerGlobalScope>(context);
    322 
    323             workerGlobalScope.prepareForDestruction();
    324 
    325             // Stick a shutdown command at the end of the queue, so that we deal
    326             // with all the cleanup tasks the databases post first.
    327             workerGlobalScope.postTask({ ScriptExecutionContext::Task::CleanupTask, [] (ScriptExecutionContext& context) {
    328                 WorkerGlobalScope& workerGlobalScope = downcast<WorkerGlobalScope>(context);
    329                 // It's not safe to call clearScript until all the cleanup tasks posted by functions initiated by WorkerThreadShutdownStartTask have completed.
    330                 workerGlobalScope.clearScript();
    331             } });
    332 
    333         } });
    334         return;
    335     }
    336     m_runLoop.terminate();
    337 }
    338 
    339 void WorkerThread::releaseFastMallocFreeMemoryInAllThreads()
    340 {
    341     LockHolder lock(workerThreadsMutex());
    342     for (auto* workerThread : workerThreads(lock)) {
    343         workerThread->runLoop().postTask([] (ScriptExecutionContext&) {
    344             WTF::releaseFastMallocFreeMemory();
    345         });
    346     }
    347136}
    348137
     
    361150}
    362151
     152WorkerGlobalScope* WorkerThread::globalScope()
     153{
     154    return downcast<WorkerGlobalScope>(WorkerOrWorkletThread::globalScope());
     155}
     156
    363157} // namespace WebCore
  • trunk/Source/WebCore/workers/WorkerThread.h

    r268161 r268897  
    2828#include "ContentSecurityPolicyResponseHeaders.h"
    2929#include "WorkerOrWorkletThread.h"
    30 #include "WorkerRunLoop.h"
    3130#include <JavaScriptCore/RuntimeFlags.h>
    3231#include <memory>
    33 #include <wtf/Forward.h>
    34 #include <wtf/Function.h>
    35 #include <wtf/RefCounted.h>
    3632#include <wtf/URL.h>
    37 #include <wtf/threads/BinarySemaphore.h>
    3833
    3934namespace WebCore {
    4035
    41 class ContentSecurityPolicyResponseHeaders;
    4236class NotificationClient;
    4337class SecurityOrigin;
     
    8175    virtual ~WorkerThread();
    8276
    83     static HashSet<WorkerThread*>& workerThreads(const LockHolder&);
    84     static Lock& workerThreadsMutex();
    85 
    86     void stop(WTF::Function<void()>&& terminatedCallback);
    87 
    88     void suspend();
    89     void resume();
    90 
    91     Thread* thread() const final { return m_thread.get(); }
    92     WorkerRunLoop& runLoop() final { return m_runLoop; }
    9377    WorkerLoaderProxy& workerLoaderProxy() final { return m_workerLoaderProxy; }
    9478    WorkerDebuggerProxy& workerDebuggerProxy() const { return m_workerDebuggerProxy; }
     
    9781    // Number of active worker threads.
    9882    WEBCORE_EXPORT static unsigned workerThreadCount();
    99     static void releaseFastMallocFreeMemoryInAllThreads();
    10083
    10184#if ENABLE(NOTIFICATIONS)
     
    10386    void setNotificationClient(NotificationClient* client) { m_notificationClient = client; }
    10487#endif
    105 
    106     void startRunningDebuggerTasks();
    107     void stopRunningDebuggerTasks();
    10888   
    10989    JSC::RuntimeFlags runtimeFlags() const { return m_runtimeFlags; }
    110 
    111     String identifier() const { return m_identifier; }
    11290
    11391protected:
     
    11795    virtual Ref<WorkerGlobalScope> createWorkerGlobalScope(const WorkerParameters&, Ref<SecurityOrigin>&&, Ref<SecurityOrigin>&& topOrigin) = 0;
    11896
    119     // Executes the event loop for the worker thread. Derived classes can override to perform actions before/after entering the event loop.
    120     virtual void runEventLoop();
    121 
    122     WorkerGlobalScope* workerGlobalScope() { return m_workerGlobalScope.get(); }
     97    WorkerGlobalScope* globalScope();
    12398
    12499    IDBClient::IDBConnectionProxy* idbConnectionProxy();
    125100    SocketProvider* socketProvider();
    126101
    127     void start(Function<void(const String&)>&& evaluateCallback);
    128 
    129102private:
    130     void workerThread();
    131103    virtual bool isServiceWorkerThread() const { return false; }
    132104
    133105    virtual void finishedEvaluatingScript() { }
    134106
    135     RefPtr<Thread> m_thread;
    136     String m_identifier;
    137     WorkerRunLoop m_runLoop;
     107    // WorkerOrWorkletThread.
     108    Ref<WTF::Thread> createThread() final;
     109    Ref<WorkerOrWorkletGlobalScope> createGlobalScope() final;
     110    void evaluateScriptIfNecessary(String& exceptionMessage) final;
     111    bool shouldWaitForWebInspectorOnStartup() const final;
     112
    138113    WorkerLoaderProxy& m_workerLoaderProxy;
    139114    WorkerDebuggerProxy& m_workerDebuggerProxy;
    140115    WorkerReportingProxy& m_workerReportingProxy;
    141116    JSC::RuntimeFlags m_runtimeFlags;
    142     bool m_pausedForDebugger { false };
    143 
    144     RefPtr<WorkerGlobalScope> m_workerGlobalScope;
    145     Lock m_threadCreationAndWorkerGlobalScopeMutex;
    146117
    147118    std::unique_ptr<WorkerThreadStartupData> m_startupData;
    148    
    149     WTF::Function<void(const String&)> m_evaluateCallback;
    150119
    151120#if ENABLE(NOTIFICATIONS)
     
    157126#endif
    158127    RefPtr<SocketProvider> m_socketProvider;
    159 
    160     WTF::Function<void()> m_stoppedCallback;
    161     BinarySemaphore m_suspensionSemaphore;
    162     bool m_isSuspended { false };
    163128};
    164129
  • trunk/Source/WebCore/workers/service/context/ServiceWorkerThread.cpp

    r266275 r268897  
    100100void ServiceWorkerThread::queueTaskToFireFetchEvent(Ref<ServiceWorkerFetch::Client>&& client, Optional<ServiceWorkerClientIdentifier>&& clientId, ResourceRequest&& request, String&& referrer, FetchOptions&& options)
    101101{
    102     auto serviceWorkerGlobalScope = makeRef(downcast<ServiceWorkerGlobalScope>(*workerGlobalScope()));
     102    auto serviceWorkerGlobalScope = makeRef(downcast<ServiceWorkerGlobalScope>(*globalScope()));
    103103    serviceWorkerGlobalScope->eventLoop().queueTask(TaskSource::DOMManipulation, [serviceWorkerGlobalScope, client = WTFMove(client), clientId, request = WTFMove(request), referrer = WTFMove(referrer), options = WTFMove(options)]() mutable {
    104104        ServiceWorkerFetch::dispatchFetchEvent(WTFMove(client), serviceWorkerGlobalScope, clientId, WTFMove(request), WTFMove(referrer), WTFMove(options));
     
    117117void ServiceWorkerThread::queueTaskToPostMessage(MessageWithMessagePorts&& message, ServiceWorkerOrClientData&& sourceData)
    118118{
    119     auto serviceWorkerGlobalScope = makeRef(downcast<ServiceWorkerGlobalScope>(*workerGlobalScope()));
     119    auto serviceWorkerGlobalScope = makeRef(downcast<ServiceWorkerGlobalScope>(*globalScope()));
    120120    serviceWorkerGlobalScope->eventLoop().queueTask(TaskSource::DOMManipulation, [weakThis = makeWeakPtr(this), serviceWorkerGlobalScope, message = WTFMove(message), sourceData = WTFMove(sourceData)]() mutable {
    121121        URL sourceURL;
     
    146146void ServiceWorkerThread::queueTaskToFireInstallEvent()
    147147{
    148     auto serviceWorkerGlobalScope = makeRef(downcast<ServiceWorkerGlobalScope>(*workerGlobalScope()));
     148    auto serviceWorkerGlobalScope = makeRef(downcast<ServiceWorkerGlobalScope>(*globalScope()));
    149149    serviceWorkerGlobalScope->eventLoop().queueTask(TaskSource::DOMManipulation, [weakThis = makeWeakPtr(this), serviceWorkerGlobalScope]() mutable {
    150150        RELEASE_LOG(ServiceWorker, "ServiceWorkerThread::queueTaskToFireInstallEvent firing event for worker %llu", serviceWorkerGlobalScope->thread().identifier().toUInt64());
     
    172172void ServiceWorkerThread::queueTaskToFireActivateEvent()
    173173{
    174     auto serviceWorkerGlobalScope = makeRef(downcast<ServiceWorkerGlobalScope>(*workerGlobalScope()));
     174    auto serviceWorkerGlobalScope = makeRef(downcast<ServiceWorkerGlobalScope>(*globalScope()));
    175175    serviceWorkerGlobalScope->eventLoop().queueTask(TaskSource::DOMManipulation, [weakThis = makeWeakPtr(this), serviceWorkerGlobalScope]() mutable {
    176176        RELEASE_LOG(ServiceWorker, "ServiceWorkerThread::queueTaskToFireActivateEvent firing event for worker %llu", serviceWorkerGlobalScope->thread().identifier().toUInt64());
     
    192192{
    193193    ASSERT(!isMainThread());
    194     m_doesHandleFetch = workerGlobalScope()->hasEventListeners(eventNames().fetchEvent);
     194    m_doesHandleFetch = globalScope()->hasEventListeners(eventNames().fetchEvent);
    195195}
    196196
  • trunk/Source/WebCore/worklets/Worklet.cpp

    r267859 r268897  
    3434#include "WorkletGlobalScopeProxy.h"
    3535#include "WorkletPendingTasks.h"
     36#include <JavaScriptCore/IdentifiersFactory.h>
    3637#include <wtf/CrossThreadCopier.h>
    3738#include <wtf/IsoMallocInlines.h>
     
    4344Worklet::Worklet(Document& document)
    4445    : ActiveDOMObject(&document)
     46    , m_identifier("worklet:" + Inspector::IdentifiersFactory::createIdentifier())
    4547{
    4648}
  • trunk/Source/WebCore/worklets/Worklet.h

    r267859 r268897  
    5353
    5454    const Vector<Ref<WorkletGlobalScopeProxy>>& proxies() const { return m_proxies; }
     55    const String& identifier() const { return m_identifier; }
    5556
    5657protected:
     
    6364    const char* activeDOMObjectName() const final;
    6465
     66    String m_identifier;
    6567    Vector<Ref<WorkletGlobalScopeProxy>> m_proxies;
    6668    HashSet<RefPtr<WorkletPendingTasks>> m_pendingTasksSet;
  • trunk/Source/WebCore/worklets/WorkletParameters.h

    r268076 r268897  
    3535    JSC::RuntimeFlags jsRuntimeFlags;
    3636    float sampleRate;
     37    String identifier;
    3738
    3839    WorkletParameters isolatedCopy() const
     
    4142            windowURL.isolatedCopy(),
    4243            jsRuntimeFlags,
    43             sampleRate
     44            sampleRate,
     45            identifier.isolatedCopy()
    4446        };
    4547    }
Note: See TracChangeset for help on using the changeset viewer.