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

Changeset 242372 in webkit


Ignore:
Timestamp:
Mar 4, 2019, 12:30:58 PM (7 years ago)
Author:
youenn@apple.com
Message:

Make sure to correctly notify of end of a ServiceWorkerJob when the context is stopped
https://bugs.webkit.org/show_bug.cgi?id=195195

Reviewed by Chris Dumez.

Before the patch, we were notifying that some jobs were finished too aggressively at context stop time.
This was confusing the Network Process.
Only notify such jobs that have pending loads.
Improve the tracking of jobs doing registration resolution to ensure the Network Process gets notified
in case of a registration promise being resolved but the settling callback being not yet called while the context is stopped.

Covered by existing tests not crashing anymore, in particular imported/w3c/web-platform-tests/service-workers/service-worker/skip-waiting.https.html.

  • workers/service/ServiceWorkerContainer.cpp:

(WebCore::ServiceWorkerContainer::jobResolvedWithRegistration):
(WebCore::ServiceWorkerContainer::notifyRegistrationIsSettled):
(WebCore::ServiceWorkerContainer::stop):

  • workers/service/ServiceWorkerContainer.h:
  • workers/service/ServiceWorkerJob.cpp:

(WebCore::ServiceWorkerJob::cancelPendingLoad):

  • workers/service/ServiceWorkerJob.h:

(WebCore::ServiceWorkerJob::isLoading const):

Location:
trunk/Source/WebCore
Files:
5 edited

Legend:

Unmodified
Added
Removed
  • trunk/Source/WebCore/ChangeLog

    r242369 r242372  
     12019-03-04  Youenn Fablet  <youenn@apple.com>
     2
     3        Make sure to correctly notify of end of a ServiceWorkerJob when the context is stopped
     4        https://bugs.webkit.org/show_bug.cgi?id=195195
     5
     6        Reviewed by Chris Dumez.
     7
     8        Before the patch, we were notifying that some jobs were finished too aggressively at context stop time.
     9        This was confusing the Network Process.
     10        Only notify such jobs that have pending loads.
     11        Improve the tracking of jobs doing registration resolution to ensure the Network Process gets notified
     12        in case of a registration promise being resolved but the settling callback being not yet called while the context is stopped.
     13
     14        Covered by existing tests not crashing anymore, in particular imported/w3c/web-platform-tests/service-workers/service-worker/skip-waiting.https.html.
     15
     16        * workers/service/ServiceWorkerContainer.cpp:
     17        (WebCore::ServiceWorkerContainer::jobResolvedWithRegistration):
     18        (WebCore::ServiceWorkerContainer::notifyRegistrationIsSettled):
     19        (WebCore::ServiceWorkerContainer::stop):
     20        * workers/service/ServiceWorkerContainer.h:
     21        * workers/service/ServiceWorkerJob.cpp:
     22        (WebCore::ServiceWorkerJob::cancelPendingLoad):
     23        * workers/service/ServiceWorkerJob.h:
     24        (WebCore::ServiceWorkerJob::isLoading const):
     25
    1262019-03-04  Chris Dumez  <cdumez@apple.com>
    227
  • trunk/Source/WebCore/workers/service/ServiceWorkerContainer.cpp

    r240727 r242372  
    422422    ASSERT_WITH_MESSAGE(job.hasPromise() || job.data().type == ServiceWorkerJobType::Update, "Only soft updates have no promise");
    423423
    424     auto guard = WTF::makeScopeExit([this, &job] {
    425         destroyJob(job);
    426     });
    427 
    428424    if (job.data().type == ServiceWorkerJobType::Register)
    429425        CONTAINER_RELEASE_LOG_IF_ALLOWED("jobResolvedWithRegistration: Registration job %" PRIu64 " succeeded", job.identifier().toUInt64());
     
    433429    }
    434430
    435     std::function<void()> notifyWhenResolvedIfNeeded;
    436     if (shouldNotifyWhenResolved == ShouldNotifyWhenResolved::Yes) {
    437         notifyWhenResolvedIfNeeded = [connection = m_swConnection, registrationKey = data.key]() mutable {
    438             callOnMainThread([connection = WTFMove(connection), registrationKey = registrationKey.isolatedCopy()] {
    439                 connection->didResolveRegistrationPromise(registrationKey);
    440             });
    441         };
    442     }
    443 
    444     if (isStopped()) {
    445         if (notifyWhenResolvedIfNeeded)
    446             notifyWhenResolvedIfNeeded();
    447         return;
    448     }
     431    auto guard = WTF::makeScopeExit([this, &job] {
     432        destroyJob(job);
     433    });
     434
     435    auto notifyIfExitEarly = WTF::makeScopeExit([this, &data, &shouldNotifyWhenResolved] {
     436        if (shouldNotifyWhenResolved == ShouldNotifyWhenResolved::Yes)
     437            notifyRegistrationIsSettled(data.key);
     438    });
     439
     440    if (isStopped())
     441        return;
    449442
    450443    auto promise = job.takePromise();
    451     if (!promise) {
    452         if (notifyWhenResolvedIfNeeded)
    453             notifyWhenResolvedIfNeeded();
    454         return;
    455     }
    456 
    457     scriptExecutionContext()->postTask([this, protectedThis = makeRef(*this), promise = WTFMove(promise), jobIdentifier = job.identifier(), data = WTFMove(data), notifyWhenResolvedIfNeeded = WTFMove(notifyWhenResolvedIfNeeded)](ScriptExecutionContext& context) mutable {
     444    if (!promise)
     445        return;
     446
     447    notifyIfExitEarly.release();
     448
     449    scriptExecutionContext()->postTask([this, protectedThis = RefPtr<ServiceWorkerContainer>(this), promise = WTFMove(promise), jobIdentifier = job.identifier(), data = WTFMove(data), shouldNotifyWhenResolved](ScriptExecutionContext& context) mutable {
    458450        if (isStopped() || !context.sessionID().isValid()) {
    459             if (notifyWhenResolvedIfNeeded)
    460                 notifyWhenResolvedIfNeeded();
     451            if (shouldNotifyWhenResolved == ShouldNotifyWhenResolved::Yes)
     452                notifyRegistrationIsSettled(data.key);
    461453            return;
    462454        }
     
    466458        CONTAINER_RELEASE_LOG_IF_ALLOWED("jobResolvedWithRegistration: Resolving promise for job %" PRIu64 ". Registration ID: %" PRIu64, jobIdentifier.toUInt64(), registration->identifier().toUInt64());
    467459
    468         if (notifyWhenResolvedIfNeeded) {
    469             promise->whenSettled([notifyWhenResolvedIfNeeded = WTFMove(notifyWhenResolvedIfNeeded)] {
    470                 notifyWhenResolvedIfNeeded();
     460        if (shouldNotifyWhenResolved == ShouldNotifyWhenResolved::Yes) {
     461            m_ongoingSettledRegistrations.add(++m_lastOngoingSettledRegistrationIdentifier, registration->data().key);
     462            promise->whenSettled([this, protectedThis = WTFMove(protectedThis), identifier = m_lastOngoingSettledRegistrationIdentifier] {
     463                notifyRegistrationIsSettled(m_ongoingSettledRegistrations.take(identifier));
    471464            });
    472465        }
    473466
    474467        promise->resolve<IDLInterface<ServiceWorkerRegistration>>(WTFMove(registration));
     468    });
     469}
     470
     471void ServiceWorkerContainer::notifyRegistrationIsSettled(const ServiceWorkerRegistrationKey& registrationKey)
     472{
     473    callOnMainThread([connection = m_swConnection, registrationKey = registrationKey.isolatedCopy()] {
     474        connection->didResolveRegistrationPromise(registrationKey);
    475475    });
    476476}
     
    640640    auto jobMap = WTFMove(m_jobMap);
    641641    for (auto& ongoingJob : jobMap.values()) {
    642         notifyFailedFetchingScript(*ongoingJob.job.get(), ResourceError { errorDomainWebKitInternal, 0, ongoingJob.job->data().scriptURL, "Job cancelled"_s, ResourceError::Type::Cancellation });
    643         ongoingJob.job->cancelPendingLoad();
    644     }
     642        if (ongoingJob.job->cancelPendingLoad())
     643            notifyFailedFetchingScript(*ongoingJob.job.get(), ResourceError { errorDomainWebKitInternal, 0, ongoingJob.job->data().scriptURL, "Job cancelled"_s, ResourceError::Type::Cancellation });
     644    }
     645
     646    auto registrationMap = WTFMove(m_ongoingSettledRegistrations);
     647    for (auto& registration : registrationMap.values())
     648        notifyRegistrationIsSettled(registration);
    645649}
    646650
  • trunk/Source/WebCore/workers/service/ServiceWorkerContainer.h

    r240727 r242372  
    115115    void stop() final;
    116116
     117    void notifyRegistrationIsSettled(const ServiceWorkerRegistrationKey&);
     118
    117119    std::unique_ptr<ReadyPromise> m_readyPromise;
    118120
     
    146148    uint64_t m_lastPendingPromiseIdentifier { 0 };
    147149    HashMap<uint64_t, std::unique_ptr<PendingPromise>> m_pendingPromises;
     150
     151    uint64_t m_lastOngoingSettledRegistrationIdentifier { 0 };
     152    HashMap<uint64_t, ServiceWorkerRegistrationKey> m_ongoingSettledRegistrations;
     153
    148154};
    149155
  • trunk/Source/WebCore/workers/service/ServiceWorkerJob.cpp

    r240727 r242372  
    167167}
    168168
    169 void ServiceWorkerJob::cancelPendingLoad()
     169bool ServiceWorkerJob::cancelPendingLoad()
    170170{
    171171    if (!m_scriptLoader)
    172         return;
     172        return false;
     173
    173174    m_scriptLoader->cancel();
    174175    m_scriptLoader = nullptr;
     176    return true;
    175177}
    176178
  • trunk/Source/WebCore/workers/service/ServiceWorkerJob.h

    r240727 r242372  
    7070    const DocumentOrWorkerIdentifier& contextIdentifier() { return m_contextIdentifier; }
    7171
    72     void cancelPendingLoad();
     72    bool cancelPendingLoad();
    7373
    7474private:
Note: See TracChangeset for help on using the changeset viewer.