Add Internals.terminateServiceWorker, and the ability to restart service workers...
authorbeidson@apple.com <beidson@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Fri, 1 Dec 2017 19:45:41 +0000 (19:45 +0000)
committerbeidson@apple.com <beidson@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Fri, 1 Dec 2017 19:45:41 +0000 (19:45 +0000)
https://bugs.webkit.org/show_bug.cgi?id=180170

Reviewed by Chris Dumez.

Source/WebCore:

Test: http/tests/workers/service/postmessage-after-terminate.https.html

* dom/ActiveDOMObject.cpp:
(WebCore::ActiveDOMObject::~ActiveDOMObject):

* testing/Internals.cpp:
(WebCore::Internals::terminateServiceWorker):
* testing/Internals.h:
* testing/Internals.idl:

* workers/service/SWClientConnection.h:

* workers/service/ServiceWorker.idl:

* workers/service/context/SWContextManager.cpp:
(WebCore::SWContextManager::postMessageToServiceWorkerGlobalScope):
(WebCore::SWContextManager::terminateWorker):
* workers/service/context/SWContextManager.h:

* workers/service/context/ServiceWorkerThreadProxy.h:

* workers/service/server/SWServer.cpp:
(WebCore::SWServer::workerByID const):
(WebCore::SWServer::Connection::syncTerminateWorker):
(WebCore::SWServer::installContextData):
(WebCore::SWServer::invokeRunServiceWorker):
(WebCore::SWServer::terminateWorker):
(WebCore::SWServer::syncTerminateWorker):
(WebCore::SWServer::terminateWorkerInternal):
(WebCore::SWServer::workerContextTerminated):
* workers/service/server/SWServer.h:
(WebCore::SWServer::workerByID const): Deleted.

* workers/service/server/SWServerToContextConnection.h:

* workers/service/server/SWServerWorker.cpp:
(WebCore::SWServerWorker::contextData const):
* workers/service/server/SWServerWorker.h:
(WebCore::SWServerWorker::isRunning const):
(WebCore::SWServerWorker::isTerminating const):
(WebCore::SWServerWorker::setState):
(WebCore::SWServerWorker::server):

Source/WebKit:

* StorageProcess/ServiceWorker/WebSWServerConnection.cpp:
(WebKit::WebSWServerConnection::startFetch):
(WebKit::WebSWServerConnection::postMessageToServiceWorkerGlobalScope):
* StorageProcess/ServiceWorker/WebSWServerConnection.h:
* StorageProcess/ServiceWorker/WebSWServerConnection.messages.in:

* StorageProcess/ServiceWorker/WebSWServerToContextConnection.cpp:
(WebKit::WebSWServerToContextConnection::syncTerminateWorker):
* StorageProcess/ServiceWorker/WebSWServerToContextConnection.h:

* StorageProcess/StorageToWebProcessConnection.cpp:
(WebKit::StorageToWebProcessConnection::didReceiveSyncMessage):

* WebProcess/Storage/WebSWClientConnection.cpp:
(WebKit::WebSWClientConnection::syncTerminateWorker):
* WebProcess/Storage/WebSWClientConnection.h:

* WebProcess/Storage/WebSWContextManagerConnection.cpp:
(WebKit::WebSWContextManagerConnection::terminateWorker):
(WebKit::WebSWContextManagerConnection::syncTerminateWorker):
* WebProcess/Storage/WebSWContextManagerConnection.h:
* WebProcess/Storage/WebSWContextManagerConnection.messages.in:

* WebProcess/Storage/WebToStorageProcessConnection.cpp:
(WebKit::WebToStorageProcessConnection::didReceiveSyncMessage):
* WebProcess/Storage/WebToStorageProcessConnection.h:

Source/WTF:

* wtf/CompletionHandler.h:
(WTF::CompletionHandler<Out):

LayoutTests:

* http/tests/workers/service/postmessage-after-terminate.https-expected.txt: Added.
* http/tests/workers/service/postmessage-after-terminate.https.html: Added.
* http/tests/workers/service/resources/basic-ServiceWorker-postMessage.js:
(then):
* http/tests/workers/service/resources/postmessage-after-terminate.js: Copied from LayoutTests/http/tests/workers/service/resources/basic-ServiceWorker-postMessage.js.
(then):
* http/tests/workers/service/resources/postmessage-echo-worker.js: Renamed from LayoutTests/http/tests/workers/service/resources/basic-ServiceWorker-postMessage-worker.js.

git-svn-id: https://svn.webkit.org/repository/webkit/trunk@225403 268f45cc-cd09-0410-ab3c-d52691b4dbfc

37 files changed:
LayoutTests/ChangeLog
LayoutTests/http/tests/workers/service/postmessage-after-terminate.https-expected.txt [new file with mode: 0644]
LayoutTests/http/tests/workers/service/postmessage-after-terminate.https.html [new file with mode: 0644]
LayoutTests/http/tests/workers/service/resources/basic-ServiceWorker-postMessage.js
LayoutTests/http/tests/workers/service/resources/postmessage-after-terminate.js [new file with mode: 0644]
LayoutTests/http/tests/workers/service/resources/postmessage-echo-worker.js [moved from LayoutTests/http/tests/workers/service/resources/basic-ServiceWorker-postMessage-worker.js with 100% similarity]
Source/WTF/ChangeLog
Source/WTF/wtf/CompletionHandler.h
Source/WebCore/ChangeLog
Source/WebCore/dom/ActiveDOMObject.cpp
Source/WebCore/testing/Internals.cpp
Source/WebCore/testing/Internals.h
Source/WebCore/testing/Internals.idl
Source/WebCore/workers/service/SWClientConnection.h
Source/WebCore/workers/service/ServiceWorker.idl
Source/WebCore/workers/service/context/SWContextManager.cpp
Source/WebCore/workers/service/context/SWContextManager.h
Source/WebCore/workers/service/context/ServiceWorkerThreadProxy.h
Source/WebCore/workers/service/server/SWServer.cpp
Source/WebCore/workers/service/server/SWServer.h
Source/WebCore/workers/service/server/SWServerToContextConnection.h
Source/WebCore/workers/service/server/SWServerWorker.cpp
Source/WebCore/workers/service/server/SWServerWorker.h
Source/WebKit/ChangeLog
Source/WebKit/StorageProcess/ServiceWorker/WebSWServerConnection.cpp
Source/WebKit/StorageProcess/ServiceWorker/WebSWServerConnection.h
Source/WebKit/StorageProcess/ServiceWorker/WebSWServerConnection.messages.in
Source/WebKit/StorageProcess/ServiceWorker/WebSWServerToContextConnection.cpp
Source/WebKit/StorageProcess/ServiceWorker/WebSWServerToContextConnection.h
Source/WebKit/StorageProcess/StorageToWebProcessConnection.cpp
Source/WebKit/WebProcess/Storage/WebSWClientConnection.cpp
Source/WebKit/WebProcess/Storage/WebSWClientConnection.h
Source/WebKit/WebProcess/Storage/WebSWContextManagerConnection.cpp
Source/WebKit/WebProcess/Storage/WebSWContextManagerConnection.h
Source/WebKit/WebProcess/Storage/WebSWContextManagerConnection.messages.in
Source/WebKit/WebProcess/Storage/WebToStorageProcessConnection.cpp
Source/WebKit/WebProcess/Storage/WebToStorageProcessConnection.h

index 1e7a5c3..8c40f03 100644 (file)
@@ -1,3 +1,18 @@
+2017-12-01  Brady Eidson  <beidson@apple.com>
+
+        Add Internals.terminateServiceWorker, and the ability to restart service workers for postMessage.
+        https://bugs.webkit.org/show_bug.cgi?id=180170
+
+        Reviewed by Chris Dumez.
+
+        * http/tests/workers/service/postmessage-after-terminate.https-expected.txt: Added.
+        * http/tests/workers/service/postmessage-after-terminate.https.html: Added.
+        * http/tests/workers/service/resources/basic-ServiceWorker-postMessage.js:
+        (then):
+        * http/tests/workers/service/resources/postmessage-after-terminate.js: Copied from LayoutTests/http/tests/workers/service/resources/basic-ServiceWorker-postMessage.js.
+        (then):
+        * http/tests/workers/service/resources/postmessage-echo-worker.js: Renamed from LayoutTests/http/tests/workers/service/resources/basic-ServiceWorker-postMessage-worker.js.
+
 2017-12-01  Zalan Bujtas  <zalan@apple.com>
 
         Nullptr deref in WebCore::RenderTableCaption::containingBlockLogicalWidthForContent
diff --git a/LayoutTests/http/tests/workers/service/postmessage-after-terminate.https-expected.txt b/LayoutTests/http/tests/workers/service/postmessage-after-terminate.https-expected.txt
new file mode 100644 (file)
index 0000000..f7c37e6
--- /dev/null
@@ -0,0 +1,5 @@
+PASS: Client received message from service worker, origin: https://127.0.0.1:8443
+PASS: Service worker received message 'Message 1' from origin 'https://127.0.0.1:8443'
+PASS: Client received message from service worker, origin: https://127.0.0.1:8443
+PASS: Service worker received message 'Message 2' from origin 'https://127.0.0.1:8443'
+
diff --git a/LayoutTests/http/tests/workers/service/postmessage-after-terminate.https.html b/LayoutTests/http/tests/workers/service/postmessage-after-terminate.https.html
new file mode 100644 (file)
index 0000000..c068ab6
--- /dev/null
@@ -0,0 +1,9 @@
+<html>
+<head>
+<script src="resources/sw-test-pre.js"></script>
+</head>
+<body>
+
+<script src="resources/postmessage-after-terminate.js"></script>
+</body>
+</html>
index f90045c..ceb5777 100644 (file)
@@ -9,6 +9,6 @@ navigator.serviceWorker.addEventListener("message", function(event) {
         finishSWTest();
 });
 
-navigator.serviceWorker.register("resources/basic-ServiceWorker-postMessage-worker.js", { }).then(function(registration) {
+navigator.serviceWorker.register("resources/postmessage-echo-worker.js", { }).then(function(registration) {
     registration.installing.postMessage("Message 1");
 });
diff --git a/LayoutTests/http/tests/workers/service/resources/postmessage-after-terminate.js b/LayoutTests/http/tests/workers/service/resources/postmessage-after-terminate.js
new file mode 100644 (file)
index 0000000..9d5f975
--- /dev/null
@@ -0,0 +1,15 @@
+var messageNumber = 1;
+navigator.serviceWorker.addEventListener("message", function(event) {
+    log("PASS: Client received message from service worker, origin: " + event.origin);
+    log(event.data);
+    if (messageNumber == 1) {
+        window.internals.terminateServiceWorker(event.source);
+        event.source.postMessage("Message 2");
+        messageNumber++;
+    } else
+        finishSWTest();
+});
+
+navigator.serviceWorker.register("resources/postmessage-echo-worker.js", { }).then(function(registration) {
+    registration.installing.postMessage("Message 1");
+});
index 8864bc1..d2ab6dd 100644 (file)
@@ -1,3 +1,13 @@
+2017-12-01  Brady Eidson  <beidson@apple.com>
+
+        Add Internals.terminateServiceWorker, and the ability to restart service workers for postMessage.
+        https://bugs.webkit.org/show_bug.cgi?id=180170
+
+        Reviewed by Chris Dumez.
+
+        * wtf/CompletionHandler.h:
+        (WTF::CompletionHandler<Out):
+
 2017-11-30  Yusuke Suzuki  <utatane.tea@gmail.com>
 
         [JSC] Remove easy toRemove & map.remove() use in OAS phase
index 36b1cb6..a553c73 100644 (file)
@@ -53,7 +53,7 @@ public:
 
     explicit operator bool() const { return !!m_function; }
 
-    Out operator()(In... in)
+    Out operator()(In... in) const
     {
         ASSERT_WITH_MESSAGE(m_function, "Completion handler should not be called more than once");
         auto function = WTFMove(m_function);
@@ -61,7 +61,7 @@ public:
     }
 
 private:
-    WTF::Function<Out(In...)> m_function;
+    mutable WTF::Function<Out(In...)> m_function;
 };
 
 } // namespace WTF
index 36ca971..9a8f2b2 100644 (file)
@@ -1,3 +1,53 @@
+2017-12-01  Brady Eidson  <beidson@apple.com>
+
+        Add Internals.terminateServiceWorker, and the ability to restart service workers for postMessage.
+        https://bugs.webkit.org/show_bug.cgi?id=180170
+
+        Reviewed by Chris Dumez.
+
+        Test: http/tests/workers/service/postmessage-after-terminate.https.html
+
+        * dom/ActiveDOMObject.cpp:
+        (WebCore::ActiveDOMObject::~ActiveDOMObject):
+
+        * testing/Internals.cpp:
+        (WebCore::Internals::terminateServiceWorker):
+        * testing/Internals.h:
+        * testing/Internals.idl:
+
+        * workers/service/SWClientConnection.h:
+
+        * workers/service/ServiceWorker.idl:
+
+        * workers/service/context/SWContextManager.cpp:
+        (WebCore::SWContextManager::postMessageToServiceWorkerGlobalScope):
+        (WebCore::SWContextManager::terminateWorker):
+        * workers/service/context/SWContextManager.h:
+
+        * workers/service/context/ServiceWorkerThreadProxy.h:
+
+        * workers/service/server/SWServer.cpp:
+        (WebCore::SWServer::workerByID const):
+        (WebCore::SWServer::Connection::syncTerminateWorker):
+        (WebCore::SWServer::installContextData):
+        (WebCore::SWServer::invokeRunServiceWorker):
+        (WebCore::SWServer::terminateWorker):
+        (WebCore::SWServer::syncTerminateWorker):
+        (WebCore::SWServer::terminateWorkerInternal):
+        (WebCore::SWServer::workerContextTerminated):
+        * workers/service/server/SWServer.h:
+        (WebCore::SWServer::workerByID const): Deleted.
+
+        * workers/service/server/SWServerToContextConnection.h:
+
+        * workers/service/server/SWServerWorker.cpp:
+        (WebCore::SWServerWorker::contextData const):
+        * workers/service/server/SWServerWorker.h:
+        (WebCore::SWServerWorker::isRunning const):
+        (WebCore::SWServerWorker::isTerminating const):
+        (WebCore::SWServerWorker::setState):
+        (WebCore::SWServerWorker::server):
+
 2017-12-01  Zalan Bujtas  <zalan@apple.com>
 
         Nullptr deref in WebCore::RenderTableCaption::containingBlockLogicalWidthForContent
index d6cfe29..582b395 100644 (file)
@@ -47,21 +47,18 @@ ActiveDOMObject::ActiveDOMObject(ScriptExecutionContext* scriptExecutionContext)
 
 ActiveDOMObject::~ActiveDOMObject()
 {
-    if (!m_scriptExecutionContext)
-        return;
-
-    ASSERT(m_suspendIfNeededWasCalled);
-
     // ActiveDOMObject may be inherited by a sub-class whose life-cycle
     // exceeds that of the associated ScriptExecutionContext. In those cases,
     // m_scriptExecutionContext would/should have been nullified by
     // ContextDestructionObserver::contextDestroyed() (which we implement /
     // inherit). Hence, we should ensure that this is not 0 before use it
     // here.
-    if (m_scriptExecutionContext) {
-        ASSERT(m_scriptExecutionContext->isContextThread());
-        m_scriptExecutionContext->willDestroyActiveDOMObject(*this);
-    }
+    if (!m_scriptExecutionContext)
+        return;
+
+    ASSERT(m_suspendIfNeededWasCalled);
+    ASSERT(m_scriptExecutionContext->isContextThread());
+    m_scriptExecutionContext->willDestroyActiveDOMObject(*this);
 }
 
 void ActiveDOMObject::suspendIfNeeded()
index 7f8ce4a..6646c4f 100644 (file)
 #include "ScrollingMomentumCalculator.h"
 #include "SecurityOrigin.h"
 #include "SerializedScriptValue.h"
+#include "ServiceWorker.h"
 #include "ServiceWorkerProvider.h"
 #include "ServiceWorkerRegistrationData.h"
 #include "Settings.h"
@@ -4270,6 +4271,14 @@ void Internals::hasServiceWorkerRegistration(const String& clientURL, HasRegistr
         promise.resolve(!!result);
     });
 }
+
+void Internals::terminateServiceWorker(ServiceWorker& worker)
+{
+    if (!contextDocument())
+        return;
+
+    ServiceWorkerProvider::singleton().serviceWorkerConnectionForSession(contextDocument()->sessionID()).syncTerminateWorker(worker.identifier());
+}
 #endif
 
 String Internals::timelineDescription(AnimationTimeline& timeline)
index 74b047c..6998a7e 100644 (file)
@@ -90,6 +90,10 @@ class VoidCallback;
 class WebGLRenderingContext;
 class XMLHttpRequest;
 
+#if ENABLE(SERVICE_WORKER)
+class ServiceWorker;
+#endif
+
 class Internals final : public RefCounted<Internals>, private ContextDestructionObserver
 #if ENABLE(MEDIA_STREAM)
     , private RealtimeMediaSource::Observer
@@ -623,6 +627,7 @@ public:
     Ref<FetchEvent> createBeingDispatchedFetchEvent(ScriptExecutionContext&);
     using HasRegistrationPromise = DOMPromiseDeferred<IDLBoolean>;
     void hasServiceWorkerRegistration(const String& clientURL, HasRegistrationPromise&&);
+    void terminateServiceWorker(ServiceWorker&);
 #endif
 
 #if ENABLE(APPLE_PAY)
index 99a1c91..2e2447a 100644 (file)
@@ -567,6 +567,7 @@ enum EventThrottlingBehavior {
     [Conditional=SERVICE_WORKER] Promise<Response> waitForFetchEventToFinish(FetchEvent event);
     [Conditional=SERVICE_WORKER, CallWith=ScriptExecutionContext] FetchEvent createBeingDispatchedFetchEvent();
     [Conditional=SERVICE_WORKER] Promise<boolean> hasServiceWorkerRegistration(DOMString scopeURL);
+    [Conditional=SERVICE_WORKER] void terminateServiceWorker(ServiceWorker worker);
 
     [EnabledAtRuntime=WebAnimations] DOMString timelineDescription(AnimationTimeline timeline);
     [EnabledAtRuntime=WebAnimations] void pauseTimeline(AnimationTimeline timeline);
index 3e0c496..59b6bb6 100644 (file)
@@ -73,6 +73,7 @@ public:
     virtual void postMessageToServiceWorkerGlobalScope(ServiceWorkerIdentifier destinationIdentifier, Ref<SerializedScriptValue>&&, DocumentIdentifier sourceContextIdentifier, ServiceWorkerClientData&& source) = 0;
     virtual SWServerConnectionIdentifier serverConnectionIdentifier() const = 0;
     virtual bool mayHaveServiceWorkerRegisteredForOrigin(const SecurityOrigin&) const = 0;
+    virtual void syncTerminateWorker(ServiceWorkerIdentifier) = 0;
 
     virtual void serviceWorkerStartedControllingClient(ServiceWorkerIdentifier, ServiceWorkerRegistrationIdentifier, DocumentIdentifier) = 0;
     virtual void serviceWorkerStoppedControllingClient(ServiceWorkerIdentifier, ServiceWorkerRegistrationIdentifier, DocumentIdentifier) = 0;
index 2f3c447..dbc0373 100644 (file)
@@ -31,7 +31,8 @@
     SecureContext,
     Exposed=(Window,ServiceWorker),
     Conditional=SERVICE_WORKER,
-    EnabledAtRuntime=ServiceWorker
+    EnabledAtRuntime=ServiceWorker,
+    ExportMacro=WEBCORE_EXPORT
 ] interface ServiceWorker : EventTarget {
     readonly attribute USVString scriptURL;
     readonly attribute ServiceWorkerState state;
index 1375d3d..ad3a570 100644 (file)
@@ -69,8 +69,8 @@ ServiceWorkerThreadProxy* SWContextManager::serviceWorkerThreadProxy(ServiceWork
 void SWContextManager::postMessageToServiceWorkerGlobalScope(ServiceWorkerIdentifier destination, Ref<SerializedScriptValue>&& message, ServiceWorkerClientIdentifier sourceIdentifier, ServiceWorkerClientData&& sourceData)
 {
     auto* serviceWorker = m_workerMap.get(destination);
-    if (!serviceWorker)
-        return;
+    ASSERT(serviceWorker);
+    ASSERT(!serviceWorker->isTerminatingOrTerminated());
 
     // FIXME: We should pass valid MessagePortChannels.
     serviceWorker->thread().postMessageToServiceWorkerGlobalScope(WTFMove(message), nullptr, sourceIdentifier, WTFMove(sourceData));
@@ -94,15 +94,27 @@ void SWContextManager::fireActivateEvent(ServiceWorkerIdentifier identifier)
     serviceWorker->thread().fireActivateEvent();
 }
 
-void SWContextManager::terminateWorker(ServiceWorkerIdentifier identifier)
+void SWContextManager::terminateWorker(ServiceWorkerIdentifier identifier, Function<void()>&& completionHandler)
 {
     auto* serviceWorker = m_workerMap.get(identifier);
     if (!serviceWorker)
         return;
 
-    serviceWorker->thread().stop([identifier] {
+    serviceWorker->setTerminatingOrTerminated(true);
+
+    serviceWorker->thread().stop([this, identifier, completionHandler = WTFMove(completionHandler)] {
         if (auto* connection = SWContextManager::singleton().connection())
             connection->workerTerminated(identifier);
+
+        if (completionHandler)
+            completionHandler();
+        
+        auto worker = m_workerMap.take(identifier);
+        ASSERT(worker);
+        
+        // Spin the runloop before releasing the worker thread proxy, as there would otherwise be
+        // a race towards its destruction.
+        callOnMainThread([worker = WTFMove(worker)] { });
     });
 }
 
index e2f0e9e..1713115 100644 (file)
@@ -61,7 +61,7 @@ public:
     WEBCORE_EXPORT void postMessageToServiceWorkerGlobalScope(ServiceWorkerIdentifier destination, Ref<SerializedScriptValue>&& message, ServiceWorkerClientIdentifier sourceIdentifier, ServiceWorkerClientData&& sourceData);
     WEBCORE_EXPORT void fireInstallEvent(ServiceWorkerIdentifier);
     WEBCORE_EXPORT void fireActivateEvent(ServiceWorkerIdentifier);
-    WEBCORE_EXPORT void terminateWorker(ServiceWorkerIdentifier);
+    WEBCORE_EXPORT void terminateWorker(ServiceWorkerIdentifier, Function<void()>&&);
 
     void forEachServiceWorkerThread(const WTF::Function<void(ServiceWorkerThreadProxy&)>&);
 
index 1272b24..030dcf1 100644 (file)
@@ -56,6 +56,9 @@ public:
     ServiceWorkerThread& thread() { return m_serviceWorkerThread.get(); }
     ServiceWorkerInspectorProxy& inspectorProxy() { return m_inspectorProxy; }
 
+    bool isTerminatingOrTerminated() const { return m_isTerminatingOrTerminated; }
+    void setTerminatingOrTerminated(bool terminating) { m_isTerminatingOrTerminated = terminating; }
+
 private:
     WEBCORE_EXPORT ServiceWorkerThreadProxy(PageConfiguration&&, const ServiceWorkerContextData&, PAL::SessionID, CacheStorageProvider&);
 
@@ -74,6 +77,8 @@ private:
     CacheStorageProvider& m_cacheStorageProvider;
     RefPtr<CacheStorageConnection> m_cacheStorageConnection;
     PAL::SessionID m_sessionID;
+    bool m_isTerminatingOrTerminated { false };
+
     ServiceWorkerInspectorProxy m_inspectorProxy;
 #if ENABLE(REMOTE_INSPECTOR)
     std::unique_ptr<ServiceWorkerDebuggable> m_remoteDebuggable;
index 6d56488..d77453b 100644 (file)
@@ -87,6 +87,13 @@ SWServer::~SWServer()
     allServers().remove(this);
 }
 
+SWServerWorker* SWServer::workerByID(ServiceWorkerIdentifier identifier) const
+{
+    auto* worker = SWServerWorker::existingWorkerForIdentifier(identifier);
+    ASSERT(!worker || &worker->server() == this);
+    return worker;
+}
+
 SWServerRegistration* SWServer::getRegistration(const ServiceWorkerRegistrationKey& registrationKey)
 {
     return m_registrations.get(registrationKey);
@@ -188,6 +195,12 @@ void SWServer::Connection::serviceWorkerStoppedControllingClient(ServiceWorkerId
     m_server.serviceWorkerStoppedControllingClient(*this, serviceWorkerIdentifier, registrationIdentifier, contextIdentifier);
 }
 
+void SWServer::Connection::syncTerminateWorker(ServiceWorkerIdentifier identifier)
+{
+    if (auto* worker = m_server.workerByID(identifier))
+        m_server.syncTerminateWorker(*worker);
+}
+
 SWServer::SWServer(UniqueRef<SWOriginStore>&& originStore)
     : m_originStore(WTFMove(originStore))
 {
@@ -299,12 +312,6 @@ void SWServer::didFinishActivation(SWServerWorker& worker)
         SWServerJobQueue::didFinishActivation(*registration, worker.identifier());
 }
 
-void SWServer::workerContextTerminated(SWServerWorker& worker)
-{
-    auto result = m_workersByID.remove(worker.identifier());
-    ASSERT_UNUSED(result, result);
-}
-
 void SWServer::didResolveRegistrationPromise(Connection& connection, const ServiceWorkerRegistrationKey& registrationKey)
 {
     ASSERT_UNUSED(connection, m_connections.contains(connection.identifier()));
@@ -387,20 +394,83 @@ void SWServer::installContextData(const ServiceWorkerContextData& data)
     auto* registration = m_registrations.get(data.registration.key);
     RELEASE_ASSERT(registration);
 
-    auto result = m_workersByID.add(data.serviceWorkerIdentifier, SWServerWorker::create(*this, *registration, connection->identifier(), data.scriptURL, data.script, data.workerType, data.serviceWorkerIdentifier));
-    ASSERT_UNUSED(result, result.isNewEntry);
+    auto result = m_runningOrTerminatingWorkers.add(data.serviceWorkerIdentifier, SWServerWorker::create(*this, *registration, connection->identifier(), data.scriptURL, data.script, data.workerType, data.serviceWorkerIdentifier));
+    ASSERT(result.isNewEntry);
+
+    result.iterator->value->setState(SWServerWorker::State::Running);
 
     connection->installServiceWorkerContext(data);
 }
 
+bool SWServer::invokeRunServiceWorker(ServiceWorkerIdentifier identifier)
+{
+    if (auto* worker = m_runningOrTerminatingWorkers.get(identifier)) {
+        if (worker->isRunning())
+            return true;
+    }
+
+    // Nobody should have a ServiceWorkerIdentifier for a SWServerWorker that doesn't exist.
+    auto* worker = workerByID(identifier);
+    ASSERT(worker);
+
+    // If the registration for a working has been removed then the request to run
+    // the worker is moot.
+    if (!getRegistration(worker->registrationKey()))
+        return false;
+
+    m_runningOrTerminatingWorkers.add(identifier, *worker);
+    worker->setState(SWServerWorker::State::Running);
+
+    auto* connection = SWServerToContextConnection::globalServerToContextConnection();
+    ASSERT(connection);
+    connection->installServiceWorkerContext(worker->contextData());
+    
+    return true;
+}
 
 void SWServer::terminateWorker(SWServerWorker& worker)
 {
+    terminateWorkerInternal(worker, Asynchronous);
+}
+
+void SWServer::syncTerminateWorker(SWServerWorker& worker)
+{
+    terminateWorkerInternal(worker, Synchronous);
+}
+
+void SWServer::terminateWorkerInternal(SWServerWorker& worker, TerminationMode mode)
+{
     auto* connection = SWServerToContextConnection::connectionForIdentifier(worker.contextConnectionIdentifier());
-    if (connection)
-        connection->terminateWorker(worker.identifier());
-    else
+    if (!connection) {
         LOG_ERROR("Request to terminate a worker whose context connection does not exist");
+        return;
+    }
+
+    ASSERT(m_runningOrTerminatingWorkers.get(worker.identifier()) == &worker);
+    ASSERT(!worker.isTerminating());
+
+    worker.setState(SWServerWorker::State::Terminating);
+
+    switch (mode) {
+    case Asynchronous:
+        connection->terminateWorker(worker.identifier());
+        break;
+    case Synchronous:
+        connection->syncTerminateWorker(worker.identifier());
+        break;
+    };
+}
+
+void SWServer::workerContextTerminated(SWServerWorker& worker)
+{
+    ASSERT(worker.isTerminating());
+
+    worker.setState(SWServerWorker::State::NotRunning);
+
+    // At this point if no registrations are referencing the worker then it will be destroyed,
+    // removing itself from the m_workersByID map.
+    auto result = m_runningOrTerminatingWorkers.take(worker.identifier());
+    ASSERT_UNUSED(result, result && result->ptr() == &worker);
 }
 
 void SWServer::fireInstallEvent(SWServerWorker& worker)
index b8ede17..cab8631 100644 (file)
@@ -90,6 +90,7 @@ public:
         WEBCORE_EXPORT void removeServiceWorkerRegistrationInServer(ServiceWorkerRegistrationIdentifier);
         WEBCORE_EXPORT void serviceWorkerStartedControllingClient(ServiceWorkerIdentifier, ServiceWorkerRegistrationIdentifier, DocumentIdentifier);
         WEBCORE_EXPORT void serviceWorkerStoppedControllingClient(ServiceWorkerIdentifier, ServiceWorkerRegistrationIdentifier, DocumentIdentifier);
+        WEBCORE_EXPORT void syncTerminateWorker(ServiceWorkerIdentifier);
 
     private:
         // Messages to the client WebProcess
@@ -108,7 +109,6 @@ public:
     WEBCORE_EXPORT void clearAll();
     WEBCORE_EXPORT void clear(const SecurityOrigin&);
 
-
     SWServerRegistration* getRegistration(const ServiceWorkerRegistrationKey&);
     void addRegistration(std::unique_ptr<SWServerRegistration>&&);
     void removeRegistration(const ServiceWorkerRegistrationKey&);
@@ -125,9 +125,10 @@ public:
 
     void updateWorker(Connection&, const ServiceWorkerJobDataIdentifier&, SWServerRegistration&, const URL&, const String& script, WorkerType);
     void terminateWorker(SWServerWorker&);
+    void syncTerminateWorker(SWServerWorker&);
     void fireInstallEvent(SWServerWorker&);
     void fireActivateEvent(SWServerWorker&);
-    SWServerWorker* workerByID(ServiceWorkerIdentifier identifier) const { return m_workersByID.get(identifier); }
+    WEBCORE_EXPORT SWServerWorker* workerByID(ServiceWorkerIdentifier) const;
     
     Connection* getConnection(SWServerConnectionIdentifier identifier) { return m_connections.get(identifier); }
     SWOriginStore& originStore() { return m_originStore; }
@@ -145,6 +146,8 @@ public:
     WEBCORE_EXPORT void registerServiceWorkerClient(ClientOrigin&&, ServiceWorkerClientIdentifier, ServiceWorkerClientData&&);
     WEBCORE_EXPORT void unregisterServiceWorkerClient(const ClientOrigin&, ServiceWorkerClientIdentifier);
 
+    WEBCORE_EXPORT bool invokeRunServiceWorker(ServiceWorkerIdentifier);
+
 private:
     void registerConnection(Connection&);
     void unregisterConnection(Connection&);
@@ -165,12 +168,18 @@ private:
 
     void installContextData(const ServiceWorkerContextData&);
 
+    enum TerminationMode {
+        Synchronous,
+        Asynchronous,
+    };
+    void terminateWorkerInternal(SWServerWorker&, TerminationMode);
+
     HashMap<SWServerConnectionIdentifier, Connection*> m_connections;
     HashMap<ServiceWorkerRegistrationKey, std::unique_ptr<SWServerRegistration>> m_registrations;
     HashMap<ServiceWorkerRegistrationIdentifier, SWServerRegistration*> m_registrationsByID;
     HashMap<ServiceWorkerRegistrationKey, std::unique_ptr<SWServerJobQueue>> m_jobQueues;
 
-    HashMap<ServiceWorkerIdentifier, Ref<SWServerWorker>> m_workersByID;
+    HashMap<ServiceWorkerIdentifier, Ref<SWServerWorker>> m_runningOrTerminatingWorkers;
 
     struct ClientInformation {
         ServiceWorkerClientIdentifier identifier;
index 5db8d0a..1a1a7f6 100644 (file)
@@ -48,6 +48,7 @@ public:
     virtual void fireInstallEvent(ServiceWorkerIdentifier) = 0;
     virtual void fireActivateEvent(ServiceWorkerIdentifier) = 0;
     virtual void terminateWorker(ServiceWorkerIdentifier) = 0;
+    virtual void syncTerminateWorker(ServiceWorkerIdentifier) = 0;
 
     // Messages back from the SW host process
     WEBCORE_EXPORT void scriptContextFailedToStart(const std::optional<ServiceWorkerJobDataIdentifier>&, ServiceWorkerIdentifier, const String& message);
index 1f0b1dc..558cf54 100644 (file)
@@ -60,6 +60,14 @@ SWServerWorker::~SWServerWorker()
     ASSERT_UNUSED(taken, taken == this);
 }
 
+ServiceWorkerContextData SWServerWorker::contextData() const
+{
+    auto* registration = m_server.getRegistration(m_registrationKey);
+    ASSERT(registration);
+
+    return { std::nullopt, registration->data(), m_data.identifier, m_script, m_data.scriptURL, m_data.type };
+}
+
 void SWServerWorker::terminate()
 {
     m_server.terminateWorker(*this);
index ac869b4..7f56d37 100644 (file)
@@ -39,6 +39,7 @@ namespace WebCore {
 class SWServer;
 class SWServerRegistration;
 enum class WorkerType;
+struct ServiceWorkerContextData;
 struct ServiceWorkerJobDataIdentifier;
 
 class SWServerWorker : public RefCounted<SWServerWorker> {
@@ -53,7 +54,16 @@ public:
 
     void terminate();
 
-    SWServer& server();
+    enum class State {
+        Running,
+        Terminating,
+        NotRunning,
+    };
+    bool isRunning() const { return m_state == State::Running; }
+    bool isTerminating() const { return m_state == State::Terminating; }
+    void setState(State state) { m_state = state; }
+
+    SWServer& server() { return m_server; }
     const ServiceWorkerRegistrationKey& registrationKey() const { return m_registrationKey; }
     const URL& scriptURL() const { return m_data.scriptURL; }
     const String& script() const { return m_script; }
@@ -77,6 +87,7 @@ public:
     WEBCORE_EXPORT static SWServerWorker* existingWorkerForIdentifier(ServiceWorkerIdentifier);
 
     const ServiceWorkerData& data() const { return m_data; }
+    ServiceWorkerContextData contextData() const;
 
 private:
     SWServerWorker(SWServer&, SWServerRegistration&, SWServerToContextConnectionIdentifier, const URL&, const String& script, WorkerType, ServiceWorkerIdentifier);
@@ -87,6 +98,7 @@ private:
     ServiceWorkerData m_data;
     String m_script;
     bool m_hasPendingEvents { false };
+    State m_state { State::NotRunning };
 };
 
 } // namespace WebCore
index ee414f3..30b09fd 100644 (file)
@@ -1,3 +1,37 @@
+2017-12-01  Brady Eidson  <beidson@apple.com>
+
+        Add Internals.terminateServiceWorker, and the ability to restart service workers for postMessage.
+        https://bugs.webkit.org/show_bug.cgi?id=180170
+
+        Reviewed by Chris Dumez.
+
+        * StorageProcess/ServiceWorker/WebSWServerConnection.cpp:
+        (WebKit::WebSWServerConnection::startFetch):
+        (WebKit::WebSWServerConnection::postMessageToServiceWorkerGlobalScope):
+        * StorageProcess/ServiceWorker/WebSWServerConnection.h:
+        * StorageProcess/ServiceWorker/WebSWServerConnection.messages.in:
+
+        * StorageProcess/ServiceWorker/WebSWServerToContextConnection.cpp:
+        (WebKit::WebSWServerToContextConnection::syncTerminateWorker):
+        * StorageProcess/ServiceWorker/WebSWServerToContextConnection.h:
+
+        * StorageProcess/StorageToWebProcessConnection.cpp:
+        (WebKit::StorageToWebProcessConnection::didReceiveSyncMessage):
+
+        * WebProcess/Storage/WebSWClientConnection.cpp:
+        (WebKit::WebSWClientConnection::syncTerminateWorker):
+        * WebProcess/Storage/WebSWClientConnection.h:
+
+        * WebProcess/Storage/WebSWContextManagerConnection.cpp:
+        (WebKit::WebSWContextManagerConnection::terminateWorker):
+        (WebKit::WebSWContextManagerConnection::syncTerminateWorker):
+        * WebProcess/Storage/WebSWContextManagerConnection.h:
+        * WebProcess/Storage/WebSWContextManagerConnection.messages.in:
+
+        * WebProcess/Storage/WebToStorageProcessConnection.cpp:
+        (WebKit::WebToStorageProcessConnection::didReceiveSyncMessage):
+        * WebProcess/Storage/WebToStorageProcessConnection.h:
+
 2017-12-01  Youenn Fablet  <youenn@apple.com>
 
         Clear WebSWClientConnection in case storage process IPC connection is closing
index 6546054..4acebf6 100644 (file)
@@ -118,11 +118,22 @@ void WebSWServerConnection::updateWorkerStateInClient(ServiceWorkerIdentifier wo
 
 void WebSWServerConnection::startFetch(uint64_t fetchIdentifier, std::optional<ServiceWorkerIdentifier> serviceWorkerIdentifier, const ResourceRequest& request, const FetchOptions& options, const IPC::FormDataReference& formData)
 {
+    // It's possible this specific worker cannot be re-run (e.g. its registration has been removed)
+    if (serviceWorkerIdentifier && !server().invokeRunServiceWorker(*serviceWorkerIdentifier))
+        return;
+
+    // FIXME: If we don't have a ServiceWorkerIdentifier here then we need to create and run the appropriate Service Worker,
+    // but it's unclear that we have enough information here to do that.
+
     sendToContextProcess(Messages::WebSWContextManagerConnection::StartFetch { identifier(), fetchIdentifier, serviceWorkerIdentifier, request, options, formData });
 }
 
 void WebSWServerConnection::postMessageToServiceWorkerGlobalScope(ServiceWorkerIdentifier destinationServiceWorkerIdentifier, const IPC::DataReference& message, DocumentIdentifier sourceContextIdentifier, ServiceWorkerClientData&& sourceData)
 {
+    // It's possible this specific worker cannot be re-run (e.g. its registration has been removed)
+    if (!server().invokeRunServiceWorker(destinationServiceWorkerIdentifier))
+        return;
+
     ServiceWorkerClientIdentifier sourceIdentifier { identifier(), sourceContextIdentifier };
     sendToContextProcess(Messages::WebSWContextManagerConnection::PostMessageToServiceWorkerGlobalScope { destinationServiceWorkerIdentifier, message, sourceIdentifier, WTFMove(sourceData) });
 }
index bf21bbf..1e6112d 100644 (file)
@@ -54,6 +54,7 @@ public:
 
     void disconnectedFromWebProcess();
     void didReceiveMessage(IPC::Connection&, IPC::Decoder&) final;
+    void didReceiveSyncMessage(IPC::Connection&, IPC::Decoder&, std::unique_ptr<IPC::Encoder>&);
 
     PAL::SessionID sessionID() const { return m_sessionID; }
 
index 722ebc2..c0b93cf 100644 (file)
@@ -40,6 +40,8 @@ messages -> WebSWServerConnection {
     GetRegistrations(uint64_t serviceRegistrationMatchRequestIdentifier, struct WebCore::SecurityOriginData topOrigin, WebCore::URL clientURL)
     RegisterServiceWorkerClient(struct WebCore::SecurityOriginData topOrigin, WebCore::DocumentIdentifier identifier, struct WebCore::ServiceWorkerClientData data)
     UnregisterServiceWorkerClient(WebCore::DocumentIdentifier identifier)
+
+    SyncTerminateWorker(WebCore::ServiceWorkerIdentifier workerIdentifier) -> ()
 }
 
 #endif // ENABLE(SERVICE_WORKER)
index 24e4ada..e5dcee2 100644 (file)
@@ -76,6 +76,11 @@ void WebSWServerToContextConnection::terminateWorker(ServiceWorkerIdentifier ser
     send(Messages::WebSWContextManagerConnection::TerminateWorker(serviceWorkerIdentifier));
 }
 
+void WebSWServerToContextConnection::syncTerminateWorker(ServiceWorkerIdentifier serviceWorkerIdentifier)
+{
+    sendSync(Messages::WebSWContextManagerConnection::SyncTerminateWorker(serviceWorkerIdentifier), Messages::WebSWContextManagerConnection::SyncTerminateWorker::Reply());
+}
+
 } // namespace WebKit
 
 #endif // ENABLE(SERVICE_WORKER)
index b5b8749..6ca0c03 100644 (file)
@@ -59,6 +59,7 @@ private:
     void fireInstallEvent(WebCore::ServiceWorkerIdentifier) final;
     void fireActivateEvent(WebCore::ServiceWorkerIdentifier) final;
     void terminateWorker(WebCore::ServiceWorkerIdentifier) final;
+    void syncTerminateWorker(WebCore::ServiceWorkerIdentifier) final;
 
     Ref<IPC::Connection> m_ipcConnection;
     
index 0cf83ff..7548192 100644 (file)
@@ -108,6 +108,15 @@ void StorageToWebProcessConnection::didReceiveSyncMessage(IPC::Connection& conne
         return;
     }
 
+#if ENABLE(SERVICE_WORKER)
+    if (decoder.messageReceiverName() == Messages::WebSWServerConnection::messageReceiverName()) {
+        auto iterator = m_swConnections.find(makeObjectIdentifier<SWServerConnectionIdentifierType>(decoder.destinationID()));
+        if (iterator != m_swConnections.end())
+            iterator->value->didReceiveSyncMessage(connection, decoder, replyEncoder);
+        return;
+    }
+#endif
+
     ASSERT_NOT_REACHED();
 }
 
index 0388e82..aa303b1 100644 (file)
@@ -190,6 +190,11 @@ void WebSWClientConnection::connectionToServerLost()
     clearPendingJobs();
 }
 
+void WebSWClientConnection::syncTerminateWorker(ServiceWorkerIdentifier identifier)
+{
+    sendSync(Messages::WebSWServerConnection::SyncTerminateWorker(identifier), Messages::WebSWServerConnection::SyncTerminateWorker::Reply());
+}
+
 } // namespace WebKit
 
 #endif // ENABLE(SERVICE_WORKER)
index 1fd2060..9176ab7 100644 (file)
@@ -66,6 +66,8 @@ public:
 
     void connectionToServerLost();
 
+    void syncTerminateWorker(WebCore::ServiceWorkerIdentifier) final;
+
 private:
     WebSWClientConnection(IPC::Connection&, PAL::SessionID);
 
index c0ceda1..5862da5 100644 (file)
@@ -166,7 +166,14 @@ void WebSWContextManagerConnection::fireActivateEvent(ServiceWorkerIdentifier id
 
 void WebSWContextManagerConnection::terminateWorker(ServiceWorkerIdentifier identifier)
 {
-    SWContextManager::singleton().terminateWorker(identifier);
+    SWContextManager::singleton().terminateWorker(identifier, nullptr);
+}
+
+void WebSWContextManagerConnection::syncTerminateWorker(ServiceWorkerIdentifier identifier, Ref<Messages::WebSWContextManagerConnection::SyncTerminateWorker::DelayedReply>&& reply)
+{
+    SWContextManager::singleton().terminateWorker(identifier, [reply = WTFMove(reply)] {
+        reply->send();
+    });
 }
 
 void WebSWContextManagerConnection::postMessageToServiceWorkerClient(const ServiceWorkerClientIdentifier& destinationIdentifier, Ref<SerializedScriptValue>&& message, ServiceWorkerIdentifier sourceIdentifier, const String& sourceOrigin)
index c9e65a4..ec1b029 100644 (file)
@@ -29,6 +29,7 @@
 
 #include "Connection.h"
 #include "MessageReceiver.h"
+#include "WebSWContextManagerConnectionMessages.h"
 #include <WebCore/SWContextManager.h>
 #include <WebCore/ServiceWorkerTypes.h>
 
@@ -51,6 +52,7 @@ public:
     WebSWContextManagerConnection(Ref<IPC::Connection>&&, uint64_t pageID, const WebPreferencesStore&);
 
     void didReceiveMessage(IPC::Connection&, IPC::Decoder&) final;
+    void didReceiveSyncMessage(IPC::Connection&, IPC::Decoder&, std::unique_ptr<IPC::Encoder>&) final;
 
 private:
     void updatePreferences(const WebPreferencesStore&);
@@ -70,6 +72,7 @@ private:
     void fireInstallEvent(WebCore::ServiceWorkerIdentifier);
     void fireActivateEvent(WebCore::ServiceWorkerIdentifier);
     void terminateWorker(WebCore::ServiceWorkerIdentifier);
+    void syncTerminateWorker(WebCore::ServiceWorkerIdentifier, Ref<Messages::WebSWContextManagerConnection::SyncTerminateWorker::DelayedReply>&&);
 
     Ref<IPC::Connection> m_connectionToStorageProcess;
     uint64_t m_pageID { 0 };
index 736fdf5..c8ac7d7 100644 (file)
@@ -29,6 +29,7 @@ messages -> WebSWContextManagerConnection {
     FireInstallEvent(WebCore::ServiceWorkerIdentifier identifier)
     FireActivateEvent(WebCore::ServiceWorkerIdentifier identifier)
     TerminateWorker(WebCore::ServiceWorkerIdentifier identifier)
+    SyncTerminateWorker(WebCore::ServiceWorkerIdentifier identifier) -> () Delayed
 }
 
 #endif
index 9a62492..a4bb3a1 100644 (file)
@@ -86,6 +86,19 @@ void WebToStorageProcessConnection::didReceiveMessage(IPC::Connection& connectio
     ASSERT_NOT_REACHED();
 }
 
+void WebToStorageProcessConnection::didReceiveSyncMessage(IPC::Connection& connection, IPC::Decoder& decoder, std::unique_ptr<IPC::Encoder>& replyEncoder)
+{
+#if ENABLE(SERVICE_WORKER)
+    if (decoder.messageReceiverName() == Messages::WebSWContextManagerConnection::messageReceiverName()) {
+        ASSERT(SWContextManager::singleton().connection());
+        if (auto* contextManagerConnection = SWContextManager::singleton().connection())
+            static_cast<WebSWContextManagerConnection&>(*contextManagerConnection).didReceiveSyncMessage(connection, decoder, replyEncoder);
+        return;
+    }
+#endif
+    ASSERT_NOT_REACHED();
+}
+
 void WebToStorageProcessConnection::didClose(IPC::Connection& connection)
 {
 #if ENABLE(INDEXED_DATABASE)
index 6a486e2..5f7ea3b 100644 (file)
@@ -62,6 +62,7 @@ private:
 
     // IPC::Connection::Client
     void didReceiveMessage(IPC::Connection&, IPC::Decoder&) override;
+    void didReceiveSyncMessage(IPC::Connection&, IPC::Decoder&, std::unique_ptr<IPC::Encoder>&) override;
     void didClose(IPC::Connection&) override;
     void didReceiveInvalidMessage(IPC::Connection&, IPC::StringReference messageReceiverName, IPC::StringReference messageName) override;