dom/workers/WorkerRunnable.h

Fri, 16 Jan 2015 18:13:44 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Fri, 16 Jan 2015 18:13:44 +0100
branch
TOR_BUG_9701
changeset 14
925c144e1f1f
permissions
-rw-r--r--

Integrate suggestion from review to improve consistency with existing code.

michael@0 1 /* -*- Mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 40 -*- */
michael@0 2 /* This Source Code Form is subject to the terms of the Mozilla Public
michael@0 3 * License, v. 2.0. If a copy of the MPL was not distributed with this
michael@0 4 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
michael@0 5
michael@0 6 #ifndef mozilla_dom_workers_workerrunnable_h__
michael@0 7 #define mozilla_dom_workers_workerrunnable_h__
michael@0 8
michael@0 9 #include "Workers.h"
michael@0 10
michael@0 11 #include "nsICancelableRunnable.h"
michael@0 12
michael@0 13 #include "mozilla/Atomics.h"
michael@0 14 #include "nsISupportsImpl.h"
michael@0 15
michael@0 16 class JSContext;
michael@0 17 class nsIEventTarget;
michael@0 18
michael@0 19 BEGIN_WORKERS_NAMESPACE
michael@0 20
michael@0 21 class WorkerPrivate;
michael@0 22
michael@0 23 // Use this runnable to communicate from the worker to its parent or vice-versa.
michael@0 24 // The busy count must be taken into consideration and declared at construction
michael@0 25 // time.
michael@0 26 class WorkerRunnable : public nsICancelableRunnable
michael@0 27 {
michael@0 28 public:
michael@0 29 enum TargetAndBusyBehavior {
michael@0 30 // Target the main thread for top-level workers, otherwise target the
michael@0 31 // WorkerThread of the worker's parent. No change to the busy count.
michael@0 32 ParentThreadUnchangedBusyCount,
michael@0 33
michael@0 34 // Target the thread where the worker event loop runs. The busy count will
michael@0 35 // be incremented before dispatching and decremented (asynchronously) after
michael@0 36 // running.
michael@0 37 WorkerThreadModifyBusyCount,
michael@0 38
michael@0 39 // Target the thread where the worker event loop runs. The busy count will
michael@0 40 // not be modified in any way. Besides worker-internal runnables this is
michael@0 41 // almost always the wrong choice.
michael@0 42 WorkerThreadUnchangedBusyCount
michael@0 43 };
michael@0 44
michael@0 45 protected:
michael@0 46 // The WorkerPrivate that this runnable is associated with.
michael@0 47 WorkerPrivate* mWorkerPrivate;
michael@0 48
michael@0 49 // See above.
michael@0 50 TargetAndBusyBehavior mBehavior;
michael@0 51
michael@0 52 // It's unclear whether or not Cancel() is supposed to work when called on any
michael@0 53 // thread. To be safe we're using an atomic but it's likely overkill.
michael@0 54 Atomic<uint32_t> mCanceled;
michael@0 55
michael@0 56 private:
michael@0 57 // Whether or not Cancel() is currently being called from inside the Run()
michael@0 58 // method. Avoids infinite recursion when a subclass calls Run() from inside
michael@0 59 // Cancel(). Only checked and modified on the target thread.
michael@0 60 bool mCallingCancelWithinRun;
michael@0 61
michael@0 62 public:
michael@0 63 NS_DECL_THREADSAFE_ISUPPORTS
michael@0 64
michael@0 65 // If you override Cancel() then you'll need to either call the base class
michael@0 66 // Cancel() method or override IsCanceled() so that the Run() method bails out
michael@0 67 // appropriately.
michael@0 68 NS_DECL_NSICANCELABLERUNNABLE
michael@0 69
michael@0 70 // Passing a JSContext here is required for the WorkerThreadModifyBusyCount
michael@0 71 // behavior. It also guarantees that any failure (false return) will throw an
michael@0 72 // exception on the given context. If a context is not passed then failures
michael@0 73 // must be dealt with by the caller.
michael@0 74 bool
michael@0 75 Dispatch(JSContext* aCx);
michael@0 76
michael@0 77 // See above note about Cancel().
michael@0 78 virtual bool
michael@0 79 IsCanceled() const
michael@0 80 {
michael@0 81 return mCanceled != 0;
michael@0 82 }
michael@0 83
michael@0 84 static WorkerRunnable*
michael@0 85 FromRunnable(nsIRunnable* aRunnable);
michael@0 86
michael@0 87 protected:
michael@0 88 WorkerRunnable(WorkerPrivate* aWorkerPrivate, TargetAndBusyBehavior aBehavior)
michael@0 89 #ifdef DEBUG
michael@0 90 ;
michael@0 91 #else
michael@0 92 : mWorkerPrivate(aWorkerPrivate), mBehavior(aBehavior), mCanceled(0),
michael@0 93 mCallingCancelWithinRun(false)
michael@0 94 { }
michael@0 95 #endif
michael@0 96
michael@0 97 // This class is reference counted.
michael@0 98 virtual ~WorkerRunnable()
michael@0 99 { }
michael@0 100
michael@0 101 // By default asserts that Dispatch() is being called on the right thread
michael@0 102 // (ParentThread if |mTarget| is WorkerThread, or WorkerThread otherwise).
michael@0 103 // Also increments the busy count of |mWorkerPrivate| if targeting the
michael@0 104 // WorkerThread.
michael@0 105 virtual bool
michael@0 106 PreDispatch(JSContext* aCx, WorkerPrivate* aWorkerPrivate);
michael@0 107
michael@0 108 // By default asserts that Dispatch() is being called on the right thread
michael@0 109 // (ParentThread if |mTarget| is WorkerThread, or WorkerThread otherwise).
michael@0 110 // Also reports any Dispatch() failures as an exception on |aCx|, and
michael@0 111 // busy count if targeting the WorkerThread and Dispatch() failed.
michael@0 112 virtual void
michael@0 113 PostDispatch(JSContext* aCx, WorkerPrivate* aWorkerPrivate,
michael@0 114 bool aDispatchResult);
michael@0 115
michael@0 116 // Must be implemented by subclasses. Called on the target thread.
michael@0 117 virtual bool
michael@0 118 WorkerRun(JSContext* aCx, WorkerPrivate* aWorkerPrivate) = 0;
michael@0 119
michael@0 120 // By default asserts that Run() (and WorkerRun()) were called on the correct
michael@0 121 // thread. Any failures (false return from WorkerRun) are reported on |aCx|.
michael@0 122 // Also sends an asynchronous message to the ParentThread if the busy
michael@0 123 // count was previously modified in PreDispatch().
michael@0 124 virtual void
michael@0 125 PostRun(JSContext* aCx, WorkerPrivate* aWorkerPrivate, bool aRunResult);
michael@0 126
michael@0 127 virtual bool
michael@0 128 DispatchInternal();
michael@0 129
michael@0 130 // Calling Run() directly is not supported. Just call Dispatch() and
michael@0 131 // WorkerRun() will be called on the correct thread automatically.
michael@0 132 NS_DECL_NSIRUNNABLE
michael@0 133 };
michael@0 134
michael@0 135 // This runnable is used to send a message directly to a worker's sync loop.
michael@0 136 class WorkerSyncRunnable : public WorkerRunnable
michael@0 137 {
michael@0 138 protected:
michael@0 139 nsCOMPtr<nsIEventTarget> mSyncLoopTarget;
michael@0 140
michael@0 141 // Passing null for aSyncLoopTarget is allowed and will result in the behavior
michael@0 142 // of a normal WorkerRunnable.
michael@0 143 WorkerSyncRunnable(WorkerPrivate* aWorkerPrivate,
michael@0 144 nsIEventTarget* aSyncLoopTarget);
michael@0 145
michael@0 146 WorkerSyncRunnable(WorkerPrivate* aWorkerPrivate,
michael@0 147 already_AddRefed<nsIEventTarget>&& aSyncLoopTarget);
michael@0 148
michael@0 149 virtual ~WorkerSyncRunnable();
michael@0 150
michael@0 151 private:
michael@0 152 virtual bool
michael@0 153 DispatchInternal() MOZ_OVERRIDE;
michael@0 154 };
michael@0 155
michael@0 156 // This runnable is identical to WorkerSyncRunnable except it is meant to be
michael@0 157 // used on the main thread only.
michael@0 158 class MainThreadWorkerSyncRunnable : public WorkerSyncRunnable
michael@0 159 {
michael@0 160 protected:
michael@0 161 // Passing null for aSyncLoopTarget is allowed and will result in the behavior
michael@0 162 // of a normal WorkerRunnable.
michael@0 163 MainThreadWorkerSyncRunnable(WorkerPrivate* aWorkerPrivate,
michael@0 164 nsIEventTarget* aSyncLoopTarget)
michael@0 165 : WorkerSyncRunnable(aWorkerPrivate, aSyncLoopTarget)
michael@0 166 {
michael@0 167 AssertIsOnMainThread();
michael@0 168 }
michael@0 169
michael@0 170 MainThreadWorkerSyncRunnable(WorkerPrivate* aWorkerPrivate,
michael@0 171 already_AddRefed<nsIEventTarget>&& aSyncLoopTarget)
michael@0 172 : WorkerSyncRunnable(aWorkerPrivate, Move(aSyncLoopTarget))
michael@0 173 {
michael@0 174 AssertIsOnMainThread();
michael@0 175 }
michael@0 176
michael@0 177 virtual ~MainThreadWorkerSyncRunnable()
michael@0 178 { }
michael@0 179
michael@0 180 private:
michael@0 181 virtual bool
michael@0 182 PreDispatch(JSContext* aCx, WorkerPrivate* aWorkerPrivate) MOZ_OVERRIDE
michael@0 183 {
michael@0 184 AssertIsOnMainThread();
michael@0 185 return true;
michael@0 186 }
michael@0 187
michael@0 188 virtual void
michael@0 189 PostDispatch(JSContext* aCx, WorkerPrivate* aWorkerPrivate,
michael@0 190 bool aDispatchResult) MOZ_OVERRIDE;
michael@0 191 };
michael@0 192
michael@0 193 // This runnable is used to stop a sync loop . As sync loops keep the busy count
michael@0 194 // incremented as long as they run this runnable does not modify the busy count
michael@0 195 // in any way.
michael@0 196 class StopSyncLoopRunnable : public WorkerSyncRunnable
michael@0 197 {
michael@0 198 bool mResult;
michael@0 199
michael@0 200 public:
michael@0 201 // Passing null for aSyncLoopTarget is not allowed.
michael@0 202 StopSyncLoopRunnable(WorkerPrivate* aWorkerPrivate,
michael@0 203 already_AddRefed<nsIEventTarget>&& aSyncLoopTarget,
michael@0 204 bool aResult);
michael@0 205
michael@0 206 // By default StopSyncLoopRunnables cannot be canceled since they could leave
michael@0 207 // a sync loop spinning forever.
michael@0 208 NS_DECL_NSICANCELABLERUNNABLE
michael@0 209
michael@0 210 protected:
michael@0 211 virtual ~StopSyncLoopRunnable()
michael@0 212 { }
michael@0 213
michael@0 214 // Called on the worker thread to set an exception on the context if mResult
michael@0 215 // is false. Override if you need an exception.
michael@0 216 virtual void
michael@0 217 MaybeSetException(JSContext* aCx)
michael@0 218 { }
michael@0 219
michael@0 220 private:
michael@0 221 virtual bool
michael@0 222 WorkerRun(JSContext* aCx, WorkerPrivate* aWorkerPrivate) MOZ_OVERRIDE;
michael@0 223
michael@0 224 virtual bool
michael@0 225 DispatchInternal() MOZ_OVERRIDE;
michael@0 226 };
michael@0 227
michael@0 228 // This runnable is identical to StopSyncLoopRunnable except it is meant to be
michael@0 229 // used on the main thread only.
michael@0 230 class MainThreadStopSyncLoopRunnable : public StopSyncLoopRunnable
michael@0 231 {
michael@0 232 public:
michael@0 233 // Passing null for aSyncLoopTarget is not allowed.
michael@0 234 MainThreadStopSyncLoopRunnable(
michael@0 235 WorkerPrivate* aWorkerPrivate,
michael@0 236 already_AddRefed<nsIEventTarget>&& aSyncLoopTarget,
michael@0 237 bool aResult)
michael@0 238 : StopSyncLoopRunnable(aWorkerPrivate, Move(aSyncLoopTarget), aResult)
michael@0 239 {
michael@0 240 AssertIsOnMainThread();
michael@0 241 }
michael@0 242
michael@0 243 protected:
michael@0 244 virtual ~MainThreadStopSyncLoopRunnable()
michael@0 245 { }
michael@0 246
michael@0 247 private:
michael@0 248 virtual bool
michael@0 249 PreDispatch(JSContext* aCx, WorkerPrivate* aWorkerPrivate) MOZ_OVERRIDE
michael@0 250 {
michael@0 251 AssertIsOnMainThread();
michael@0 252 return true;
michael@0 253 }
michael@0 254
michael@0 255 virtual void
michael@0 256 PostDispatch(JSContext* aCx, WorkerPrivate* aWorkerPrivate,
michael@0 257 bool aDispatchResult) MOZ_OVERRIDE;
michael@0 258 };
michael@0 259
michael@0 260 // This runnable is processed as soon as it is received by the worker,
michael@0 261 // potentially running before previously queued runnables and perhaps even with
michael@0 262 // other JS code executing on the stack. These runnables must not alter the
michael@0 263 // state of the JS runtime and should only twiddle state values. The busy count
michael@0 264 // is never modified.
michael@0 265 class WorkerControlRunnable : public WorkerRunnable
michael@0 266 {
michael@0 267 friend class WorkerPrivate;
michael@0 268
michael@0 269 protected:
michael@0 270 WorkerControlRunnable(WorkerPrivate* aWorkerPrivate,
michael@0 271 TargetAndBusyBehavior aBehavior)
michael@0 272 #ifdef DEBUG
michael@0 273 ;
michael@0 274 #else
michael@0 275 : WorkerRunnable(aWorkerPrivate, aBehavior)
michael@0 276 { }
michael@0 277 #endif
michael@0 278
michael@0 279 virtual ~WorkerControlRunnable()
michael@0 280 { }
michael@0 281
michael@0 282 public:
michael@0 283 NS_DECL_ISUPPORTS_INHERITED
michael@0 284
michael@0 285 private:
michael@0 286 virtual bool
michael@0 287 DispatchInternal() MOZ_OVERRIDE;
michael@0 288
michael@0 289 // Should only be called by WorkerPrivate::DoRunLoop.
michael@0 290 using WorkerRunnable::Cancel;
michael@0 291 };
michael@0 292
michael@0 293 // A convenience class for WorkerControlRunnables that originate on the main
michael@0 294 // thread.
michael@0 295 class MainThreadWorkerControlRunnable : public WorkerControlRunnable
michael@0 296 {
michael@0 297 protected:
michael@0 298 MainThreadWorkerControlRunnable(WorkerPrivate* aWorkerPrivate)
michael@0 299 : WorkerControlRunnable(aWorkerPrivate, WorkerThreadUnchangedBusyCount)
michael@0 300 { }
michael@0 301
michael@0 302 virtual ~MainThreadWorkerControlRunnable()
michael@0 303 { }
michael@0 304
michael@0 305 virtual bool
michael@0 306 PreDispatch(JSContext* aCx, WorkerPrivate* aWorkerPrivate) MOZ_OVERRIDE
michael@0 307 {
michael@0 308 AssertIsOnMainThread();
michael@0 309 return true;
michael@0 310 }
michael@0 311
michael@0 312 virtual void
michael@0 313 PostDispatch(JSContext* aCx, WorkerPrivate* aWorkerPrivate,
michael@0 314 bool aDispatchResult) MOZ_OVERRIDE;
michael@0 315 };
michael@0 316
michael@0 317 // A WorkerRunnable that should be dispatched from the worker to itself for
michael@0 318 // async tasks. This will increment the busy count PostDispatch() (only if
michael@0 319 // dispatch was successful) and decrement it in PostRun().
michael@0 320 //
michael@0 321 // Async tasks will almost always want to use this since
michael@0 322 // a WorkerSameThreadRunnable keeps the Worker from being GCed.
michael@0 323 class WorkerSameThreadRunnable : public WorkerRunnable
michael@0 324 {
michael@0 325 protected:
michael@0 326 WorkerSameThreadRunnable(WorkerPrivate* aWorkerPrivate)
michael@0 327 : WorkerRunnable(aWorkerPrivate, WorkerThreadModifyBusyCount)
michael@0 328 { }
michael@0 329
michael@0 330 virtual ~WorkerSameThreadRunnable()
michael@0 331 { }
michael@0 332
michael@0 333 virtual bool
michael@0 334 PreDispatch(JSContext* aCx, WorkerPrivate* aWorkerPrivate) MOZ_OVERRIDE;
michael@0 335
michael@0 336 virtual void
michael@0 337 PostDispatch(JSContext* aCx, WorkerPrivate* aWorkerPrivate,
michael@0 338 bool aDispatchResult) MOZ_OVERRIDE;
michael@0 339
michael@0 340 virtual void
michael@0 341 PostRun(JSContext* aCx, WorkerPrivate* aWorkerPrivate,
michael@0 342 bool aRunResult) MOZ_OVERRIDE;
michael@0 343 };
michael@0 344
michael@0 345 END_WORKERS_NAMESPACE
michael@0 346
michael@0 347 #endif // mozilla_dom_workers_workerrunnable_h__

mercurial