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

Changeset 259859 in webkit


Ignore:
Timestamp:
Apr 10, 2020, 3:50:35 AM (6 years ago)
Author:
youenn@apple.com
Message:

SWServer should not run a service worker that is terminating
https://bugs.webkit.org/show_bug.cgi?id=210044

Reviewed by Chris Dumez.

Source/WebCore:

If a test is being terminated and we want to restart it, we were previously running it right away.
This does not work well as the service worker process might still have the terminating service worker in its map.
Also, if the service worker is not able to terminate properly, we will kill the service worker process so there is no reason
to try running this service worker in this process.
Instead, wait for the service worker to terminate (which might include terminating the service worker process).

In addition, we remove the isServiceWorkerRunning internals API since this is potentially flaky as the service worker
might be terminated and rerunning in between two isServiceWorkerRunning checks.
Instead, we introduce whenServiceWorkerIsTerminated which will resolve as soon as the service worker goes to terminated.

Covered by existing spinning tests no longer crashing.

  • testing/Internals.cpp:

(WebCore::Internals::whenServiceWorkerIsTerminated):

  • testing/Internals.h:
  • testing/Internals.idl:
  • workers/service/SWClientConnection.h:

(WebCore::SWClientConnection::whenServiceWorkerIsTerminatedForTesting):

  • workers/service/server/SWServer.cpp:

(WebCore::SWServer::runServiceWorkerIfNecessary):
(WebCore::SWServer::runServiceWorker):
(WebCore::SWServer::workerContextTerminated):

  • workers/service/server/SWServerWorker.cpp:

(WebCore::SWServerWorker::whenTerminated):
(WebCore::SWServerWorker::setState):

  • workers/service/server/SWServerWorker.h:

(WebCore::SWServerWorker::isNotRunning const):

Source/WebKit:

Implement whenServiceWorkerIsTerminated check.

  • NetworkProcess/ServiceWorker/WebSWServerConnection.cpp:

(WebKit::WebSWServerConnection::whenServiceWorkerIsTerminatedForTesting):

  • NetworkProcess/ServiceWorker/WebSWServerConnection.h:
  • NetworkProcess/ServiceWorker/WebSWServerConnection.messages.in:
  • WebProcess/Storage/WebSWClientConnection.cpp:

(WebKit::WebSWClientConnection::whenServiceWorkerIsTerminatedForTesting):

  • WebProcess/Storage/WebSWClientConnection.h:

LayoutTests:

  • http/wpt/service-workers/resources/routines.js:

(async waitForServiceWorkerNoLongerRunning):
Use new internals API.

Location:
trunk
Files:
16 edited

Legend:

Unmodified
Added
Removed
  • trunk/LayoutTests/ChangeLog

    r259850 r259859  
     12020-04-10  Youenn Fablet  <youenn@apple.com>
     2
     3        SWServer should not run a service worker that is terminating
     4        https://bugs.webkit.org/show_bug.cgi?id=210044
     5
     6        Reviewed by Chris Dumez.
     7
     8        * http/wpt/service-workers/resources/routines.js:
     9        (async waitForServiceWorkerNoLongerRunning):
     10        Use new internals API.
     11
    1122020-04-09  Peng Liu  <peng.liu6@apple.com>
    213
  • trunk/LayoutTests/http/wpt/service-workers/resources/routines.js

    r253898 r259859  
    3434        return Promise.reject("requires internals");
    3535
    36     let count = 100;
    37     while (--count > 0 && await internals.isServiceWorkerRunning(worker)) {
    38         worker.postMessage("test");
    39         await new Promise(resolve => setTimeout(resolve, 50));
    40     }
    41     if (count === 0)
    42         return Promise.reject("service worker is still running");
     36    const promise = internals.whenServiceWorkerIsTerminated(worker);
     37    let timer = setInterval(() => worker.postMessage("test"), 50);
     38    await promise;
     39    clearInterval(timer);
    4340}
  • trunk/Source/WebCore/ChangeLog

    r259858 r259859  
     12020-04-10  Youenn Fablet  <youenn@apple.com>
     2
     3        SWServer should not run a service worker that is terminating
     4        https://bugs.webkit.org/show_bug.cgi?id=210044
     5
     6        Reviewed by Chris Dumez.
     7
     8        If a test is being terminated and we want to restart it, we were previously running it right away.
     9        This does not work well as the service worker process might still have the terminating service worker in its map.
     10        Also, if the service worker is not able to terminate properly, we will kill the service worker process so there is no reason
     11        to try running this service worker in this process.
     12        Instead, wait for the service worker to terminate (which might include terminating the service worker process).
     13
     14        In addition, we remove the isServiceWorkerRunning internals API since this is potentially flaky as the service worker
     15        might be terminated and rerunning in between two isServiceWorkerRunning checks.
     16        Instead, we introduce whenServiceWorkerIsTerminated which will resolve as soon as the service worker goes to terminated.
     17
     18        Covered by existing spinning tests no longer crashing.
     19
     20        * testing/Internals.cpp:
     21        (WebCore::Internals::whenServiceWorkerIsTerminated):
     22        * testing/Internals.h:
     23        * testing/Internals.idl:
     24        * workers/service/SWClientConnection.h:
     25        (WebCore::SWClientConnection::whenServiceWorkerIsTerminatedForTesting):
     26        * workers/service/server/SWServer.cpp:
     27        (WebCore::SWServer::runServiceWorkerIfNecessary):
     28        (WebCore::SWServer::runServiceWorker):
     29        (WebCore::SWServer::workerContextTerminated):
     30        * workers/service/server/SWServerWorker.cpp:
     31        (WebCore::SWServerWorker::whenTerminated):
     32        (WebCore::SWServerWorker::setState):
     33        * workers/service/server/SWServerWorker.h:
     34        (WebCore::SWServerWorker::isNotRunning const):
     35
    1362020-04-10  Charlie Turner  <cturner@igalia.com>
    237
  • trunk/Source/WebCore/testing/Internals.cpp

    r259824 r259859  
    51455145}
    51465146
    5147 void Internals::isServiceWorkerRunning(ServiceWorker& worker, DOMPromiseDeferred<IDLBoolean>&& promise)
    5148 {
    5149     return ServiceWorkerProvider::singleton().serviceWorkerConnection().isServiceWorkerRunning(worker.identifier(), [promise = WTFMove(promise)](bool result) mutable {
    5150         promise.resolve(result);
     5147void Internals::whenServiceWorkerIsTerminated(ServiceWorker& worker, DOMPromiseDeferred<void>&& promise)
     5148{
     5149    return ServiceWorkerProvider::singleton().serviceWorkerConnection().whenServiceWorkerIsTerminatedForTesting(worker.identifier(), [promise = WTFMove(promise)]() mutable {
     5150        promise.resolve();
    51515151    });
    51525152}
  • trunk/Source/WebCore/testing/Internals.h

    r259824 r259859  
    785785    void hasServiceWorkerRegistration(const String& clientURL, HasRegistrationPromise&&);
    786786    void terminateServiceWorker(ServiceWorker&, DOMPromiseDeferred<void>&&);
    787     void isServiceWorkerRunning(ServiceWorker&, DOMPromiseDeferred<IDLBoolean>&&);
     787    void whenServiceWorkerIsTerminated(ServiceWorker&, DOMPromiseDeferred<void>&&);
    788788#endif
    789789
  • trunk/Source/WebCore/testing/Internals.idl

    r259575 r259859  
    771771    [Conditional=SERVICE_WORKER] Promise<boolean> hasServiceWorkerRegistration(DOMString scopeURL);
    772772    [Conditional=SERVICE_WORKER] Promise<void> terminateServiceWorker(ServiceWorker worker);
    773     [Conditional=SERVICE_WORKER] Promise<boolean> isServiceWorkerRunning(ServiceWorker worker);
     773    [Conditional=SERVICE_WORKER] Promise<void> whenServiceWorkerIsTerminated(ServiceWorker worker);
    774774
    775775    [CallWith=Document, Conditional=APPLE_PAY] readonly attribute MockPaymentCoordinator mockPaymentCoordinator;
  • trunk/Source/WebCore/workers/service/SWClientConnection.h

    r259383 r259859  
    8787
    8888    virtual void storeRegistrationsOnDiskForTesting(CompletionHandler<void()>&& callback) { callback(); }
    89     virtual void isServiceWorkerRunning(ServiceWorkerIdentifier, CompletionHandler<void(bool)>&& callback) { callback(false); }
     89    virtual void whenServiceWorkerIsTerminatedForTesting(ServiceWorkerIdentifier, CompletionHandler<void()>&& callback) { callback(); }
    9090
    9191    WEBCORE_EXPORT void registerServiceWorkerClients();
  • trunk/Source/WebCore/workers/service/server/SWServer.cpp

    r259383 r259859  
    686686    }
    687687
     688    if (worker->isTerminating()) {
     689        worker->whenTerminated([this, weakThis = makeWeakPtr(this), identifier, callback = WTFMove(callback)]() mutable {
     690            if (!weakThis)
     691                return callback(nullptr);
     692            runServiceWorkerIfNecessary(identifier, WTFMove(callback));
     693        });
     694        return;
     695    }
     696
    688697    if (!contextConnection) {
    689698        auto& serviceWorkerRunRequestsForOrigin = m_serviceWorkerRunRequests.ensure(worker->registrableDomain(), [] {
     
    713722        return false;
    714723
    715     auto addResult = m_runningOrTerminatingWorkers.add(identifier, *worker);
    716     ASSERT_UNUSED(addResult, addResult.isNewEntry || worker->isTerminating());
     724    ASSERT(!worker->isTerminating());
     725    ASSERT(!m_runningOrTerminatingWorkers.contains(identifier));
     726    m_runningOrTerminatingWorkers.add(identifier, *worker);
    717727
    718728    worker->setState(SWServerWorker::State::Running);
     
    739749void SWServer::workerContextTerminated(SWServerWorker& worker)
    740750{
    741     worker.setState(SWServerWorker::State::NotRunning);
    742 
    743     if (auto* jobQueue = m_jobQueues.get(worker.registrationKey()))
    744         jobQueue->cancelJobsFromServiceWorker(worker.identifier());
    745 
    746751    // At this point if no registrations are referencing the worker then it will be destroyed,
    747752    // removing itself from the m_workersByID map.
    748753    auto result = m_runningOrTerminatingWorkers.take(worker.identifier());
    749754    ASSERT_UNUSED(result, result && result->ptr() == &worker);
     755
     756    worker.setState(SWServerWorker::State::NotRunning);
     757
     758    if (auto* jobQueue = m_jobQueues.get(worker.registrationKey()))
     759        jobQueue->cancelJobsFromServiceWorker(worker.identifier());
    750760}
    751761
  • trunk/Source/WebCore/workers/service/server/SWServerWorker.cpp

    r259383 r259859  
    105105}
    106106
     107void SWServerWorker::whenTerminated(CompletionHandler<void()>&& callback)
     108{
     109    ASSERT(isRunning() || isTerminating());
     110    m_terminationCallbacks.append(WTFMove(callback));
     111}
     112
    107113void SWServerWorker::startTermination(CompletionHandler<void()>&& callback)
    108114{
     
    297303{
    298304    ASSERT(state != State::Running || m_registration);
     305    ASSERT(state != State::Running || m_state != State::Terminating);
    299306    m_state = state;
    300307
  • trunk/Source/WebCore/workers/service/server/SWServerWorker.h

    r259383 r259859  
    6464
    6565    WEBCORE_EXPORT void terminate(CompletionHandler<void()>&& = [] { });
     66    WEBCORE_EXPORT void whenTerminated(CompletionHandler<void()>&&);
    6667
    6768    WEBCORE_EXPORT void whenActivated(CompletionHandler<void(bool)>&&);
     
    7475    bool isRunning() const { return m_state == State::Running; }
    7576    bool isTerminating() const { return m_state == State::Terminating; }
     77    bool isNotRunning() const { return m_state == State::NotRunning; }
    7678    void setState(State);
    7779
  • trunk/Source/WebKit/ChangeLog

    r259857 r259859  
     12020-04-10  Youenn Fablet  <youenn@apple.com>
     2
     3        SWServer should not run a service worker that is terminating
     4        https://bugs.webkit.org/show_bug.cgi?id=210044
     5
     6        Reviewed by Chris Dumez.
     7
     8        Implement whenServiceWorkerIsTerminated check.
     9
     10        * NetworkProcess/ServiceWorker/WebSWServerConnection.cpp:
     11        (WebKit::WebSWServerConnection::whenServiceWorkerIsTerminatedForTesting):
     12        * NetworkProcess/ServiceWorker/WebSWServerConnection.h:
     13        * NetworkProcess/ServiceWorker/WebSWServerConnection.messages.in:
     14        * WebProcess/Storage/WebSWClientConnection.cpp:
     15        (WebKit::WebSWClientConnection::whenServiceWorkerIsTerminatedForTesting):
     16        * WebProcess/Storage/WebSWClientConnection.h:
     17
    1182020-04-10  Commit Queue  <commit-queue@webkit.org>
    219
  • trunk/Source/WebKit/NetworkProcess/ServiceWorker/WebSWServerConnection.cpp

    r259383 r259859  
    465465}
    466466
    467 void WebSWServerConnection::isServiceWorkerRunning(ServiceWorkerIdentifier identifier, CompletionHandler<void(bool)>&& completionHandler)
     467void WebSWServerConnection::whenServiceWorkerIsTerminatedForTesting(WebCore::ServiceWorkerIdentifier identifier, CompletionHandler<void()>&& completionHandler)
    468468{
    469469    auto* worker = SWServerWorker::existingWorkerForIdentifier(identifier);
    470     completionHandler(worker ? worker->isRunning() : false);
     470    if (!worker || worker->isNotRunning())
     471        return completionHandler();
     472    worker->whenTerminated(WTFMove(completionHandler));
    471473}
    472474
  • trunk/Source/WebKit/NetworkProcess/ServiceWorker/WebSWServerConnection.h

    r259383 r259859  
    104104    void unregisterServiceWorkerClient(const WebCore::ServiceWorkerClientIdentifier&);
    105105    void terminateWorkerFromClient(WebCore::ServiceWorkerIdentifier, CompletionHandler<void()>&&);
    106     void isServiceWorkerRunning(WebCore::ServiceWorkerIdentifier, CompletionHandler<void(bool)>&&);
     106    void whenServiceWorkerIsTerminatedForTesting(WebCore::ServiceWorkerIdentifier, CompletionHandler<void()>&&);
    107107
    108108    void postMessageToServiceWorkerClient(WebCore::DocumentIdentifier destinationContextIdentifier, const WebCore::MessageWithMessagePorts&, WebCore::ServiceWorkerIdentifier sourceServiceWorkerIdentifier, const String& sourceOrigin) final;
  • trunk/Source/WebKit/NetworkProcess/ServiceWorker/WebSWServerConnection.messages.in

    r259383 r259859  
    4343
    4444    TerminateWorkerFromClient(WebCore::ServiceWorkerIdentifier workerIdentifier) -> () Async
     45    WhenServiceWorkerIsTerminatedForTesting(WebCore::ServiceWorkerIdentifier workerIdentifier) -> () Async
    4546
    4647    SetThrottleState(bool isThrottleable)
    4748    StoreRegistrationsOnDisk() -> () Async
    48     IsServiceWorkerRunning(WebCore::ServiceWorkerIdentifier workerIdentifier) -> (bool isRunning) Async
    4949}
    5050
  • trunk/Source/WebKit/WebProcess/Storage/WebSWClientConnection.cpp

    r259383 r259859  
    249249}
    250250
    251 void WebSWClientConnection::isServiceWorkerRunning(ServiceWorkerIdentifier identifier, CompletionHandler<void(bool)>&& callback)
    252 {
    253     sendWithAsyncReply(Messages::WebSWServerConnection::IsServiceWorkerRunning { identifier }, WTFMove(callback));
     251void WebSWClientConnection::whenServiceWorkerIsTerminatedForTesting(ServiceWorkerIdentifier identifier, CompletionHandler<void()>&& callback)
     252{
     253    sendWithAsyncReply(Messages::WebSWServerConnection::WhenServiceWorkerIsTerminatedForTesting { identifier }, WTFMove(callback));
    254254}
    255255
  • trunk/Source/WebKit/WebProcess/Storage/WebSWClientConnection.h

    r259383 r259859  
    8787
    8888    void getRegistrations(WebCore::SecurityOriginData&& topOrigin, const URL& clientURL, GetRegistrationsCallback&&) final;
    89     void isServiceWorkerRunning(WebCore::ServiceWorkerIdentifier, CompletionHandler<void(bool)>&&) final;
     89    void whenServiceWorkerIsTerminatedForTesting(WebCore::ServiceWorkerIdentifier, CompletionHandler<void()>&&) final;
    9090
    9191    void didResolveRegistrationPromise(const WebCore::ServiceWorkerRegistrationKey&) final;
Note: See TracChangeset for help on using the changeset viewer.