1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/dom/workers/WorkerRunnable.h Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,347 @@ 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_workerrunnable_h__ 1.10 +#define mozilla_dom_workers_workerrunnable_h__ 1.11 + 1.12 +#include "Workers.h" 1.13 + 1.14 +#include "nsICancelableRunnable.h" 1.15 + 1.16 +#include "mozilla/Atomics.h" 1.17 +#include "nsISupportsImpl.h" 1.18 + 1.19 +class JSContext; 1.20 +class nsIEventTarget; 1.21 + 1.22 +BEGIN_WORKERS_NAMESPACE 1.23 + 1.24 +class WorkerPrivate; 1.25 + 1.26 +// Use this runnable to communicate from the worker to its parent or vice-versa. 1.27 +// The busy count must be taken into consideration and declared at construction 1.28 +// time. 1.29 +class WorkerRunnable : public nsICancelableRunnable 1.30 +{ 1.31 +public: 1.32 + enum TargetAndBusyBehavior { 1.33 + // Target the main thread for top-level workers, otherwise target the 1.34 + // WorkerThread of the worker's parent. No change to the busy count. 1.35 + ParentThreadUnchangedBusyCount, 1.36 + 1.37 + // Target the thread where the worker event loop runs. The busy count will 1.38 + // be incremented before dispatching and decremented (asynchronously) after 1.39 + // running. 1.40 + WorkerThreadModifyBusyCount, 1.41 + 1.42 + // Target the thread where the worker event loop runs. The busy count will 1.43 + // not be modified in any way. Besides worker-internal runnables this is 1.44 + // almost always the wrong choice. 1.45 + WorkerThreadUnchangedBusyCount 1.46 + }; 1.47 + 1.48 +protected: 1.49 + // The WorkerPrivate that this runnable is associated with. 1.50 + WorkerPrivate* mWorkerPrivate; 1.51 + 1.52 + // See above. 1.53 + TargetAndBusyBehavior mBehavior; 1.54 + 1.55 + // It's unclear whether or not Cancel() is supposed to work when called on any 1.56 + // thread. To be safe we're using an atomic but it's likely overkill. 1.57 + Atomic<uint32_t> mCanceled; 1.58 + 1.59 +private: 1.60 + // Whether or not Cancel() is currently being called from inside the Run() 1.61 + // method. Avoids infinite recursion when a subclass calls Run() from inside 1.62 + // Cancel(). Only checked and modified on the target thread. 1.63 + bool mCallingCancelWithinRun; 1.64 + 1.65 +public: 1.66 + NS_DECL_THREADSAFE_ISUPPORTS 1.67 + 1.68 + // If you override Cancel() then you'll need to either call the base class 1.69 + // Cancel() method or override IsCanceled() so that the Run() method bails out 1.70 + // appropriately. 1.71 + NS_DECL_NSICANCELABLERUNNABLE 1.72 + 1.73 + // Passing a JSContext here is required for the WorkerThreadModifyBusyCount 1.74 + // behavior. It also guarantees that any failure (false return) will throw an 1.75 + // exception on the given context. If a context is not passed then failures 1.76 + // must be dealt with by the caller. 1.77 + bool 1.78 + Dispatch(JSContext* aCx); 1.79 + 1.80 + // See above note about Cancel(). 1.81 + virtual bool 1.82 + IsCanceled() const 1.83 + { 1.84 + return mCanceled != 0; 1.85 + } 1.86 + 1.87 + static WorkerRunnable* 1.88 + FromRunnable(nsIRunnable* aRunnable); 1.89 + 1.90 +protected: 1.91 + WorkerRunnable(WorkerPrivate* aWorkerPrivate, TargetAndBusyBehavior aBehavior) 1.92 +#ifdef DEBUG 1.93 + ; 1.94 +#else 1.95 + : mWorkerPrivate(aWorkerPrivate), mBehavior(aBehavior), mCanceled(0), 1.96 + mCallingCancelWithinRun(false) 1.97 + { } 1.98 +#endif 1.99 + 1.100 + // This class is reference counted. 1.101 + virtual ~WorkerRunnable() 1.102 + { } 1.103 + 1.104 + // By default asserts that Dispatch() is being called on the right thread 1.105 + // (ParentThread if |mTarget| is WorkerThread, or WorkerThread otherwise). 1.106 + // Also increments the busy count of |mWorkerPrivate| if targeting the 1.107 + // WorkerThread. 1.108 + virtual bool 1.109 + PreDispatch(JSContext* aCx, WorkerPrivate* aWorkerPrivate); 1.110 + 1.111 + // By default asserts that Dispatch() is being called on the right thread 1.112 + // (ParentThread if |mTarget| is WorkerThread, or WorkerThread otherwise). 1.113 + // Also reports any Dispatch() failures as an exception on |aCx|, and 1.114 + // busy count if targeting the WorkerThread and Dispatch() failed. 1.115 + virtual void 1.116 + PostDispatch(JSContext* aCx, WorkerPrivate* aWorkerPrivate, 1.117 + bool aDispatchResult); 1.118 + 1.119 + // Must be implemented by subclasses. Called on the target thread. 1.120 + virtual bool 1.121 + WorkerRun(JSContext* aCx, WorkerPrivate* aWorkerPrivate) = 0; 1.122 + 1.123 + // By default asserts that Run() (and WorkerRun()) were called on the correct 1.124 + // thread. Any failures (false return from WorkerRun) are reported on |aCx|. 1.125 + // Also sends an asynchronous message to the ParentThread if the busy 1.126 + // count was previously modified in PreDispatch(). 1.127 + virtual void 1.128 + PostRun(JSContext* aCx, WorkerPrivate* aWorkerPrivate, bool aRunResult); 1.129 + 1.130 + virtual bool 1.131 + DispatchInternal(); 1.132 + 1.133 + // Calling Run() directly is not supported. Just call Dispatch() and 1.134 + // WorkerRun() will be called on the correct thread automatically. 1.135 + NS_DECL_NSIRUNNABLE 1.136 +}; 1.137 + 1.138 +// This runnable is used to send a message directly to a worker's sync loop. 1.139 +class WorkerSyncRunnable : public WorkerRunnable 1.140 +{ 1.141 +protected: 1.142 + nsCOMPtr<nsIEventTarget> mSyncLoopTarget; 1.143 + 1.144 + // Passing null for aSyncLoopTarget is allowed and will result in the behavior 1.145 + // of a normal WorkerRunnable. 1.146 + WorkerSyncRunnable(WorkerPrivate* aWorkerPrivate, 1.147 + nsIEventTarget* aSyncLoopTarget); 1.148 + 1.149 + WorkerSyncRunnable(WorkerPrivate* aWorkerPrivate, 1.150 + already_AddRefed<nsIEventTarget>&& aSyncLoopTarget); 1.151 + 1.152 + virtual ~WorkerSyncRunnable(); 1.153 + 1.154 +private: 1.155 + virtual bool 1.156 + DispatchInternal() MOZ_OVERRIDE; 1.157 +}; 1.158 + 1.159 +// This runnable is identical to WorkerSyncRunnable except it is meant to be 1.160 +// used on the main thread only. 1.161 +class MainThreadWorkerSyncRunnable : public WorkerSyncRunnable 1.162 +{ 1.163 +protected: 1.164 + // Passing null for aSyncLoopTarget is allowed and will result in the behavior 1.165 + // of a normal WorkerRunnable. 1.166 + MainThreadWorkerSyncRunnable(WorkerPrivate* aWorkerPrivate, 1.167 + nsIEventTarget* aSyncLoopTarget) 1.168 + : WorkerSyncRunnable(aWorkerPrivate, aSyncLoopTarget) 1.169 + { 1.170 + AssertIsOnMainThread(); 1.171 + } 1.172 + 1.173 + MainThreadWorkerSyncRunnable(WorkerPrivate* aWorkerPrivate, 1.174 + already_AddRefed<nsIEventTarget>&& aSyncLoopTarget) 1.175 + : WorkerSyncRunnable(aWorkerPrivate, Move(aSyncLoopTarget)) 1.176 + { 1.177 + AssertIsOnMainThread(); 1.178 + } 1.179 + 1.180 + virtual ~MainThreadWorkerSyncRunnable() 1.181 + { } 1.182 + 1.183 +private: 1.184 + virtual bool 1.185 + PreDispatch(JSContext* aCx, WorkerPrivate* aWorkerPrivate) MOZ_OVERRIDE 1.186 + { 1.187 + AssertIsOnMainThread(); 1.188 + return true; 1.189 + } 1.190 + 1.191 + virtual void 1.192 + PostDispatch(JSContext* aCx, WorkerPrivate* aWorkerPrivate, 1.193 + bool aDispatchResult) MOZ_OVERRIDE; 1.194 +}; 1.195 + 1.196 +// This runnable is used to stop a sync loop . As sync loops keep the busy count 1.197 +// incremented as long as they run this runnable does not modify the busy count 1.198 +// in any way. 1.199 +class StopSyncLoopRunnable : public WorkerSyncRunnable 1.200 +{ 1.201 + bool mResult; 1.202 + 1.203 +public: 1.204 + // Passing null for aSyncLoopTarget is not allowed. 1.205 + StopSyncLoopRunnable(WorkerPrivate* aWorkerPrivate, 1.206 + already_AddRefed<nsIEventTarget>&& aSyncLoopTarget, 1.207 + bool aResult); 1.208 + 1.209 + // By default StopSyncLoopRunnables cannot be canceled since they could leave 1.210 + // a sync loop spinning forever. 1.211 + NS_DECL_NSICANCELABLERUNNABLE 1.212 + 1.213 +protected: 1.214 + virtual ~StopSyncLoopRunnable() 1.215 + { } 1.216 + 1.217 + // Called on the worker thread to set an exception on the context if mResult 1.218 + // is false. Override if you need an exception. 1.219 + virtual void 1.220 + MaybeSetException(JSContext* aCx) 1.221 + { } 1.222 + 1.223 +private: 1.224 + virtual bool 1.225 + WorkerRun(JSContext* aCx, WorkerPrivate* aWorkerPrivate) MOZ_OVERRIDE; 1.226 + 1.227 + virtual bool 1.228 + DispatchInternal() MOZ_OVERRIDE; 1.229 +}; 1.230 + 1.231 +// This runnable is identical to StopSyncLoopRunnable except it is meant to be 1.232 +// used on the main thread only. 1.233 +class MainThreadStopSyncLoopRunnable : public StopSyncLoopRunnable 1.234 +{ 1.235 +public: 1.236 + // Passing null for aSyncLoopTarget is not allowed. 1.237 + MainThreadStopSyncLoopRunnable( 1.238 + WorkerPrivate* aWorkerPrivate, 1.239 + already_AddRefed<nsIEventTarget>&& aSyncLoopTarget, 1.240 + bool aResult) 1.241 + : StopSyncLoopRunnable(aWorkerPrivate, Move(aSyncLoopTarget), aResult) 1.242 + { 1.243 + AssertIsOnMainThread(); 1.244 + } 1.245 + 1.246 +protected: 1.247 + virtual ~MainThreadStopSyncLoopRunnable() 1.248 + { } 1.249 + 1.250 +private: 1.251 + virtual bool 1.252 + PreDispatch(JSContext* aCx, WorkerPrivate* aWorkerPrivate) MOZ_OVERRIDE 1.253 + { 1.254 + AssertIsOnMainThread(); 1.255 + return true; 1.256 + } 1.257 + 1.258 + virtual void 1.259 + PostDispatch(JSContext* aCx, WorkerPrivate* aWorkerPrivate, 1.260 + bool aDispatchResult) MOZ_OVERRIDE; 1.261 +}; 1.262 + 1.263 +// This runnable is processed as soon as it is received by the worker, 1.264 +// potentially running before previously queued runnables and perhaps even with 1.265 +// other JS code executing on the stack. These runnables must not alter the 1.266 +// state of the JS runtime and should only twiddle state values. The busy count 1.267 +// is never modified. 1.268 +class WorkerControlRunnable : public WorkerRunnable 1.269 +{ 1.270 + friend class WorkerPrivate; 1.271 + 1.272 +protected: 1.273 + WorkerControlRunnable(WorkerPrivate* aWorkerPrivate, 1.274 + TargetAndBusyBehavior aBehavior) 1.275 +#ifdef DEBUG 1.276 + ; 1.277 +#else 1.278 + : WorkerRunnable(aWorkerPrivate, aBehavior) 1.279 + { } 1.280 +#endif 1.281 + 1.282 + virtual ~WorkerControlRunnable() 1.283 + { } 1.284 + 1.285 +public: 1.286 + NS_DECL_ISUPPORTS_INHERITED 1.287 + 1.288 +private: 1.289 + virtual bool 1.290 + DispatchInternal() MOZ_OVERRIDE; 1.291 + 1.292 + // Should only be called by WorkerPrivate::DoRunLoop. 1.293 + using WorkerRunnable::Cancel; 1.294 +}; 1.295 + 1.296 +// A convenience class for WorkerControlRunnables that originate on the main 1.297 +// thread. 1.298 +class MainThreadWorkerControlRunnable : public WorkerControlRunnable 1.299 +{ 1.300 +protected: 1.301 + MainThreadWorkerControlRunnable(WorkerPrivate* aWorkerPrivate) 1.302 + : WorkerControlRunnable(aWorkerPrivate, WorkerThreadUnchangedBusyCount) 1.303 + { } 1.304 + 1.305 + virtual ~MainThreadWorkerControlRunnable() 1.306 + { } 1.307 + 1.308 + virtual bool 1.309 + PreDispatch(JSContext* aCx, WorkerPrivate* aWorkerPrivate) MOZ_OVERRIDE 1.310 + { 1.311 + AssertIsOnMainThread(); 1.312 + return true; 1.313 + } 1.314 + 1.315 + virtual void 1.316 + PostDispatch(JSContext* aCx, WorkerPrivate* aWorkerPrivate, 1.317 + bool aDispatchResult) MOZ_OVERRIDE; 1.318 +}; 1.319 + 1.320 +// A WorkerRunnable that should be dispatched from the worker to itself for 1.321 +// async tasks. This will increment the busy count PostDispatch() (only if 1.322 +// dispatch was successful) and decrement it in PostRun(). 1.323 +// 1.324 +// Async tasks will almost always want to use this since 1.325 +// a WorkerSameThreadRunnable keeps the Worker from being GCed. 1.326 +class WorkerSameThreadRunnable : public WorkerRunnable 1.327 +{ 1.328 +protected: 1.329 + WorkerSameThreadRunnable(WorkerPrivate* aWorkerPrivate) 1.330 + : WorkerRunnable(aWorkerPrivate, WorkerThreadModifyBusyCount) 1.331 + { } 1.332 + 1.333 + virtual ~WorkerSameThreadRunnable() 1.334 + { } 1.335 + 1.336 + virtual bool 1.337 + PreDispatch(JSContext* aCx, WorkerPrivate* aWorkerPrivate) MOZ_OVERRIDE; 1.338 + 1.339 + virtual void 1.340 + PostDispatch(JSContext* aCx, WorkerPrivate* aWorkerPrivate, 1.341 + bool aDispatchResult) MOZ_OVERRIDE; 1.342 + 1.343 + virtual void 1.344 + PostRun(JSContext* aCx, WorkerPrivate* aWorkerPrivate, 1.345 + bool aRunResult) MOZ_OVERRIDE; 1.346 +}; 1.347 + 1.348 +END_WORKERS_NAMESPACE 1.349 + 1.350 +#endif // mozilla_dom_workers_workerrunnable_h__