1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
3 /* This Source Code Form is subject to the terms of the Mozilla Public
4  * License, v. 2.0. If a copy of the MPL was not distributed with this
5  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
6 
7 #include "ServiceWorkerJobQueue.h"
8 
9 #include "nsThreadUtils.h"
10 #include "ServiceWorkerJob.h"
11 #include "mozilla/dom/WorkerCommon.h"
12 
13 namespace mozilla {
14 namespace dom {
15 
16 class ServiceWorkerJobQueue::Callback final
17     : public ServiceWorkerJob::Callback {
18   RefPtr<ServiceWorkerJobQueue> mQueue;
19 
20   ~Callback() = default;
21 
22  public:
Callback(ServiceWorkerJobQueue * aQueue)23   explicit Callback(ServiceWorkerJobQueue* aQueue) : mQueue(aQueue) {
24     MOZ_ASSERT(NS_IsMainThread());
25     MOZ_ASSERT(mQueue);
26   }
27 
JobFinished(ServiceWorkerJob * aJob,ErrorResult & aStatus)28   virtual void JobFinished(ServiceWorkerJob* aJob,
29                            ErrorResult& aStatus) override {
30     MOZ_ASSERT(NS_IsMainThread());
31     mQueue->JobFinished(aJob);
32   }
33 
JobDiscarded(ErrorResult &)34   virtual void JobDiscarded(ErrorResult&) override {
35     // no-op; nothing to do.
36   }
37 
38   NS_INLINE_DECL_REFCOUNTING(ServiceWorkerJobQueue::Callback, override)
39 };
40 
~ServiceWorkerJobQueue()41 ServiceWorkerJobQueue::~ServiceWorkerJobQueue() {
42   MOZ_ASSERT(NS_IsMainThread());
43   MOZ_ASSERT(mJobList.IsEmpty());
44 }
45 
JobFinished(ServiceWorkerJob * aJob)46 void ServiceWorkerJobQueue::JobFinished(ServiceWorkerJob* aJob) {
47   MOZ_ASSERT(NS_IsMainThread());
48   MOZ_ASSERT(aJob);
49 
50   // XXX There are some corner cases where jobs can double-complete.  Until
51   // we track all these down we do a non-fatal assert in debug builds and
52   // a runtime check to verify the queue is in the correct state.
53   NS_ASSERTION(!mJobList.IsEmpty(),
54                "Job queue should contain the job that just completed.");
55   NS_ASSERTION(mJobList.SafeElementAt(0, nullptr) == aJob,
56                "Job queue should contain the job that just completed.");
57   if (NS_WARN_IF(mJobList.SafeElementAt(0, nullptr) != aJob)) {
58     return;
59   }
60 
61   mJobList.RemoveElementAt(0);
62 
63   if (mJobList.IsEmpty()) {
64     return;
65   }
66 
67   RunJob();
68 }
69 
RunJob()70 void ServiceWorkerJobQueue::RunJob() {
71   MOZ_ASSERT(NS_IsMainThread());
72   MOZ_ASSERT(!mJobList.IsEmpty());
73   MOZ_ASSERT(mJobList[0]->GetState() == ServiceWorkerJob::State::Initial);
74 
75   RefPtr<Callback> callback = new Callback(this);
76   mJobList[0]->Start(callback);
77 }
78 
ServiceWorkerJobQueue()79 ServiceWorkerJobQueue::ServiceWorkerJobQueue() {
80   MOZ_ASSERT(NS_IsMainThread());
81 }
82 
ScheduleJob(ServiceWorkerJob * aJob)83 void ServiceWorkerJobQueue::ScheduleJob(ServiceWorkerJob* aJob) {
84   MOZ_ASSERT(NS_IsMainThread());
85   MOZ_ASSERT(aJob);
86   MOZ_ASSERT(!mJobList.Contains(aJob));
87 
88   if (mJobList.IsEmpty()) {
89     mJobList.AppendElement(aJob);
90     RunJob();
91     return;
92   }
93 
94   MOZ_ASSERT(mJobList[0]->GetState() == ServiceWorkerJob::State::Started);
95 
96   RefPtr<ServiceWorkerJob>& tailJob = mJobList[mJobList.Length() - 1];
97   if (!tailJob->ResultCallbacksInvoked() && aJob->IsEquivalentTo(tailJob)) {
98     tailJob->StealResultCallbacksFrom(aJob);
99     return;
100   }
101 
102   mJobList.AppendElement(aJob);
103 }
104 
CancelAll()105 void ServiceWorkerJobQueue::CancelAll() {
106   MOZ_ASSERT(NS_IsMainThread());
107 
108   for (RefPtr<ServiceWorkerJob>& job : mJobList) {
109     job->Cancel();
110   }
111 
112   // Remove jobs that are queued but not started since they should never
113   // run after being canceled.  This means throwing away all jobs except
114   // for the job at the front of the list.
115   if (!mJobList.IsEmpty()) {
116     MOZ_ASSERT(mJobList[0]->GetState() == ServiceWorkerJob::State::Started);
117     mJobList.TruncateLength(1);
118   }
119 }
120 
121 }  // namespace dom
122 }  // namespace mozilla
123