dom/workers/WorkerPrivate.h

branch
TOR_BUG_9701
changeset 14
925c144e1f1f
equal deleted inserted replaced
-1:000000000000 0:233b3f8b6e26
1 /* -*- Mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 40 -*- */
2 /* This Source Code Form is subject to the terms of the Mozilla Public
3 * License, v. 2.0. If a copy of the MPL was not distributed with this
4 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
5
6 #ifndef mozilla_dom_workers_workerprivate_h__
7 #define mozilla_dom_workers_workerprivate_h__
8
9 #include "Workers.h"
10
11 #include "nsIContentSecurityPolicy.h"
12 #include "nsPIDOMWindow.h"
13
14 #include "mozilla/CondVar.h"
15 #include "mozilla/DOMEventTargetHelper.h"
16 #include "mozilla/TimeStamp.h"
17 #include "mozilla/dom/BindingDeclarations.h"
18 #include "nsCycleCollectionParticipant.h"
19 #include "nsDataHashtable.h"
20 #include "nsHashKeys.h"
21 #include "nsRefPtrHashtable.h"
22 #include "nsString.h"
23 #include "nsTArray.h"
24 #include "nsThreadUtils.h"
25 #include "StructuredCloneTags.h"
26
27 #include "Queue.h"
28 #include "WorkerFeature.h"
29
30 class JSAutoStructuredCloneBuffer;
31 class nsIChannel;
32 class nsIDocument;
33 class nsIEventTarget;
34 class nsIPrincipal;
35 class nsIScriptContext;
36 class nsIThread;
37 class nsIThreadInternal;
38 class nsITimer;
39 class nsIURI;
40
41 namespace JS {
42 class RuntimeStats;
43 }
44
45 namespace mozilla {
46 namespace dom {
47 class Function;
48 }
49 }
50
51 #ifdef DEBUG
52 struct PRThread;
53 #endif
54
55 BEGIN_WORKERS_NAMESPACE
56
57 class AutoSyncLoopHolder;
58 class MessagePort;
59 class SharedWorker;
60 class WorkerControlRunnable;
61 class WorkerGlobalScope;
62 class WorkerPrivate;
63 class WorkerRunnable;
64
65 // SharedMutex is a small wrapper around an (internal) reference-counted Mutex
66 // object. It exists to avoid changing a lot of code to use Mutex* instead of
67 // Mutex&.
68 class SharedMutex
69 {
70 typedef mozilla::Mutex Mutex;
71
72 class RefCountedMutex MOZ_FINAL : public Mutex
73 {
74 public:
75 RefCountedMutex(const char* aName)
76 : Mutex(aName)
77 { }
78
79 NS_INLINE_DECL_THREADSAFE_REFCOUNTING(RefCountedMutex)
80
81 private:
82 ~RefCountedMutex()
83 { }
84 };
85
86 nsRefPtr<RefCountedMutex> mMutex;
87
88 public:
89 SharedMutex(const char* aName)
90 : mMutex(new RefCountedMutex(aName))
91 { }
92
93 SharedMutex(SharedMutex& aOther)
94 : mMutex(aOther.mMutex)
95 { }
96
97 operator Mutex&()
98 {
99 return *mMutex;
100 }
101
102 operator const Mutex&() const
103 {
104 return *mMutex;
105 }
106
107 void
108 AssertCurrentThreadOwns() const
109 {
110 mMutex->AssertCurrentThreadOwns();
111 }
112 };
113
114 template <class Derived>
115 class WorkerPrivateParent : public DOMEventTargetHelper
116 {
117 class SynchronizeAndResumeRunnable;
118
119 protected:
120 class EventTarget;
121 friend class EventTarget;
122
123 public:
124 struct LocationInfo
125 {
126 nsCString mHref;
127 nsCString mProtocol;
128 nsCString mHost;
129 nsCString mHostname;
130 nsCString mPort;
131 nsCString mPathname;
132 nsCString mSearch;
133 nsCString mHash;
134 nsString mOrigin;
135 };
136
137 struct LoadInfo
138 {
139 // All of these should be released in ForgetMainThreadObjects.
140 nsCOMPtr<nsIURI> mBaseURI;
141 nsCOMPtr<nsIURI> mResolvedScriptURI;
142 nsCOMPtr<nsIPrincipal> mPrincipal;
143 nsCOMPtr<nsIScriptContext> mScriptContext;
144 nsCOMPtr<nsPIDOMWindow> mWindow;
145 nsCOMPtr<nsIContentSecurityPolicy> mCSP;
146 nsCOMPtr<nsIChannel> mChannel;
147
148 nsCString mDomain;
149
150 bool mEvalAllowed;
151 bool mReportCSPViolations;
152 bool mXHRParamsAllowed;
153 bool mPrincipalIsSystem;
154 bool mIsInPrivilegedApp;
155 bool mIsInCertifiedApp;
156
157 LoadInfo()
158 : mEvalAllowed(false), mReportCSPViolations(false),
159 mXHRParamsAllowed(false), mPrincipalIsSystem(false),
160 mIsInPrivilegedApp(false), mIsInCertifiedApp(false)
161 { }
162
163 void
164 StealFrom(LoadInfo& aOther)
165 {
166 MOZ_ASSERT(!mBaseURI);
167 aOther.mBaseURI.swap(mBaseURI);
168
169 MOZ_ASSERT(!mResolvedScriptURI);
170 aOther.mResolvedScriptURI.swap(mResolvedScriptURI);
171
172 MOZ_ASSERT(!mPrincipal);
173 aOther.mPrincipal.swap(mPrincipal);
174
175 MOZ_ASSERT(!mScriptContext);
176 aOther.mScriptContext.swap(mScriptContext);
177
178 MOZ_ASSERT(!mWindow);
179 aOther.mWindow.swap(mWindow);
180
181 MOZ_ASSERT(!mCSP);
182 aOther.mCSP.swap(mCSP);
183
184 MOZ_ASSERT(!mChannel);
185 aOther.mChannel.swap(mChannel);
186
187 mDomain = aOther.mDomain;
188 mEvalAllowed = aOther.mEvalAllowed;
189 mReportCSPViolations = aOther.mReportCSPViolations;
190 mXHRParamsAllowed = aOther.mXHRParamsAllowed;
191 mPrincipalIsSystem = aOther.mPrincipalIsSystem;
192 mIsInPrivilegedApp = aOther.mIsInPrivilegedApp;
193 mIsInCertifiedApp = aOther.mIsInCertifiedApp;
194 }
195 };
196
197 enum WorkerType
198 {
199 WorkerTypeDedicated,
200 WorkerTypeShared
201 };
202
203 protected:
204 typedef mozilla::ErrorResult ErrorResult;
205
206 SharedMutex mMutex;
207 mozilla::CondVar mCondVar;
208 mozilla::CondVar mMemoryReportCondVar;
209
210 // Protected by mMutex.
211 nsRefPtr<EventTarget> mEventTarget;
212 nsTArray<nsRefPtr<WorkerRunnable>> mPreStartRunnables;
213
214 private:
215 WorkerPrivate* mParent;
216 nsString mScriptURL;
217 nsCString mSharedWorkerName;
218 LocationInfo mLocationInfo;
219 // The lifetime of these objects within LoadInfo is managed explicitly;
220 // they do not need to be cycle collected.
221 LoadInfo mLoadInfo;
222
223 // Only used for top level workers.
224 nsTArray<nsCOMPtr<nsIRunnable>> mQueuedRunnables;
225 nsRevocableEventPtr<SynchronizeAndResumeRunnable> mSynchronizeRunnable;
226
227 // Only for ChromeWorkers without window and only touched on the main thread.
228 nsTArray<nsCString> mHostObjectURIs;
229
230 // Protected by mMutex.
231 JSSettings mJSSettings;
232
233 // Only touched on the parent thread (currently this is always the main
234 // thread as SharedWorkers are always top-level).
235 nsDataHashtable<nsUint64HashKey, SharedWorker*> mSharedWorkers;
236
237 uint64_t mBusyCount;
238 uint64_t mMessagePortSerial;
239 Status mParentStatus;
240 bool mParentSuspended;
241 bool mIsChromeWorker;
242 bool mMainThreadObjectsForgotten;
243 WorkerType mWorkerType;
244 TimeStamp mCreationTimeStamp;
245
246 protected:
247 // The worker is owned by its thread, which is represented here. This is set
248 // in Construct() and emptied by WorkerFinishedRunnable, and conditionally
249 // traversed by the cycle collector if the busy count is zero.
250 nsRefPtr<WorkerPrivate> mSelfRef;
251
252 WorkerPrivateParent(JSContext* aCx, WorkerPrivate* aParent,
253 const nsAString& aScriptURL, bool aIsChromeWorker,
254 WorkerType aWorkerType,
255 const nsACString& aSharedWorkerName,
256 LoadInfo& aLoadInfo);
257
258 ~WorkerPrivateParent();
259
260 private:
261 Derived*
262 ParentAsWorkerPrivate() const
263 {
264 return static_cast<Derived*>(const_cast<WorkerPrivateParent*>(this));
265 }
266
267 // aCx is null when called from the finalizer
268 bool
269 NotifyPrivate(JSContext* aCx, Status aStatus);
270
271 // aCx is null when called from the finalizer
272 bool
273 TerminatePrivate(JSContext* aCx)
274 {
275 return NotifyPrivate(aCx, Terminating);
276 }
277
278 void
279 PostMessageInternal(JSContext* aCx, JS::Handle<JS::Value> aMessage,
280 const Optional<Sequence<JS::Value> >& aTransferable,
281 bool aToMessagePort, uint64_t aMessagePortSerial,
282 ErrorResult& aRv);
283
284 nsresult
285 DispatchPrivate(WorkerRunnable* aRunnable, nsIEventTarget* aSyncLoopTarget);
286
287 public:
288 virtual JSObject*
289 WrapObject(JSContext* aCx) MOZ_OVERRIDE;
290
291 NS_DECL_ISUPPORTS_INHERITED
292 NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS_INHERITED(WorkerPrivateParent,
293 DOMEventTargetHelper)
294
295 void
296 ClearSelfRef()
297 {
298 AssertIsOnParentThread();
299 MOZ_ASSERT(mSelfRef);
300 mSelfRef = nullptr;
301 }
302
303 nsresult
304 Dispatch(WorkerRunnable* aRunnable)
305 {
306 return DispatchPrivate(aRunnable, nullptr);
307 }
308
309 nsresult
310 DispatchControlRunnable(WorkerControlRunnable* aWorkerControlRunnable);
311
312 already_AddRefed<WorkerRunnable>
313 MaybeWrapAsWorkerRunnable(nsIRunnable* aRunnable);
314
315 already_AddRefed<nsIEventTarget>
316 GetEventTarget();
317
318 // May be called on any thread...
319 bool
320 Start();
321
322 // Called on the parent thread.
323 bool
324 Notify(JSContext* aCx, Status aStatus)
325 {
326 return NotifyPrivate(aCx, aStatus);
327 }
328
329 bool
330 Cancel(JSContext* aCx)
331 {
332 return Notify(aCx, Canceling);
333 }
334
335 bool
336 Kill(JSContext* aCx)
337 {
338 return Notify(aCx, Killing);
339 }
340
341 bool
342 Suspend(JSContext* aCx, nsPIDOMWindow* aWindow);
343
344 bool
345 Resume(JSContext* aCx, nsPIDOMWindow* aWindow);
346
347 bool
348 SynchronizeAndResume(JSContext* aCx, nsPIDOMWindow* aWindow,
349 nsIScriptContext* aScriptContext);
350
351 bool
352 Terminate(JSContext* aCx)
353 {
354 AssertIsOnParentThread();
355 return TerminatePrivate(aCx);
356 }
357
358 bool
359 Close(JSContext* aCx);
360
361 bool
362 ModifyBusyCount(JSContext* aCx, bool aIncrease);
363
364 void
365 ForgetMainThreadObjects(nsTArray<nsCOMPtr<nsISupports> >& aDoomed);
366
367 void
368 PostMessage(JSContext* aCx, JS::Handle<JS::Value> aMessage,
369 const Optional<Sequence<JS::Value> >& aTransferable,
370 ErrorResult& aRv)
371 {
372 PostMessageInternal(aCx, aMessage, aTransferable, false, 0, aRv);
373 }
374
375 void
376 PostMessageToMessagePort(JSContext* aCx,
377 uint64_t aMessagePortSerial,
378 JS::Handle<JS::Value> aMessage,
379 const Optional<Sequence<JS::Value> >& aTransferable,
380 ErrorResult& aRv);
381
382 bool
383 DispatchMessageEventToMessagePort(
384 JSContext* aCx,
385 uint64_t aMessagePortSerial,
386 JSAutoStructuredCloneBuffer&& aBuffer,
387 nsTArray<nsCOMPtr<nsISupports>>& aClonedObjects);
388
389 uint64_t
390 GetInnerWindowId();
391
392 void
393 UpdateRuntimeAndContextOptions(JSContext* aCx,
394 const JS::RuntimeOptions& aRuntimeOptions,
395 const JS::ContextOptions& aContentCxOptions,
396 const JS::ContextOptions& aChromeCxOptions);
397
398 void
399 UpdatePreference(JSContext* aCx, WorkerPreference aPref, bool aValue);
400
401 void
402 UpdateJSWorkerMemoryParameter(JSContext* aCx, JSGCParamKey key,
403 uint32_t value);
404
405 #ifdef JS_GC_ZEAL
406 void
407 UpdateGCZeal(JSContext* aCx, uint8_t aGCZeal, uint32_t aFrequency);
408 #endif
409
410 void
411 GarbageCollect(JSContext* aCx, bool aShrinking);
412
413 void
414 CycleCollect(JSContext* aCx, bool aDummy);
415
416 void
417 OfflineStatusChangeEvent(JSContext* aCx, bool aIsOffline);
418
419 bool
420 RegisterSharedWorker(JSContext* aCx, SharedWorker* aSharedWorker);
421
422 void
423 UnregisterSharedWorker(JSContext* aCx, SharedWorker* aSharedWorker);
424
425 void
426 BroadcastErrorToSharedWorkers(JSContext* aCx,
427 const nsAString& aMessage,
428 const nsAString& aFilename,
429 const nsAString& aLine,
430 uint32_t aLineNumber,
431 uint32_t aColumnNumber,
432 uint32_t aFlags);
433
434 void
435 WorkerScriptLoaded();
436
437 void
438 QueueRunnable(nsIRunnable* aRunnable)
439 {
440 AssertIsOnMainThread();
441 mQueuedRunnables.AppendElement(aRunnable);
442 }
443
444 WorkerPrivate*
445 GetParent() const
446 {
447 return mParent;
448 }
449
450 bool
451 IsSuspended() const
452 {
453 AssertIsOnParentThread();
454 return mParentSuspended;
455 }
456
457 bool
458 IsAcceptingEvents()
459 {
460 AssertIsOnParentThread();
461
462 MutexAutoLock lock(mMutex);
463 return mParentStatus < Terminating;
464 }
465
466 Status
467 ParentStatus() const
468 {
469 mMutex.AssertCurrentThreadOwns();
470 return mParentStatus;
471 }
472
473 JSContext*
474 ParentJSContext() const;
475
476 nsIScriptContext*
477 GetScriptContext() const
478 {
479 AssertIsOnMainThread();
480 return mLoadInfo.mScriptContext;
481 }
482
483 const nsString&
484 ScriptURL() const
485 {
486 return mScriptURL;
487 }
488
489 const nsCString&
490 Domain() const
491 {
492 return mLoadInfo.mDomain;
493 }
494
495 nsIURI*
496 GetBaseURI() const
497 {
498 AssertIsOnMainThread();
499 return mLoadInfo.mBaseURI;
500 }
501
502 void
503 SetBaseURI(nsIURI* aBaseURI);
504
505 nsIURI*
506 GetResolvedScriptURI() const
507 {
508 AssertIsOnMainThread();
509 return mLoadInfo.mResolvedScriptURI;
510 }
511
512 TimeStamp CreationTimeStamp() const
513 {
514 return mCreationTimeStamp;
515 }
516
517 nsIPrincipal*
518 GetPrincipal() const
519 {
520 AssertIsOnMainThread();
521 return mLoadInfo.mPrincipal;
522 }
523
524 // This method allows the principal to be retrieved off the main thread.
525 // Principals are main-thread objects so the caller must ensure that all
526 // access occurs on the main thread.
527 nsIPrincipal*
528 GetPrincipalDontAssertMainThread() const
529 {
530 return mLoadInfo.mPrincipal;
531 }
532
533 void
534 SetPrincipal(nsIPrincipal* aPrincipal);
535
536 bool
537 UsesSystemPrincipal() const
538 {
539 return mLoadInfo.mPrincipalIsSystem;
540 }
541
542 bool
543 IsInPrivilegedApp() const
544 {
545 return mLoadInfo.mIsInPrivilegedApp;
546 }
547
548 bool
549 IsInCertifiedApp() const
550 {
551 return mLoadInfo.mIsInCertifiedApp;
552 }
553
554 already_AddRefed<nsIChannel>
555 ForgetWorkerChannel()
556 {
557 AssertIsOnMainThread();
558 return mLoadInfo.mChannel.forget();
559 }
560
561 nsIDocument*
562 GetDocument() const
563 {
564 AssertIsOnMainThread();
565 return mLoadInfo.mWindow ? mLoadInfo.mWindow->GetExtantDoc() : nullptr;
566 }
567
568 nsPIDOMWindow*
569 GetWindow()
570 {
571 AssertIsOnMainThread();
572 return mLoadInfo.mWindow;
573 }
574
575 nsIContentSecurityPolicy*
576 GetCSP() const
577 {
578 AssertIsOnMainThread();
579 return mLoadInfo.mCSP;
580 }
581
582 void
583 SetCSP(nsIContentSecurityPolicy* aCSP)
584 {
585 AssertIsOnMainThread();
586 mLoadInfo.mCSP = aCSP;
587 }
588
589 bool
590 IsEvalAllowed() const
591 {
592 return mLoadInfo.mEvalAllowed;
593 }
594
595 void
596 SetEvalAllowed(bool aEvalAllowed)
597 {
598 mLoadInfo.mEvalAllowed = aEvalAllowed;
599 }
600
601 bool
602 GetReportCSPViolations() const
603 {
604 return mLoadInfo.mReportCSPViolations;
605 }
606
607 bool
608 XHRParamsAllowed() const
609 {
610 return mLoadInfo.mXHRParamsAllowed;
611 }
612
613 void
614 SetXHRParamsAllowed(bool aAllowed)
615 {
616 mLoadInfo.mXHRParamsAllowed = aAllowed;
617 }
618
619 LocationInfo&
620 GetLocationInfo()
621 {
622 return mLocationInfo;
623 }
624
625 void
626 CopyJSSettings(JSSettings& aSettings)
627 {
628 mozilla::MutexAutoLock lock(mMutex);
629 aSettings = mJSSettings;
630 }
631
632 void
633 CopyJSCompartmentOptions(JS::CompartmentOptions& aOptions)
634 {
635 mozilla::MutexAutoLock lock(mMutex);
636 aOptions = IsChromeWorker() ? mJSSettings.chrome.compartmentOptions
637 : mJSSettings.content.compartmentOptions;
638 }
639
640 // The ability to be a chrome worker is orthogonal to the type of
641 // worker [Dedicated|Shared].
642 bool
643 IsChromeWorker() const
644 {
645 return mIsChromeWorker;
646 }
647
648 bool
649 IsDedicatedWorker() const
650 {
651 return mWorkerType == WorkerTypeDedicated;
652 }
653
654 bool
655 IsSharedWorker() const
656 {
657 return mWorkerType == WorkerTypeShared;
658 }
659
660 const nsCString&
661 SharedWorkerName() const
662 {
663 return mSharedWorkerName;
664 }
665
666 uint64_t
667 NextMessagePortSerial()
668 {
669 AssertIsOnMainThread();
670 return mMessagePortSerial++;
671 }
672
673 void
674 GetAllSharedWorkers(nsTArray<nsRefPtr<SharedWorker>>& aSharedWorkers);
675
676 void
677 CloseSharedWorkersForWindow(nsPIDOMWindow* aWindow);
678
679 void
680 RegisterHostObjectURI(const nsACString& aURI);
681
682 void
683 UnregisterHostObjectURI(const nsACString& aURI);
684
685 void
686 StealHostObjectURIs(nsTArray<nsCString>& aArray);
687
688 IMPL_EVENT_HANDLER(message)
689 IMPL_EVENT_HANDLER(error)
690
691 #ifdef DEBUG
692 void
693 AssertIsOnParentThread() const;
694
695 void
696 AssertInnerWindowIsCorrect() const;
697 #else
698 void
699 AssertIsOnParentThread() const
700 { }
701
702 void
703 AssertInnerWindowIsCorrect() const
704 { }
705 #endif
706 };
707
708 class WorkerPrivate : public WorkerPrivateParent<WorkerPrivate>
709 {
710 friend class WorkerPrivateParent<WorkerPrivate>;
711 typedef WorkerPrivateParent<WorkerPrivate> ParentType;
712 friend class AutoSyncLoopHolder;
713
714 struct TimeoutInfo;
715
716 class MemoryReporter;
717 friend class MemoryReporter;
718
719 enum GCTimerMode
720 {
721 PeriodicTimer = 0,
722 IdleTimer,
723 NoTimer
724 };
725
726 Queue<WorkerControlRunnable*, 4> mControlQueue;
727
728 // Touched on multiple threads, protected with mMutex.
729 JSContext* mJSContext;
730 nsRefPtr<WorkerCrossThreadDispatcher> mCrossThreadDispatcher;
731 nsTArray<nsCOMPtr<nsIRunnable>> mUndispatchedRunnablesForSyncLoop;
732 nsCOMPtr<nsIThread> mThread;
733
734 // Things touched on worker thread only.
735 nsRefPtr<WorkerGlobalScope> mScope;
736 nsTArray<ParentType*> mChildWorkers;
737 nsTArray<WorkerFeature*> mFeatures;
738 nsTArray<nsAutoPtr<TimeoutInfo>> mTimeouts;
739
740 struct SyncLoopInfo
741 {
742 SyncLoopInfo(EventTarget* aEventTarget);
743
744 nsRefPtr<EventTarget> mEventTarget;
745 bool mCompleted;
746 bool mResult;
747 #ifdef DEBUG
748 bool mHasRun;
749 #endif
750 };
751
752 // This is only modified on the worker thread, but in DEBUG builds
753 // AssertValidSyncLoop function iterates it on other threads. Therefore
754 // modifications are done with mMutex held *only* in DEBUG builds.
755 nsTArray<nsAutoPtr<SyncLoopInfo>> mSyncLoopStack;
756
757 nsCOMPtr<nsITimer> mTimer;
758
759 nsCOMPtr<nsITimer> mGCTimer;
760 nsCOMPtr<nsIEventTarget> mPeriodicGCTimerTarget;
761 nsCOMPtr<nsIEventTarget> mIdleGCTimerTarget;
762
763 nsRefPtr<MemoryReporter> mMemoryReporter;
764
765 nsRefPtrHashtable<nsUint64HashKey, MessagePort> mWorkerPorts;
766
767 TimeStamp mKillTime;
768 uint32_t mErrorHandlerRecursionCount;
769 uint32_t mNextTimeoutId;
770 Status mStatus;
771 bool mSuspended;
772 bool mTimerRunning;
773 bool mRunningExpiredTimeouts;
774 bool mCloseHandlerStarted;
775 bool mCloseHandlerFinished;
776 bool mMemoryReporterRunning;
777 bool mBlockedForMemoryReporter;
778 bool mCancelAllPendingRunnables;
779 bool mPeriodicGCTimerRunning;
780 bool mIdleGCTimerRunning;
781
782 #ifdef DEBUG
783 PRThread* mPRThread;
784 #endif
785
786 bool mPreferences[WORKERPREF_COUNT];
787 bool mOnLine;
788
789 protected:
790 ~WorkerPrivate();
791
792 public:
793 static already_AddRefed<WorkerPrivate>
794 Constructor(const GlobalObject& aGlobal, const nsAString& aScriptURL,
795 ErrorResult& aRv);
796
797 static already_AddRefed<WorkerPrivate>
798 Constructor(const GlobalObject& aGlobal, const nsAString& aScriptURL,
799 bool aIsChromeWorker, WorkerType aWorkerType,
800 const nsACString& aSharedWorkerName,
801 LoadInfo* aLoadInfo, ErrorResult& aRv);
802
803 static bool
804 WorkerAvailable(JSContext* /* unused */, JSObject* /* unused */);
805
806 static nsresult
807 GetLoadInfo(JSContext* aCx, nsPIDOMWindow* aWindow, WorkerPrivate* aParent,
808 const nsAString& aScriptURL, bool aIsChromeWorker,
809 LoadInfo* aLoadInfo);
810
811 void
812 DoRunLoop(JSContext* aCx);
813
814 bool
815 InterruptCallback(JSContext* aCx);
816
817 nsresult
818 IsOnCurrentThread(bool* aIsOnCurrentThread);
819
820 bool
821 CloseInternal(JSContext* aCx)
822 {
823 AssertIsOnWorkerThread();
824 return NotifyInternal(aCx, Closing);
825 }
826
827 bool
828 SuspendInternal(JSContext* aCx);
829
830 bool
831 ResumeInternal(JSContext* aCx);
832
833 void
834 TraceTimeouts(const TraceCallbacks& aCallbacks, void* aClosure) const;
835
836 bool
837 ModifyBusyCountFromWorker(JSContext* aCx, bool aIncrease);
838
839 bool
840 AddChildWorker(JSContext* aCx, ParentType* aChildWorker);
841
842 void
843 RemoveChildWorker(JSContext* aCx, ParentType* aChildWorker);
844
845 bool
846 AddFeature(JSContext* aCx, WorkerFeature* aFeature);
847
848 void
849 RemoveFeature(JSContext* aCx, WorkerFeature* aFeature);
850
851 void
852 NotifyFeatures(JSContext* aCx, Status aStatus);
853
854 bool
855 HasActiveFeatures()
856 {
857 return !(mChildWorkers.IsEmpty() && mTimeouts.IsEmpty() &&
858 mFeatures.IsEmpty());
859 }
860
861 void
862 PostMessageToParent(JSContext* aCx,
863 JS::Handle<JS::Value> aMessage,
864 const Optional<Sequence<JS::Value>>& aTransferable,
865 ErrorResult& aRv)
866 {
867 PostMessageToParentInternal(aCx, aMessage, aTransferable, false, 0, aRv);
868 }
869
870 void
871 PostMessageToParentMessagePort(
872 JSContext* aCx,
873 uint64_t aMessagePortSerial,
874 JS::Handle<JS::Value> aMessage,
875 const Optional<Sequence<JS::Value>>& aTransferable,
876 ErrorResult& aRv);
877
878 bool
879 NotifyInternal(JSContext* aCx, Status aStatus);
880
881 void
882 ReportError(JSContext* aCx, const char* aMessage, JSErrorReport* aReport);
883
884 int32_t
885 SetTimeout(JSContext* aCx,
886 Function* aHandler,
887 const nsAString& aStringHandler,
888 int32_t aTimeout,
889 const Sequence<JS::Value>& aArguments,
890 bool aIsInterval,
891 ErrorResult& aRv);
892
893 void
894 ClearTimeout(int32_t aId);
895
896 bool
897 RunExpiredTimeouts(JSContext* aCx);
898
899 bool
900 RescheduleTimeoutTimer(JSContext* aCx);
901
902 void
903 CloseHandlerStarted()
904 {
905 AssertIsOnWorkerThread();
906 mCloseHandlerStarted = true;
907 }
908
909 void
910 CloseHandlerFinished()
911 {
912 AssertIsOnWorkerThread();
913 mCloseHandlerFinished = true;
914 }
915
916 void
917 UpdateRuntimeAndContextOptionsInternal(
918 JSContext* aCx,
919 const JS::RuntimeOptions& aRuntimeOptions,
920 const JS::ContextOptions& aContentCxOptions,
921 const JS::ContextOptions& aChromeCxOptions);
922
923 void
924 UpdatePreferenceInternal(JSContext* aCx, WorkerPreference aPref, bool aValue);
925
926 void
927 UpdateJSWorkerMemoryParameterInternal(JSContext* aCx, JSGCParamKey key, uint32_t aValue);
928
929 enum WorkerRanOrNot {
930 WorkerNeverRan = 0,
931 WorkerRan
932 };
933
934 void
935 ScheduleDeletion(WorkerRanOrNot aRanOrNot);
936
937 bool
938 BlockAndCollectRuntimeStats(JS::RuntimeStats* aRtStats);
939
940 #ifdef JS_GC_ZEAL
941 void
942 UpdateGCZealInternal(JSContext* aCx, uint8_t aGCZeal, uint32_t aFrequency);
943 #endif
944
945 void
946 GarbageCollectInternal(JSContext* aCx, bool aShrinking,
947 bool aCollectChildren);
948
949 void
950 CycleCollectInternal(JSContext* aCx, bool aCollectChildren);
951
952 void
953 OfflineStatusChangeEventInternal(JSContext* aCx, bool aIsOffline);
954
955 JSContext*
956 GetJSContext() const
957 {
958 AssertIsOnWorkerThread();
959 return mJSContext;
960 }
961
962 WorkerGlobalScope*
963 GlobalScope() const
964 {
965 AssertIsOnWorkerThread();
966 return mScope;
967 }
968
969 void
970 SetThread(nsIThread* aThread);
971
972 void
973 AssertIsOnWorkerThread() const
974 #ifdef DEBUG
975 ;
976 #else
977 { }
978 #endif
979
980 WorkerCrossThreadDispatcher*
981 GetCrossThreadDispatcher();
982
983 // This may block!
984 void
985 BeginCTypesCall();
986
987 // This may block!
988 void
989 EndCTypesCall();
990
991 void
992 BeginCTypesCallback()
993 {
994 // If a callback is beginning then we need to do the exact same thing as
995 // when a ctypes call ends.
996 EndCTypesCall();
997 }
998
999 void
1000 EndCTypesCallback()
1001 {
1002 // If a callback is ending then we need to do the exact same thing as
1003 // when a ctypes call begins.
1004 BeginCTypesCall();
1005 }
1006
1007 bool
1008 ConnectMessagePort(JSContext* aCx, uint64_t aMessagePortSerial);
1009
1010 void
1011 DisconnectMessagePort(uint64_t aMessagePortSerial);
1012
1013 MessagePort*
1014 GetMessagePort(uint64_t aMessagePortSerial);
1015
1016 JSObject*
1017 CreateGlobalScope(JSContext* aCx);
1018
1019 bool
1020 RegisterBindings(JSContext* aCx, JS::Handle<JSObject*> aGlobal);
1021
1022 bool
1023 DumpEnabled() const
1024 {
1025 AssertIsOnWorkerThread();
1026 return mPreferences[WORKERPREF_DUMP];
1027 }
1028
1029 bool
1030 OnLine() const
1031 {
1032 AssertIsOnWorkerThread();
1033 return mOnLine;
1034 }
1035
1036 void
1037 StopSyncLoop(nsIEventTarget* aSyncLoopTarget, bool aResult);
1038
1039 bool
1040 AllPendingRunnablesShouldBeCanceled() const
1041 {
1042 return mCancelAllPendingRunnables;
1043 }
1044
1045 void
1046 OnProcessNextEvent(uint32_t aRecursionDepth);
1047
1048 void
1049 AfterProcessNextEvent(uint32_t aRecursionDepth);
1050
1051 void
1052 AssertValidSyncLoop(nsIEventTarget* aSyncLoopTarget)
1053 #ifdef DEBUG
1054 ;
1055 #else
1056 { }
1057 #endif
1058
1059 private:
1060 WorkerPrivate(JSContext* aCx, WorkerPrivate* aParent,
1061 const nsAString& aScriptURL, bool aIsChromeWorker,
1062 WorkerType aWorkerType, const nsACString& aSharedWorkerName,
1063 LoadInfo& aLoadInfo);
1064
1065 void
1066 ClearMainEventQueue(WorkerRanOrNot aRanOrNot);
1067
1068 bool
1069 MayContinueRunning()
1070 {
1071 AssertIsOnWorkerThread();
1072
1073 Status status;
1074 {
1075 MutexAutoLock lock(mMutex);
1076 status = mStatus;
1077 }
1078
1079 if (status >= Killing) {
1080 return false;
1081 }
1082 if (status >= Running) {
1083 return mKillTime.IsNull() || RemainingRunTimeMS() > 0;
1084 }
1085 return true;
1086 }
1087
1088 uint32_t
1089 RemainingRunTimeMS() const;
1090
1091 void
1092 CancelAllTimeouts(JSContext* aCx);
1093
1094 bool
1095 ScheduleKillCloseEventRunnable(JSContext* aCx);
1096
1097 bool
1098 ProcessAllControlRunnables()
1099 {
1100 MutexAutoLock lock(mMutex);
1101 return ProcessAllControlRunnablesLocked();
1102 }
1103
1104 bool
1105 ProcessAllControlRunnablesLocked();
1106
1107 void
1108 EnableMemoryReporter();
1109
1110 void
1111 DisableMemoryReporter();
1112
1113 void
1114 WaitForWorkerEvents(PRIntervalTime interval = PR_INTERVAL_NO_TIMEOUT);
1115
1116 void
1117 PostMessageToParentInternal(JSContext* aCx,
1118 JS::Handle<JS::Value> aMessage,
1119 const Optional<Sequence<JS::Value>>& aTransferable,
1120 bool aToMessagePort,
1121 uint64_t aMessagePortSerial,
1122 ErrorResult& aRv);
1123
1124 void
1125 GetAllPreferences(bool aPreferences[WORKERPREF_COUNT]) const
1126 {
1127 AssertIsOnWorkerThread();
1128 memcpy(aPreferences, mPreferences, WORKERPREF_COUNT * sizeof(bool));
1129 }
1130
1131 already_AddRefed<nsIEventTarget>
1132 CreateNewSyncLoop();
1133
1134 bool
1135 RunCurrentSyncLoop();
1136
1137 bool
1138 DestroySyncLoop(uint32_t aLoopIndex, nsIThreadInternal* aThread = nullptr);
1139
1140 void
1141 InitializeGCTimers();
1142
1143 void
1144 SetGCTimerMode(GCTimerMode aMode);
1145
1146 void
1147 ShutdownGCTimers();
1148 };
1149
1150 // This class is only used to trick the DOM bindings. We never create
1151 // instances of it, and static_casting to it is fine since it doesn't add
1152 // anything to WorkerPrivate.
1153 class ChromeWorkerPrivate : public WorkerPrivate
1154 {
1155 public:
1156 static already_AddRefed<ChromeWorkerPrivate>
1157 Constructor(const GlobalObject& aGlobal, const nsAString& aScriptURL,
1158 ErrorResult& rv);
1159
1160 static bool
1161 WorkerAvailable(JSContext* /* unused */, JSObject* /* unused */);
1162
1163 private:
1164 ChromeWorkerPrivate() MOZ_DELETE;
1165 ChromeWorkerPrivate(const ChromeWorkerPrivate& aRHS) MOZ_DELETE;
1166 ChromeWorkerPrivate& operator =(const ChromeWorkerPrivate& aRHS) MOZ_DELETE;
1167 };
1168
1169 WorkerPrivate*
1170 GetWorkerPrivateFromContext(JSContext* aCx);
1171
1172 WorkerPrivate*
1173 GetCurrentThreadWorkerPrivate();
1174
1175 bool
1176 IsCurrentThreadRunningChromeWorker();
1177
1178 JSContext*
1179 GetCurrentThreadJSContext();
1180
1181 enum WorkerStructuredDataType
1182 {
1183 DOMWORKER_SCTAG_FILE = SCTAG_DOM_MAX,
1184 DOMWORKER_SCTAG_BLOB,
1185
1186 DOMWORKER_SCTAG_END
1187 };
1188
1189 JSStructuredCloneCallbacks*
1190 WorkerStructuredCloneCallbacks(bool aMainRuntime);
1191
1192 JSStructuredCloneCallbacks*
1193 ChromeWorkerStructuredCloneCallbacks(bool aMainRuntime);
1194
1195 class AutoSyncLoopHolder
1196 {
1197 WorkerPrivate* mWorkerPrivate;
1198 nsCOMPtr<nsIEventTarget> mTarget;
1199 uint32_t mIndex;
1200
1201 public:
1202 AutoSyncLoopHolder(WorkerPrivate* aWorkerPrivate)
1203 : mWorkerPrivate(aWorkerPrivate)
1204 , mTarget(aWorkerPrivate->CreateNewSyncLoop())
1205 , mIndex(aWorkerPrivate->mSyncLoopStack.Length() - 1)
1206 {
1207 aWorkerPrivate->AssertIsOnWorkerThread();
1208 }
1209
1210 ~AutoSyncLoopHolder()
1211 {
1212 if (mWorkerPrivate) {
1213 mWorkerPrivate->AssertIsOnWorkerThread();
1214 mWorkerPrivate->StopSyncLoop(mTarget, false);
1215 mWorkerPrivate->DestroySyncLoop(mIndex);
1216 }
1217 }
1218
1219 bool
1220 Run()
1221 {
1222 WorkerPrivate* workerPrivate = mWorkerPrivate;
1223 mWorkerPrivate = nullptr;
1224
1225 workerPrivate->AssertIsOnWorkerThread();
1226
1227 return workerPrivate->RunCurrentSyncLoop();
1228 }
1229
1230 nsIEventTarget*
1231 EventTarget() const
1232 {
1233 return mTarget;
1234 }
1235 };
1236
1237 END_WORKERS_NAMESPACE
1238
1239 #endif /* mozilla_dom_workers_workerprivate_h__ */

mercurial