1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/dom/workers/WorkerPrivate.h Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,1239 @@ 1.4 +/* -*- Mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 40 -*- */ 1.5 +/* This Source Code Form is subject to the terms of the Mozilla Public 1.6 + * License, v. 2.0. If a copy of the MPL was not distributed with this 1.7 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 1.8 + 1.9 +#ifndef mozilla_dom_workers_workerprivate_h__ 1.10 +#define mozilla_dom_workers_workerprivate_h__ 1.11 + 1.12 +#include "Workers.h" 1.13 + 1.14 +#include "nsIContentSecurityPolicy.h" 1.15 +#include "nsPIDOMWindow.h" 1.16 + 1.17 +#include "mozilla/CondVar.h" 1.18 +#include "mozilla/DOMEventTargetHelper.h" 1.19 +#include "mozilla/TimeStamp.h" 1.20 +#include "mozilla/dom/BindingDeclarations.h" 1.21 +#include "nsCycleCollectionParticipant.h" 1.22 +#include "nsDataHashtable.h" 1.23 +#include "nsHashKeys.h" 1.24 +#include "nsRefPtrHashtable.h" 1.25 +#include "nsString.h" 1.26 +#include "nsTArray.h" 1.27 +#include "nsThreadUtils.h" 1.28 +#include "StructuredCloneTags.h" 1.29 + 1.30 +#include "Queue.h" 1.31 +#include "WorkerFeature.h" 1.32 + 1.33 +class JSAutoStructuredCloneBuffer; 1.34 +class nsIChannel; 1.35 +class nsIDocument; 1.36 +class nsIEventTarget; 1.37 +class nsIPrincipal; 1.38 +class nsIScriptContext; 1.39 +class nsIThread; 1.40 +class nsIThreadInternal; 1.41 +class nsITimer; 1.42 +class nsIURI; 1.43 + 1.44 +namespace JS { 1.45 +class RuntimeStats; 1.46 +} 1.47 + 1.48 +namespace mozilla { 1.49 +namespace dom { 1.50 +class Function; 1.51 +} 1.52 +} 1.53 + 1.54 +#ifdef DEBUG 1.55 +struct PRThread; 1.56 +#endif 1.57 + 1.58 +BEGIN_WORKERS_NAMESPACE 1.59 + 1.60 +class AutoSyncLoopHolder; 1.61 +class MessagePort; 1.62 +class SharedWorker; 1.63 +class WorkerControlRunnable; 1.64 +class WorkerGlobalScope; 1.65 +class WorkerPrivate; 1.66 +class WorkerRunnable; 1.67 + 1.68 +// SharedMutex is a small wrapper around an (internal) reference-counted Mutex 1.69 +// object. It exists to avoid changing a lot of code to use Mutex* instead of 1.70 +// Mutex&. 1.71 +class SharedMutex 1.72 +{ 1.73 + typedef mozilla::Mutex Mutex; 1.74 + 1.75 + class RefCountedMutex MOZ_FINAL : public Mutex 1.76 + { 1.77 + public: 1.78 + RefCountedMutex(const char* aName) 1.79 + : Mutex(aName) 1.80 + { } 1.81 + 1.82 + NS_INLINE_DECL_THREADSAFE_REFCOUNTING(RefCountedMutex) 1.83 + 1.84 + private: 1.85 + ~RefCountedMutex() 1.86 + { } 1.87 + }; 1.88 + 1.89 + nsRefPtr<RefCountedMutex> mMutex; 1.90 + 1.91 +public: 1.92 + SharedMutex(const char* aName) 1.93 + : mMutex(new RefCountedMutex(aName)) 1.94 + { } 1.95 + 1.96 + SharedMutex(SharedMutex& aOther) 1.97 + : mMutex(aOther.mMutex) 1.98 + { } 1.99 + 1.100 + operator Mutex&() 1.101 + { 1.102 + return *mMutex; 1.103 + } 1.104 + 1.105 + operator const Mutex&() const 1.106 + { 1.107 + return *mMutex; 1.108 + } 1.109 + 1.110 + void 1.111 + AssertCurrentThreadOwns() const 1.112 + { 1.113 + mMutex->AssertCurrentThreadOwns(); 1.114 + } 1.115 +}; 1.116 + 1.117 +template <class Derived> 1.118 +class WorkerPrivateParent : public DOMEventTargetHelper 1.119 +{ 1.120 + class SynchronizeAndResumeRunnable; 1.121 + 1.122 +protected: 1.123 + class EventTarget; 1.124 + friend class EventTarget; 1.125 + 1.126 +public: 1.127 + struct LocationInfo 1.128 + { 1.129 + nsCString mHref; 1.130 + nsCString mProtocol; 1.131 + nsCString mHost; 1.132 + nsCString mHostname; 1.133 + nsCString mPort; 1.134 + nsCString mPathname; 1.135 + nsCString mSearch; 1.136 + nsCString mHash; 1.137 + nsString mOrigin; 1.138 + }; 1.139 + 1.140 + struct LoadInfo 1.141 + { 1.142 + // All of these should be released in ForgetMainThreadObjects. 1.143 + nsCOMPtr<nsIURI> mBaseURI; 1.144 + nsCOMPtr<nsIURI> mResolvedScriptURI; 1.145 + nsCOMPtr<nsIPrincipal> mPrincipal; 1.146 + nsCOMPtr<nsIScriptContext> mScriptContext; 1.147 + nsCOMPtr<nsPIDOMWindow> mWindow; 1.148 + nsCOMPtr<nsIContentSecurityPolicy> mCSP; 1.149 + nsCOMPtr<nsIChannel> mChannel; 1.150 + 1.151 + nsCString mDomain; 1.152 + 1.153 + bool mEvalAllowed; 1.154 + bool mReportCSPViolations; 1.155 + bool mXHRParamsAllowed; 1.156 + bool mPrincipalIsSystem; 1.157 + bool mIsInPrivilegedApp; 1.158 + bool mIsInCertifiedApp; 1.159 + 1.160 + LoadInfo() 1.161 + : mEvalAllowed(false), mReportCSPViolations(false), 1.162 + mXHRParamsAllowed(false), mPrincipalIsSystem(false), 1.163 + mIsInPrivilegedApp(false), mIsInCertifiedApp(false) 1.164 + { } 1.165 + 1.166 + void 1.167 + StealFrom(LoadInfo& aOther) 1.168 + { 1.169 + MOZ_ASSERT(!mBaseURI); 1.170 + aOther.mBaseURI.swap(mBaseURI); 1.171 + 1.172 + MOZ_ASSERT(!mResolvedScriptURI); 1.173 + aOther.mResolvedScriptURI.swap(mResolvedScriptURI); 1.174 + 1.175 + MOZ_ASSERT(!mPrincipal); 1.176 + aOther.mPrincipal.swap(mPrincipal); 1.177 + 1.178 + MOZ_ASSERT(!mScriptContext); 1.179 + aOther.mScriptContext.swap(mScriptContext); 1.180 + 1.181 + MOZ_ASSERT(!mWindow); 1.182 + aOther.mWindow.swap(mWindow); 1.183 + 1.184 + MOZ_ASSERT(!mCSP); 1.185 + aOther.mCSP.swap(mCSP); 1.186 + 1.187 + MOZ_ASSERT(!mChannel); 1.188 + aOther.mChannel.swap(mChannel); 1.189 + 1.190 + mDomain = aOther.mDomain; 1.191 + mEvalAllowed = aOther.mEvalAllowed; 1.192 + mReportCSPViolations = aOther.mReportCSPViolations; 1.193 + mXHRParamsAllowed = aOther.mXHRParamsAllowed; 1.194 + mPrincipalIsSystem = aOther.mPrincipalIsSystem; 1.195 + mIsInPrivilegedApp = aOther.mIsInPrivilegedApp; 1.196 + mIsInCertifiedApp = aOther.mIsInCertifiedApp; 1.197 + } 1.198 + }; 1.199 + 1.200 + enum WorkerType 1.201 + { 1.202 + WorkerTypeDedicated, 1.203 + WorkerTypeShared 1.204 + }; 1.205 + 1.206 +protected: 1.207 + typedef mozilla::ErrorResult ErrorResult; 1.208 + 1.209 + SharedMutex mMutex; 1.210 + mozilla::CondVar mCondVar; 1.211 + mozilla::CondVar mMemoryReportCondVar; 1.212 + 1.213 + // Protected by mMutex. 1.214 + nsRefPtr<EventTarget> mEventTarget; 1.215 + nsTArray<nsRefPtr<WorkerRunnable>> mPreStartRunnables; 1.216 + 1.217 +private: 1.218 + WorkerPrivate* mParent; 1.219 + nsString mScriptURL; 1.220 + nsCString mSharedWorkerName; 1.221 + LocationInfo mLocationInfo; 1.222 + // The lifetime of these objects within LoadInfo is managed explicitly; 1.223 + // they do not need to be cycle collected. 1.224 + LoadInfo mLoadInfo; 1.225 + 1.226 + // Only used for top level workers. 1.227 + nsTArray<nsCOMPtr<nsIRunnable>> mQueuedRunnables; 1.228 + nsRevocableEventPtr<SynchronizeAndResumeRunnable> mSynchronizeRunnable; 1.229 + 1.230 + // Only for ChromeWorkers without window and only touched on the main thread. 1.231 + nsTArray<nsCString> mHostObjectURIs; 1.232 + 1.233 + // Protected by mMutex. 1.234 + JSSettings mJSSettings; 1.235 + 1.236 + // Only touched on the parent thread (currently this is always the main 1.237 + // thread as SharedWorkers are always top-level). 1.238 + nsDataHashtable<nsUint64HashKey, SharedWorker*> mSharedWorkers; 1.239 + 1.240 + uint64_t mBusyCount; 1.241 + uint64_t mMessagePortSerial; 1.242 + Status mParentStatus; 1.243 + bool mParentSuspended; 1.244 + bool mIsChromeWorker; 1.245 + bool mMainThreadObjectsForgotten; 1.246 + WorkerType mWorkerType; 1.247 + TimeStamp mCreationTimeStamp; 1.248 + 1.249 +protected: 1.250 + // The worker is owned by its thread, which is represented here. This is set 1.251 + // in Construct() and emptied by WorkerFinishedRunnable, and conditionally 1.252 + // traversed by the cycle collector if the busy count is zero. 1.253 + nsRefPtr<WorkerPrivate> mSelfRef; 1.254 + 1.255 + WorkerPrivateParent(JSContext* aCx, WorkerPrivate* aParent, 1.256 + const nsAString& aScriptURL, bool aIsChromeWorker, 1.257 + WorkerType aWorkerType, 1.258 + const nsACString& aSharedWorkerName, 1.259 + LoadInfo& aLoadInfo); 1.260 + 1.261 + ~WorkerPrivateParent(); 1.262 + 1.263 +private: 1.264 + Derived* 1.265 + ParentAsWorkerPrivate() const 1.266 + { 1.267 + return static_cast<Derived*>(const_cast<WorkerPrivateParent*>(this)); 1.268 + } 1.269 + 1.270 + // aCx is null when called from the finalizer 1.271 + bool 1.272 + NotifyPrivate(JSContext* aCx, Status aStatus); 1.273 + 1.274 + // aCx is null when called from the finalizer 1.275 + bool 1.276 + TerminatePrivate(JSContext* aCx) 1.277 + { 1.278 + return NotifyPrivate(aCx, Terminating); 1.279 + } 1.280 + 1.281 + void 1.282 + PostMessageInternal(JSContext* aCx, JS::Handle<JS::Value> aMessage, 1.283 + const Optional<Sequence<JS::Value> >& aTransferable, 1.284 + bool aToMessagePort, uint64_t aMessagePortSerial, 1.285 + ErrorResult& aRv); 1.286 + 1.287 + nsresult 1.288 + DispatchPrivate(WorkerRunnable* aRunnable, nsIEventTarget* aSyncLoopTarget); 1.289 + 1.290 +public: 1.291 + virtual JSObject* 1.292 + WrapObject(JSContext* aCx) MOZ_OVERRIDE; 1.293 + 1.294 + NS_DECL_ISUPPORTS_INHERITED 1.295 + NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS_INHERITED(WorkerPrivateParent, 1.296 + DOMEventTargetHelper) 1.297 + 1.298 + void 1.299 + ClearSelfRef() 1.300 + { 1.301 + AssertIsOnParentThread(); 1.302 + MOZ_ASSERT(mSelfRef); 1.303 + mSelfRef = nullptr; 1.304 + } 1.305 + 1.306 + nsresult 1.307 + Dispatch(WorkerRunnable* aRunnable) 1.308 + { 1.309 + return DispatchPrivate(aRunnable, nullptr); 1.310 + } 1.311 + 1.312 + nsresult 1.313 + DispatchControlRunnable(WorkerControlRunnable* aWorkerControlRunnable); 1.314 + 1.315 + already_AddRefed<WorkerRunnable> 1.316 + MaybeWrapAsWorkerRunnable(nsIRunnable* aRunnable); 1.317 + 1.318 + already_AddRefed<nsIEventTarget> 1.319 + GetEventTarget(); 1.320 + 1.321 + // May be called on any thread... 1.322 + bool 1.323 + Start(); 1.324 + 1.325 + // Called on the parent thread. 1.326 + bool 1.327 + Notify(JSContext* aCx, Status aStatus) 1.328 + { 1.329 + return NotifyPrivate(aCx, aStatus); 1.330 + } 1.331 + 1.332 + bool 1.333 + Cancel(JSContext* aCx) 1.334 + { 1.335 + return Notify(aCx, Canceling); 1.336 + } 1.337 + 1.338 + bool 1.339 + Kill(JSContext* aCx) 1.340 + { 1.341 + return Notify(aCx, Killing); 1.342 + } 1.343 + 1.344 + bool 1.345 + Suspend(JSContext* aCx, nsPIDOMWindow* aWindow); 1.346 + 1.347 + bool 1.348 + Resume(JSContext* aCx, nsPIDOMWindow* aWindow); 1.349 + 1.350 + bool 1.351 + SynchronizeAndResume(JSContext* aCx, nsPIDOMWindow* aWindow, 1.352 + nsIScriptContext* aScriptContext); 1.353 + 1.354 + bool 1.355 + Terminate(JSContext* aCx) 1.356 + { 1.357 + AssertIsOnParentThread(); 1.358 + return TerminatePrivate(aCx); 1.359 + } 1.360 + 1.361 + bool 1.362 + Close(JSContext* aCx); 1.363 + 1.364 + bool 1.365 + ModifyBusyCount(JSContext* aCx, bool aIncrease); 1.366 + 1.367 + void 1.368 + ForgetMainThreadObjects(nsTArray<nsCOMPtr<nsISupports> >& aDoomed); 1.369 + 1.370 + void 1.371 + PostMessage(JSContext* aCx, JS::Handle<JS::Value> aMessage, 1.372 + const Optional<Sequence<JS::Value> >& aTransferable, 1.373 + ErrorResult& aRv) 1.374 + { 1.375 + PostMessageInternal(aCx, aMessage, aTransferable, false, 0, aRv); 1.376 + } 1.377 + 1.378 + void 1.379 + PostMessageToMessagePort(JSContext* aCx, 1.380 + uint64_t aMessagePortSerial, 1.381 + JS::Handle<JS::Value> aMessage, 1.382 + const Optional<Sequence<JS::Value> >& aTransferable, 1.383 + ErrorResult& aRv); 1.384 + 1.385 + bool 1.386 + DispatchMessageEventToMessagePort( 1.387 + JSContext* aCx, 1.388 + uint64_t aMessagePortSerial, 1.389 + JSAutoStructuredCloneBuffer&& aBuffer, 1.390 + nsTArray<nsCOMPtr<nsISupports>>& aClonedObjects); 1.391 + 1.392 + uint64_t 1.393 + GetInnerWindowId(); 1.394 + 1.395 + void 1.396 + UpdateRuntimeAndContextOptions(JSContext* aCx, 1.397 + const JS::RuntimeOptions& aRuntimeOptions, 1.398 + const JS::ContextOptions& aContentCxOptions, 1.399 + const JS::ContextOptions& aChromeCxOptions); 1.400 + 1.401 + void 1.402 + UpdatePreference(JSContext* aCx, WorkerPreference aPref, bool aValue); 1.403 + 1.404 + void 1.405 + UpdateJSWorkerMemoryParameter(JSContext* aCx, JSGCParamKey key, 1.406 + uint32_t value); 1.407 + 1.408 +#ifdef JS_GC_ZEAL 1.409 + void 1.410 + UpdateGCZeal(JSContext* aCx, uint8_t aGCZeal, uint32_t aFrequency); 1.411 +#endif 1.412 + 1.413 + void 1.414 + GarbageCollect(JSContext* aCx, bool aShrinking); 1.415 + 1.416 + void 1.417 + CycleCollect(JSContext* aCx, bool aDummy); 1.418 + 1.419 + void 1.420 + OfflineStatusChangeEvent(JSContext* aCx, bool aIsOffline); 1.421 + 1.422 + bool 1.423 + RegisterSharedWorker(JSContext* aCx, SharedWorker* aSharedWorker); 1.424 + 1.425 + void 1.426 + UnregisterSharedWorker(JSContext* aCx, SharedWorker* aSharedWorker); 1.427 + 1.428 + void 1.429 + BroadcastErrorToSharedWorkers(JSContext* aCx, 1.430 + const nsAString& aMessage, 1.431 + const nsAString& aFilename, 1.432 + const nsAString& aLine, 1.433 + uint32_t aLineNumber, 1.434 + uint32_t aColumnNumber, 1.435 + uint32_t aFlags); 1.436 + 1.437 + void 1.438 + WorkerScriptLoaded(); 1.439 + 1.440 + void 1.441 + QueueRunnable(nsIRunnable* aRunnable) 1.442 + { 1.443 + AssertIsOnMainThread(); 1.444 + mQueuedRunnables.AppendElement(aRunnable); 1.445 + } 1.446 + 1.447 + WorkerPrivate* 1.448 + GetParent() const 1.449 + { 1.450 + return mParent; 1.451 + } 1.452 + 1.453 + bool 1.454 + IsSuspended() const 1.455 + { 1.456 + AssertIsOnParentThread(); 1.457 + return mParentSuspended; 1.458 + } 1.459 + 1.460 + bool 1.461 + IsAcceptingEvents() 1.462 + { 1.463 + AssertIsOnParentThread(); 1.464 + 1.465 + MutexAutoLock lock(mMutex); 1.466 + return mParentStatus < Terminating; 1.467 + } 1.468 + 1.469 + Status 1.470 + ParentStatus() const 1.471 + { 1.472 + mMutex.AssertCurrentThreadOwns(); 1.473 + return mParentStatus; 1.474 + } 1.475 + 1.476 + JSContext* 1.477 + ParentJSContext() const; 1.478 + 1.479 + nsIScriptContext* 1.480 + GetScriptContext() const 1.481 + { 1.482 + AssertIsOnMainThread(); 1.483 + return mLoadInfo.mScriptContext; 1.484 + } 1.485 + 1.486 + const nsString& 1.487 + ScriptURL() const 1.488 + { 1.489 + return mScriptURL; 1.490 + } 1.491 + 1.492 + const nsCString& 1.493 + Domain() const 1.494 + { 1.495 + return mLoadInfo.mDomain; 1.496 + } 1.497 + 1.498 + nsIURI* 1.499 + GetBaseURI() const 1.500 + { 1.501 + AssertIsOnMainThread(); 1.502 + return mLoadInfo.mBaseURI; 1.503 + } 1.504 + 1.505 + void 1.506 + SetBaseURI(nsIURI* aBaseURI); 1.507 + 1.508 + nsIURI* 1.509 + GetResolvedScriptURI() const 1.510 + { 1.511 + AssertIsOnMainThread(); 1.512 + return mLoadInfo.mResolvedScriptURI; 1.513 + } 1.514 + 1.515 + TimeStamp CreationTimeStamp() const 1.516 + { 1.517 + return mCreationTimeStamp; 1.518 + } 1.519 + 1.520 + nsIPrincipal* 1.521 + GetPrincipal() const 1.522 + { 1.523 + AssertIsOnMainThread(); 1.524 + return mLoadInfo.mPrincipal; 1.525 + } 1.526 + 1.527 + // This method allows the principal to be retrieved off the main thread. 1.528 + // Principals are main-thread objects so the caller must ensure that all 1.529 + // access occurs on the main thread. 1.530 + nsIPrincipal* 1.531 + GetPrincipalDontAssertMainThread() const 1.532 + { 1.533 + return mLoadInfo.mPrincipal; 1.534 + } 1.535 + 1.536 + void 1.537 + SetPrincipal(nsIPrincipal* aPrincipal); 1.538 + 1.539 + bool 1.540 + UsesSystemPrincipal() const 1.541 + { 1.542 + return mLoadInfo.mPrincipalIsSystem; 1.543 + } 1.544 + 1.545 + bool 1.546 + IsInPrivilegedApp() const 1.547 + { 1.548 + return mLoadInfo.mIsInPrivilegedApp; 1.549 + } 1.550 + 1.551 + bool 1.552 + IsInCertifiedApp() const 1.553 + { 1.554 + return mLoadInfo.mIsInCertifiedApp; 1.555 + } 1.556 + 1.557 + already_AddRefed<nsIChannel> 1.558 + ForgetWorkerChannel() 1.559 + { 1.560 + AssertIsOnMainThread(); 1.561 + return mLoadInfo.mChannel.forget(); 1.562 + } 1.563 + 1.564 + nsIDocument* 1.565 + GetDocument() const 1.566 + { 1.567 + AssertIsOnMainThread(); 1.568 + return mLoadInfo.mWindow ? mLoadInfo.mWindow->GetExtantDoc() : nullptr; 1.569 + } 1.570 + 1.571 + nsPIDOMWindow* 1.572 + GetWindow() 1.573 + { 1.574 + AssertIsOnMainThread(); 1.575 + return mLoadInfo.mWindow; 1.576 + } 1.577 + 1.578 + nsIContentSecurityPolicy* 1.579 + GetCSP() const 1.580 + { 1.581 + AssertIsOnMainThread(); 1.582 + return mLoadInfo.mCSP; 1.583 + } 1.584 + 1.585 + void 1.586 + SetCSP(nsIContentSecurityPolicy* aCSP) 1.587 + { 1.588 + AssertIsOnMainThread(); 1.589 + mLoadInfo.mCSP = aCSP; 1.590 + } 1.591 + 1.592 + bool 1.593 + IsEvalAllowed() const 1.594 + { 1.595 + return mLoadInfo.mEvalAllowed; 1.596 + } 1.597 + 1.598 + void 1.599 + SetEvalAllowed(bool aEvalAllowed) 1.600 + { 1.601 + mLoadInfo.mEvalAllowed = aEvalAllowed; 1.602 + } 1.603 + 1.604 + bool 1.605 + GetReportCSPViolations() const 1.606 + { 1.607 + return mLoadInfo.mReportCSPViolations; 1.608 + } 1.609 + 1.610 + bool 1.611 + XHRParamsAllowed() const 1.612 + { 1.613 + return mLoadInfo.mXHRParamsAllowed; 1.614 + } 1.615 + 1.616 + void 1.617 + SetXHRParamsAllowed(bool aAllowed) 1.618 + { 1.619 + mLoadInfo.mXHRParamsAllowed = aAllowed; 1.620 + } 1.621 + 1.622 + LocationInfo& 1.623 + GetLocationInfo() 1.624 + { 1.625 + return mLocationInfo; 1.626 + } 1.627 + 1.628 + void 1.629 + CopyJSSettings(JSSettings& aSettings) 1.630 + { 1.631 + mozilla::MutexAutoLock lock(mMutex); 1.632 + aSettings = mJSSettings; 1.633 + } 1.634 + 1.635 + void 1.636 + CopyJSCompartmentOptions(JS::CompartmentOptions& aOptions) 1.637 + { 1.638 + mozilla::MutexAutoLock lock(mMutex); 1.639 + aOptions = IsChromeWorker() ? mJSSettings.chrome.compartmentOptions 1.640 + : mJSSettings.content.compartmentOptions; 1.641 + } 1.642 + 1.643 + // The ability to be a chrome worker is orthogonal to the type of 1.644 + // worker [Dedicated|Shared]. 1.645 + bool 1.646 + IsChromeWorker() const 1.647 + { 1.648 + return mIsChromeWorker; 1.649 + } 1.650 + 1.651 + bool 1.652 + IsDedicatedWorker() const 1.653 + { 1.654 + return mWorkerType == WorkerTypeDedicated; 1.655 + } 1.656 + 1.657 + bool 1.658 + IsSharedWorker() const 1.659 + { 1.660 + return mWorkerType == WorkerTypeShared; 1.661 + } 1.662 + 1.663 + const nsCString& 1.664 + SharedWorkerName() const 1.665 + { 1.666 + return mSharedWorkerName; 1.667 + } 1.668 + 1.669 + uint64_t 1.670 + NextMessagePortSerial() 1.671 + { 1.672 + AssertIsOnMainThread(); 1.673 + return mMessagePortSerial++; 1.674 + } 1.675 + 1.676 + void 1.677 + GetAllSharedWorkers(nsTArray<nsRefPtr<SharedWorker>>& aSharedWorkers); 1.678 + 1.679 + void 1.680 + CloseSharedWorkersForWindow(nsPIDOMWindow* aWindow); 1.681 + 1.682 + void 1.683 + RegisterHostObjectURI(const nsACString& aURI); 1.684 + 1.685 + void 1.686 + UnregisterHostObjectURI(const nsACString& aURI); 1.687 + 1.688 + void 1.689 + StealHostObjectURIs(nsTArray<nsCString>& aArray); 1.690 + 1.691 + IMPL_EVENT_HANDLER(message) 1.692 + IMPL_EVENT_HANDLER(error) 1.693 + 1.694 +#ifdef DEBUG 1.695 + void 1.696 + AssertIsOnParentThread() const; 1.697 + 1.698 + void 1.699 + AssertInnerWindowIsCorrect() const; 1.700 +#else 1.701 + void 1.702 + AssertIsOnParentThread() const 1.703 + { } 1.704 + 1.705 + void 1.706 + AssertInnerWindowIsCorrect() const 1.707 + { } 1.708 +#endif 1.709 +}; 1.710 + 1.711 +class WorkerPrivate : public WorkerPrivateParent<WorkerPrivate> 1.712 +{ 1.713 + friend class WorkerPrivateParent<WorkerPrivate>; 1.714 + typedef WorkerPrivateParent<WorkerPrivate> ParentType; 1.715 + friend class AutoSyncLoopHolder; 1.716 + 1.717 + struct TimeoutInfo; 1.718 + 1.719 + class MemoryReporter; 1.720 + friend class MemoryReporter; 1.721 + 1.722 + enum GCTimerMode 1.723 + { 1.724 + PeriodicTimer = 0, 1.725 + IdleTimer, 1.726 + NoTimer 1.727 + }; 1.728 + 1.729 + Queue<WorkerControlRunnable*, 4> mControlQueue; 1.730 + 1.731 + // Touched on multiple threads, protected with mMutex. 1.732 + JSContext* mJSContext; 1.733 + nsRefPtr<WorkerCrossThreadDispatcher> mCrossThreadDispatcher; 1.734 + nsTArray<nsCOMPtr<nsIRunnable>> mUndispatchedRunnablesForSyncLoop; 1.735 + nsCOMPtr<nsIThread> mThread; 1.736 + 1.737 + // Things touched on worker thread only. 1.738 + nsRefPtr<WorkerGlobalScope> mScope; 1.739 + nsTArray<ParentType*> mChildWorkers; 1.740 + nsTArray<WorkerFeature*> mFeatures; 1.741 + nsTArray<nsAutoPtr<TimeoutInfo>> mTimeouts; 1.742 + 1.743 + struct SyncLoopInfo 1.744 + { 1.745 + SyncLoopInfo(EventTarget* aEventTarget); 1.746 + 1.747 + nsRefPtr<EventTarget> mEventTarget; 1.748 + bool mCompleted; 1.749 + bool mResult; 1.750 +#ifdef DEBUG 1.751 + bool mHasRun; 1.752 +#endif 1.753 + }; 1.754 + 1.755 + // This is only modified on the worker thread, but in DEBUG builds 1.756 + // AssertValidSyncLoop function iterates it on other threads. Therefore 1.757 + // modifications are done with mMutex held *only* in DEBUG builds. 1.758 + nsTArray<nsAutoPtr<SyncLoopInfo>> mSyncLoopStack; 1.759 + 1.760 + nsCOMPtr<nsITimer> mTimer; 1.761 + 1.762 + nsCOMPtr<nsITimer> mGCTimer; 1.763 + nsCOMPtr<nsIEventTarget> mPeriodicGCTimerTarget; 1.764 + nsCOMPtr<nsIEventTarget> mIdleGCTimerTarget; 1.765 + 1.766 + nsRefPtr<MemoryReporter> mMemoryReporter; 1.767 + 1.768 + nsRefPtrHashtable<nsUint64HashKey, MessagePort> mWorkerPorts; 1.769 + 1.770 + TimeStamp mKillTime; 1.771 + uint32_t mErrorHandlerRecursionCount; 1.772 + uint32_t mNextTimeoutId; 1.773 + Status mStatus; 1.774 + bool mSuspended; 1.775 + bool mTimerRunning; 1.776 + bool mRunningExpiredTimeouts; 1.777 + bool mCloseHandlerStarted; 1.778 + bool mCloseHandlerFinished; 1.779 + bool mMemoryReporterRunning; 1.780 + bool mBlockedForMemoryReporter; 1.781 + bool mCancelAllPendingRunnables; 1.782 + bool mPeriodicGCTimerRunning; 1.783 + bool mIdleGCTimerRunning; 1.784 + 1.785 +#ifdef DEBUG 1.786 + PRThread* mPRThread; 1.787 +#endif 1.788 + 1.789 + bool mPreferences[WORKERPREF_COUNT]; 1.790 + bool mOnLine; 1.791 + 1.792 +protected: 1.793 + ~WorkerPrivate(); 1.794 + 1.795 +public: 1.796 + static already_AddRefed<WorkerPrivate> 1.797 + Constructor(const GlobalObject& aGlobal, const nsAString& aScriptURL, 1.798 + ErrorResult& aRv); 1.799 + 1.800 + static already_AddRefed<WorkerPrivate> 1.801 + Constructor(const GlobalObject& aGlobal, const nsAString& aScriptURL, 1.802 + bool aIsChromeWorker, WorkerType aWorkerType, 1.803 + const nsACString& aSharedWorkerName, 1.804 + LoadInfo* aLoadInfo, ErrorResult& aRv); 1.805 + 1.806 + static bool 1.807 + WorkerAvailable(JSContext* /* unused */, JSObject* /* unused */); 1.808 + 1.809 + static nsresult 1.810 + GetLoadInfo(JSContext* aCx, nsPIDOMWindow* aWindow, WorkerPrivate* aParent, 1.811 + const nsAString& aScriptURL, bool aIsChromeWorker, 1.812 + LoadInfo* aLoadInfo); 1.813 + 1.814 + void 1.815 + DoRunLoop(JSContext* aCx); 1.816 + 1.817 + bool 1.818 + InterruptCallback(JSContext* aCx); 1.819 + 1.820 + nsresult 1.821 + IsOnCurrentThread(bool* aIsOnCurrentThread); 1.822 + 1.823 + bool 1.824 + CloseInternal(JSContext* aCx) 1.825 + { 1.826 + AssertIsOnWorkerThread(); 1.827 + return NotifyInternal(aCx, Closing); 1.828 + } 1.829 + 1.830 + bool 1.831 + SuspendInternal(JSContext* aCx); 1.832 + 1.833 + bool 1.834 + ResumeInternal(JSContext* aCx); 1.835 + 1.836 + void 1.837 + TraceTimeouts(const TraceCallbacks& aCallbacks, void* aClosure) const; 1.838 + 1.839 + bool 1.840 + ModifyBusyCountFromWorker(JSContext* aCx, bool aIncrease); 1.841 + 1.842 + bool 1.843 + AddChildWorker(JSContext* aCx, ParentType* aChildWorker); 1.844 + 1.845 + void 1.846 + RemoveChildWorker(JSContext* aCx, ParentType* aChildWorker); 1.847 + 1.848 + bool 1.849 + AddFeature(JSContext* aCx, WorkerFeature* aFeature); 1.850 + 1.851 + void 1.852 + RemoveFeature(JSContext* aCx, WorkerFeature* aFeature); 1.853 + 1.854 + void 1.855 + NotifyFeatures(JSContext* aCx, Status aStatus); 1.856 + 1.857 + bool 1.858 + HasActiveFeatures() 1.859 + { 1.860 + return !(mChildWorkers.IsEmpty() && mTimeouts.IsEmpty() && 1.861 + mFeatures.IsEmpty()); 1.862 + } 1.863 + 1.864 + void 1.865 + PostMessageToParent(JSContext* aCx, 1.866 + JS::Handle<JS::Value> aMessage, 1.867 + const Optional<Sequence<JS::Value>>& aTransferable, 1.868 + ErrorResult& aRv) 1.869 + { 1.870 + PostMessageToParentInternal(aCx, aMessage, aTransferable, false, 0, aRv); 1.871 + } 1.872 + 1.873 + void 1.874 + PostMessageToParentMessagePort( 1.875 + JSContext* aCx, 1.876 + uint64_t aMessagePortSerial, 1.877 + JS::Handle<JS::Value> aMessage, 1.878 + const Optional<Sequence<JS::Value>>& aTransferable, 1.879 + ErrorResult& aRv); 1.880 + 1.881 + bool 1.882 + NotifyInternal(JSContext* aCx, Status aStatus); 1.883 + 1.884 + void 1.885 + ReportError(JSContext* aCx, const char* aMessage, JSErrorReport* aReport); 1.886 + 1.887 + int32_t 1.888 + SetTimeout(JSContext* aCx, 1.889 + Function* aHandler, 1.890 + const nsAString& aStringHandler, 1.891 + int32_t aTimeout, 1.892 + const Sequence<JS::Value>& aArguments, 1.893 + bool aIsInterval, 1.894 + ErrorResult& aRv); 1.895 + 1.896 + void 1.897 + ClearTimeout(int32_t aId); 1.898 + 1.899 + bool 1.900 + RunExpiredTimeouts(JSContext* aCx); 1.901 + 1.902 + bool 1.903 + RescheduleTimeoutTimer(JSContext* aCx); 1.904 + 1.905 + void 1.906 + CloseHandlerStarted() 1.907 + { 1.908 + AssertIsOnWorkerThread(); 1.909 + mCloseHandlerStarted = true; 1.910 + } 1.911 + 1.912 + void 1.913 + CloseHandlerFinished() 1.914 + { 1.915 + AssertIsOnWorkerThread(); 1.916 + mCloseHandlerFinished = true; 1.917 + } 1.918 + 1.919 + void 1.920 + UpdateRuntimeAndContextOptionsInternal( 1.921 + JSContext* aCx, 1.922 + const JS::RuntimeOptions& aRuntimeOptions, 1.923 + const JS::ContextOptions& aContentCxOptions, 1.924 + const JS::ContextOptions& aChromeCxOptions); 1.925 + 1.926 + void 1.927 + UpdatePreferenceInternal(JSContext* aCx, WorkerPreference aPref, bool aValue); 1.928 + 1.929 + void 1.930 + UpdateJSWorkerMemoryParameterInternal(JSContext* aCx, JSGCParamKey key, uint32_t aValue); 1.931 + 1.932 + enum WorkerRanOrNot { 1.933 + WorkerNeverRan = 0, 1.934 + WorkerRan 1.935 + }; 1.936 + 1.937 + void 1.938 + ScheduleDeletion(WorkerRanOrNot aRanOrNot); 1.939 + 1.940 + bool 1.941 + BlockAndCollectRuntimeStats(JS::RuntimeStats* aRtStats); 1.942 + 1.943 +#ifdef JS_GC_ZEAL 1.944 + void 1.945 + UpdateGCZealInternal(JSContext* aCx, uint8_t aGCZeal, uint32_t aFrequency); 1.946 +#endif 1.947 + 1.948 + void 1.949 + GarbageCollectInternal(JSContext* aCx, bool aShrinking, 1.950 + bool aCollectChildren); 1.951 + 1.952 + void 1.953 + CycleCollectInternal(JSContext* aCx, bool aCollectChildren); 1.954 + 1.955 + void 1.956 + OfflineStatusChangeEventInternal(JSContext* aCx, bool aIsOffline); 1.957 + 1.958 + JSContext* 1.959 + GetJSContext() const 1.960 + { 1.961 + AssertIsOnWorkerThread(); 1.962 + return mJSContext; 1.963 + } 1.964 + 1.965 + WorkerGlobalScope* 1.966 + GlobalScope() const 1.967 + { 1.968 + AssertIsOnWorkerThread(); 1.969 + return mScope; 1.970 + } 1.971 + 1.972 + void 1.973 + SetThread(nsIThread* aThread); 1.974 + 1.975 + void 1.976 + AssertIsOnWorkerThread() const 1.977 +#ifdef DEBUG 1.978 + ; 1.979 +#else 1.980 + { } 1.981 +#endif 1.982 + 1.983 + WorkerCrossThreadDispatcher* 1.984 + GetCrossThreadDispatcher(); 1.985 + 1.986 + // This may block! 1.987 + void 1.988 + BeginCTypesCall(); 1.989 + 1.990 + // This may block! 1.991 + void 1.992 + EndCTypesCall(); 1.993 + 1.994 + void 1.995 + BeginCTypesCallback() 1.996 + { 1.997 + // If a callback is beginning then we need to do the exact same thing as 1.998 + // when a ctypes call ends. 1.999 + EndCTypesCall(); 1.1000 + } 1.1001 + 1.1002 + void 1.1003 + EndCTypesCallback() 1.1004 + { 1.1005 + // If a callback is ending then we need to do the exact same thing as 1.1006 + // when a ctypes call begins. 1.1007 + BeginCTypesCall(); 1.1008 + } 1.1009 + 1.1010 + bool 1.1011 + ConnectMessagePort(JSContext* aCx, uint64_t aMessagePortSerial); 1.1012 + 1.1013 + void 1.1014 + DisconnectMessagePort(uint64_t aMessagePortSerial); 1.1015 + 1.1016 + MessagePort* 1.1017 + GetMessagePort(uint64_t aMessagePortSerial); 1.1018 + 1.1019 + JSObject* 1.1020 + CreateGlobalScope(JSContext* aCx); 1.1021 + 1.1022 + bool 1.1023 + RegisterBindings(JSContext* aCx, JS::Handle<JSObject*> aGlobal); 1.1024 + 1.1025 + bool 1.1026 + DumpEnabled() const 1.1027 + { 1.1028 + AssertIsOnWorkerThread(); 1.1029 + return mPreferences[WORKERPREF_DUMP]; 1.1030 + } 1.1031 + 1.1032 + bool 1.1033 + OnLine() const 1.1034 + { 1.1035 + AssertIsOnWorkerThread(); 1.1036 + return mOnLine; 1.1037 + } 1.1038 + 1.1039 + void 1.1040 + StopSyncLoop(nsIEventTarget* aSyncLoopTarget, bool aResult); 1.1041 + 1.1042 + bool 1.1043 + AllPendingRunnablesShouldBeCanceled() const 1.1044 + { 1.1045 + return mCancelAllPendingRunnables; 1.1046 + } 1.1047 + 1.1048 + void 1.1049 + OnProcessNextEvent(uint32_t aRecursionDepth); 1.1050 + 1.1051 + void 1.1052 + AfterProcessNextEvent(uint32_t aRecursionDepth); 1.1053 + 1.1054 + void 1.1055 + AssertValidSyncLoop(nsIEventTarget* aSyncLoopTarget) 1.1056 +#ifdef DEBUG 1.1057 + ; 1.1058 +#else 1.1059 + { } 1.1060 +#endif 1.1061 + 1.1062 +private: 1.1063 + WorkerPrivate(JSContext* aCx, WorkerPrivate* aParent, 1.1064 + const nsAString& aScriptURL, bool aIsChromeWorker, 1.1065 + WorkerType aWorkerType, const nsACString& aSharedWorkerName, 1.1066 + LoadInfo& aLoadInfo); 1.1067 + 1.1068 + void 1.1069 + ClearMainEventQueue(WorkerRanOrNot aRanOrNot); 1.1070 + 1.1071 + bool 1.1072 + MayContinueRunning() 1.1073 + { 1.1074 + AssertIsOnWorkerThread(); 1.1075 + 1.1076 + Status status; 1.1077 + { 1.1078 + MutexAutoLock lock(mMutex); 1.1079 + status = mStatus; 1.1080 + } 1.1081 + 1.1082 + if (status >= Killing) { 1.1083 + return false; 1.1084 + } 1.1085 + if (status >= Running) { 1.1086 + return mKillTime.IsNull() || RemainingRunTimeMS() > 0; 1.1087 + } 1.1088 + return true; 1.1089 + } 1.1090 + 1.1091 + uint32_t 1.1092 + RemainingRunTimeMS() const; 1.1093 + 1.1094 + void 1.1095 + CancelAllTimeouts(JSContext* aCx); 1.1096 + 1.1097 + bool 1.1098 + ScheduleKillCloseEventRunnable(JSContext* aCx); 1.1099 + 1.1100 + bool 1.1101 + ProcessAllControlRunnables() 1.1102 + { 1.1103 + MutexAutoLock lock(mMutex); 1.1104 + return ProcessAllControlRunnablesLocked(); 1.1105 + } 1.1106 + 1.1107 + bool 1.1108 + ProcessAllControlRunnablesLocked(); 1.1109 + 1.1110 + void 1.1111 + EnableMemoryReporter(); 1.1112 + 1.1113 + void 1.1114 + DisableMemoryReporter(); 1.1115 + 1.1116 + void 1.1117 + WaitForWorkerEvents(PRIntervalTime interval = PR_INTERVAL_NO_TIMEOUT); 1.1118 + 1.1119 + void 1.1120 + PostMessageToParentInternal(JSContext* aCx, 1.1121 + JS::Handle<JS::Value> aMessage, 1.1122 + const Optional<Sequence<JS::Value>>& aTransferable, 1.1123 + bool aToMessagePort, 1.1124 + uint64_t aMessagePortSerial, 1.1125 + ErrorResult& aRv); 1.1126 + 1.1127 + void 1.1128 + GetAllPreferences(bool aPreferences[WORKERPREF_COUNT]) const 1.1129 + { 1.1130 + AssertIsOnWorkerThread(); 1.1131 + memcpy(aPreferences, mPreferences, WORKERPREF_COUNT * sizeof(bool)); 1.1132 + } 1.1133 + 1.1134 + already_AddRefed<nsIEventTarget> 1.1135 + CreateNewSyncLoop(); 1.1136 + 1.1137 + bool 1.1138 + RunCurrentSyncLoop(); 1.1139 + 1.1140 + bool 1.1141 + DestroySyncLoop(uint32_t aLoopIndex, nsIThreadInternal* aThread = nullptr); 1.1142 + 1.1143 + void 1.1144 + InitializeGCTimers(); 1.1145 + 1.1146 + void 1.1147 + SetGCTimerMode(GCTimerMode aMode); 1.1148 + 1.1149 + void 1.1150 + ShutdownGCTimers(); 1.1151 +}; 1.1152 + 1.1153 +// This class is only used to trick the DOM bindings. We never create 1.1154 +// instances of it, and static_casting to it is fine since it doesn't add 1.1155 +// anything to WorkerPrivate. 1.1156 +class ChromeWorkerPrivate : public WorkerPrivate 1.1157 +{ 1.1158 +public: 1.1159 + static already_AddRefed<ChromeWorkerPrivate> 1.1160 + Constructor(const GlobalObject& aGlobal, const nsAString& aScriptURL, 1.1161 + ErrorResult& rv); 1.1162 + 1.1163 + static bool 1.1164 + WorkerAvailable(JSContext* /* unused */, JSObject* /* unused */); 1.1165 + 1.1166 +private: 1.1167 + ChromeWorkerPrivate() MOZ_DELETE; 1.1168 + ChromeWorkerPrivate(const ChromeWorkerPrivate& aRHS) MOZ_DELETE; 1.1169 + ChromeWorkerPrivate& operator =(const ChromeWorkerPrivate& aRHS) MOZ_DELETE; 1.1170 +}; 1.1171 + 1.1172 +WorkerPrivate* 1.1173 +GetWorkerPrivateFromContext(JSContext* aCx); 1.1174 + 1.1175 +WorkerPrivate* 1.1176 +GetCurrentThreadWorkerPrivate(); 1.1177 + 1.1178 +bool 1.1179 +IsCurrentThreadRunningChromeWorker(); 1.1180 + 1.1181 +JSContext* 1.1182 +GetCurrentThreadJSContext(); 1.1183 + 1.1184 +enum WorkerStructuredDataType 1.1185 +{ 1.1186 + DOMWORKER_SCTAG_FILE = SCTAG_DOM_MAX, 1.1187 + DOMWORKER_SCTAG_BLOB, 1.1188 + 1.1189 + DOMWORKER_SCTAG_END 1.1190 +}; 1.1191 + 1.1192 +JSStructuredCloneCallbacks* 1.1193 +WorkerStructuredCloneCallbacks(bool aMainRuntime); 1.1194 + 1.1195 +JSStructuredCloneCallbacks* 1.1196 +ChromeWorkerStructuredCloneCallbacks(bool aMainRuntime); 1.1197 + 1.1198 +class AutoSyncLoopHolder 1.1199 +{ 1.1200 + WorkerPrivate* mWorkerPrivate; 1.1201 + nsCOMPtr<nsIEventTarget> mTarget; 1.1202 + uint32_t mIndex; 1.1203 + 1.1204 +public: 1.1205 + AutoSyncLoopHolder(WorkerPrivate* aWorkerPrivate) 1.1206 + : mWorkerPrivate(aWorkerPrivate) 1.1207 + , mTarget(aWorkerPrivate->CreateNewSyncLoop()) 1.1208 + , mIndex(aWorkerPrivate->mSyncLoopStack.Length() - 1) 1.1209 + { 1.1210 + aWorkerPrivate->AssertIsOnWorkerThread(); 1.1211 + } 1.1212 + 1.1213 + ~AutoSyncLoopHolder() 1.1214 + { 1.1215 + if (mWorkerPrivate) { 1.1216 + mWorkerPrivate->AssertIsOnWorkerThread(); 1.1217 + mWorkerPrivate->StopSyncLoop(mTarget, false); 1.1218 + mWorkerPrivate->DestroySyncLoop(mIndex); 1.1219 + } 1.1220 + } 1.1221 + 1.1222 + bool 1.1223 + Run() 1.1224 + { 1.1225 + WorkerPrivate* workerPrivate = mWorkerPrivate; 1.1226 + mWorkerPrivate = nullptr; 1.1227 + 1.1228 + workerPrivate->AssertIsOnWorkerThread(); 1.1229 + 1.1230 + return workerPrivate->RunCurrentSyncLoop(); 1.1231 + } 1.1232 + 1.1233 + nsIEventTarget* 1.1234 + EventTarget() const 1.1235 + { 1.1236 + return mTarget; 1.1237 + } 1.1238 +}; 1.1239 + 1.1240 +END_WORKERS_NAMESPACE 1.1241 + 1.1242 +#endif /* mozilla_dom_workers_workerprivate_h__ */