Bug 1550519 - Show a translucent parent highlight when a subgrid is highlighted....
[gecko.git] / dom / promise / PromiseWorkerProxy.h
bloba4b20ca39ad0c370819acdaad16be7c7d9be985a
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/. */
7 #ifndef mozilla_dom_PromiseWorkerProxy_h
8 #define mozilla_dom_PromiseWorkerProxy_h
10 // Required for Promise::PromiseTaskSync.
11 #include "mozilla/dom/Promise.h"
12 #include "mozilla/dom/PromiseNativeHandler.h"
13 #include "mozilla/dom/StructuredCloneHolder.h"
14 #include "mozilla/dom/WorkerRunnable.h"
15 #include "nsProxyRelease.h"
17 namespace mozilla {
18 namespace dom {
20 class Promise;
21 class ThreadSafeWorkerRef;
22 class WorkerPrivate;
24 // A proxy to (eventually) mirror a resolved/rejected Promise's result from the
25 // main thread to a Promise on the worker thread.
27 // How to use:
29 // 1. Create a Promise on the worker thread and return it to the content
30 // script:
32 // RefPtr<Promise> promise =
33 // Promise::Create(workerPrivate->GlobalScope(), aRv);
34 // if (aRv.Failed()) {
35 // return nullptr;
36 // }
38 // 2. Create a PromiseWorkerProxy wrapping the Promise. If this fails, the
39 // worker is shutting down and you should fail the original call. This is
40 // only likely to happen in (Gecko-specific) worker onclose handlers.
42 // RefPtr<PromiseWorkerProxy> proxy =
43 // PromiseWorkerProxy::Create(workerPrivate, promise);
44 // if (!proxy) {
45 // // You may also reject the Promise with an AbortError or similar.
46 // return nullptr;
47 // }
49 // 3. Dispatch a runnable to the main thread, with a reference to the proxy to
50 // perform the main thread operation. PromiseWorkerProxy is thread-safe
51 // refcounted.
53 // 4. Return the worker thread promise to the JS caller:
55 // return promise.forget();
57 // 5. In your main thread runnable Run(), obtain a Promise on
58 // the main thread and call its AppendNativeHandler(PromiseNativeHandler*)
59 // to bind the PromiseWorkerProxy created at #2.
61 // 4. Then the Promise results returned by ResolvedCallback/RejectedCallback
62 // will be dispatched as a WorkerRunnable to the worker thread to
63 // resolve/reject the Promise created at #1.
65 // PromiseWorkerProxy can also be used in situations where there is no main
66 // thread Promise, or where special handling is required on the worker thread
67 // for promise resolution. Create a PromiseWorkerProxy as in steps 1 to 3
68 // above. When the main thread is ready to resolve the worker thread promise:
70 // 1. Acquire the mutex before attempting to access the worker private.
72 // AssertIsOnMainThread();
73 // MutexAutoLock lock(proxy->Lock());
74 // if (proxy->CleanedUp()) {
75 // // Worker has already shut down, can't access worker private.
76 // return;
77 // }
79 // 2. Dispatch a runnable to the worker. Use GetWorkerPrivate() to acquire the
80 // worker.
82 // RefPtr<FinishTaskWorkerRunnable> runnable =
83 // new FinishTaskWorkerRunnable(proxy->GetWorkerPrivate(), proxy,
84 // result);
85 // if (!r->Dispatch()) {
86 // // Worker is alive but not Running any more, so the Promise can't
87 // // be resolved, give up. The proxy will get Release()d at some
88 // // point.
90 // // Usually do nothing, but you may want to log the fact.
91 // }
93 // 3. In the WorkerRunnable's WorkerRun() use WorkerPromise() to access the
94 // Promise and resolve/reject it. Then call CleanUp().
96 // bool
97 // WorkerRun(JSContext* aCx, WorkerPrivate* aWorkerPrivate) override
98 // {
99 // aWorkerPrivate->AssertIsOnWorkerThread();
100 // RefPtr<Promise> promise = mProxy->WorkerPromise();
101 // promise->MaybeResolve(mResult);
102 // mProxy->CleanUp();
103 // }
105 // Note: If a PromiseWorkerProxy is not cleaned up by a WorkerRunnable - this
106 // can happen if the main thread Promise is never fulfilled - it will
107 // stay alive till the worker reaches a Canceling state, even if all external
108 // references to it are dropped.
110 class PromiseWorkerProxy : public PromiseNativeHandler,
111 public StructuredCloneHolderBase {
112 friend class PromiseWorkerProxyRunnable;
114 NS_DECL_THREADSAFE_ISUPPORTS
116 public:
117 typedef JSObject* (*ReadCallbackOp)(JSContext* aCx,
118 JSStructuredCloneReader* aReader,
119 const PromiseWorkerProxy* aProxy,
120 uint32_t aTag, uint32_t aData);
121 typedef bool (*WriteCallbackOp)(JSContext* aCx,
122 JSStructuredCloneWriter* aWorker,
123 PromiseWorkerProxy* aProxy,
124 JS::HandleObject aObj);
126 struct PromiseWorkerProxyStructuredCloneCallbacks {
127 ReadCallbackOp Read;
128 WriteCallbackOp Write;
131 static already_AddRefed<PromiseWorkerProxy> Create(
132 WorkerPrivate* aWorkerPrivate, Promise* aWorkerPromise,
133 const PromiseWorkerProxyStructuredCloneCallbacks* aCallbacks = nullptr);
135 // Main thread callers must hold Lock() and check CleanUp() before calling
136 // this. Worker thread callers, this will assert that the proxy has not been
137 // cleaned up.
138 WorkerPrivate* GetWorkerPrivate() const;
140 // This should only be used within WorkerRunnable::WorkerRun() running on the
141 // worker thread! Do not call this after calling CleanUp().
142 Promise* WorkerPromise() const;
144 // Worker thread only. Calling this invalidates several assumptions, so be
145 // sure this is the last thing you do.
146 // 1. WorkerPrivate() will no longer return a valid worker.
147 // 2. WorkerPromise() will crash!
148 void CleanUp();
150 Mutex& Lock() { return mCleanUpLock; }
152 bool CleanedUp() const {
153 mCleanUpLock.AssertCurrentThreadOwns();
154 return mCleanedUp;
157 // StructuredCloneHolderBase
159 JSObject* CustomReadHandler(JSContext* aCx, JSStructuredCloneReader* aReader,
160 uint32_t aTag, uint32_t aIndex) override;
162 bool CustomWriteHandler(JSContext* aCx, JSStructuredCloneWriter* aWriter,
163 JS::Handle<JSObject*> aObj) override;
165 protected:
166 virtual void ResolvedCallback(JSContext* aCx,
167 JS::Handle<JS::Value> aValue) override;
169 virtual void RejectedCallback(JSContext* aCx,
170 JS::Handle<JS::Value> aValue) override;
172 private:
173 explicit PromiseWorkerProxy(
174 Promise* aWorkerPromise,
175 const PromiseWorkerProxyStructuredCloneCallbacks* aCallbacks = nullptr);
177 virtual ~PromiseWorkerProxy();
179 // If not called from Create(), be sure to hold Lock().
180 void CleanProperties();
182 // Function pointer for calling Promise::{ResolveInternal,RejectInternal}.
183 typedef void (Promise::*RunCallbackFunc)(JSContext*, JS::Handle<JS::Value>);
185 void RunCallback(JSContext* aCx, JS::Handle<JS::Value> aValue,
186 RunCallbackFunc aFunc);
188 // Any thread with appropriate checks.
189 RefPtr<ThreadSafeWorkerRef> mWorkerRef;
191 // Worker thread only.
192 RefPtr<Promise> mWorkerPromise;
194 // Modified on the worker thread.
195 // It is ok to *read* this without a lock on the worker.
196 // Main thread must always acquire a lock.
197 bool mCleanedUp; // To specify if the cleanUp() has been done.
199 const PromiseWorkerProxyStructuredCloneCallbacks* mCallbacks;
201 // Ensure the worker and the main thread won't race to access |mCleanedUp|.
202 Mutex mCleanUpLock;
204 } // namespace dom
205 } // namespace mozilla
207 #endif // mozilla_dom_PromiseWorkerProxy_h