LCOV - code coverage report
Current view: top level - dom/promise - PromiseWorkerProxy.h (source / functions) Hit Total Coverage
Test: output.info Lines: 0 5 0.0 %
Date: 2017-07-14 16:53:18 Functions: 0 2 0.0 %
Legend: Lines: hit not hit

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

Generated by: LCOV version 1.13