LCOV - code coverage report
Current view: top level - xpcom/threads - SyncRunnable.h (source / functions) Hit Total Coverage
Test: output.info Lines: 31 33 93.9 %
Date: 2017-07-14 16:53:18 Functions: 7 7 100.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_SyncRunnable_h
       8             : #define mozilla_SyncRunnable_h
       9             : 
      10             : #include "nsThreadUtils.h"
      11             : #include "mozilla/AbstractThread.h"
      12             : #include "mozilla/Monitor.h"
      13             : #include "mozilla/Move.h"
      14             : 
      15             : namespace mozilla {
      16             : 
      17             : /**
      18             :  * This class will wrap a nsIRunnable and dispatch it to the main thread
      19             :  * synchronously. This is different from nsIEventTarget.DISPATCH_SYNC:
      20             :  * this class does not spin the event loop waiting for the event to be
      21             :  * dispatched. This means that you don't risk reentrance from pending
      22             :  * messages, but you must be sure that the target thread does not ever block
      23             :  * on this thread, or else you will deadlock.
      24             :  *
      25             :  * Typical usage:
      26             :  * RefPtr<SyncRunnable> sr = new SyncRunnable(new myrunnable...());
      27             :  * sr->DispatchToThread(t);
      28             :  *
      29             :  * We also provide a convenience wrapper:
      30             :  * SyncRunnable::DispatchToThread(new myrunnable...());
      31             :  *
      32             :  */
      33           6 : class SyncRunnable : public Runnable
      34             : {
      35             : public:
      36           1 :   explicit SyncRunnable(nsIRunnable* aRunnable)
      37           1 :     : Runnable("SyncRunnable")
      38             :     , mRunnable(aRunnable)
      39             :     , mMonitor("SyncRunnable")
      40           1 :     , mDone(false)
      41             :   {
      42           1 :   }
      43             : 
      44           1 :   explicit SyncRunnable(already_AddRefed<nsIRunnable> aRunnable)
      45           1 :     : Runnable("SyncRunnable")
      46           1 :     , mRunnable(Move(aRunnable))
      47             :     , mMonitor("SyncRunnable")
      48           2 :     , mDone(false)
      49             :   {
      50           1 :   }
      51             : 
      52           1 :   void DispatchToThread(nsIEventTarget* aThread, bool aForceDispatch = false)
      53             :   {
      54             :     nsresult rv;
      55             :     bool on;
      56             : 
      57           1 :     if (!aForceDispatch) {
      58           1 :       rv = aThread->IsOnCurrentThread(&on);
      59           1 :       MOZ_ASSERT(NS_SUCCEEDED(rv));
      60           1 :       if (NS_SUCCEEDED(rv) && on) {
      61           0 :         mRunnable->Run();
      62           0 :         return;
      63             :       }
      64             :     }
      65             : 
      66           1 :     rv = aThread->Dispatch(this, NS_DISPATCH_NORMAL);
      67           1 :     if (NS_SUCCEEDED(rv)) {
      68           2 :       mozilla::MonitorAutoLock lock(mMonitor);
      69           3 :       while (!mDone) {
      70           1 :         lock.Wait();
      71             :       }
      72             :     }
      73             :   }
      74             : 
      75             :   void DispatchToThread(AbstractThread* aThread, bool aForceDispatch = false)
      76             :   {
      77             :     if (!aForceDispatch && aThread->IsCurrentThreadIn()) {
      78             :       mRunnable->Run();
      79             :       return;
      80             :     }
      81             : 
      82             :     // Check we don't have tail dispatching here. Otherwise we will deadlock
      83             :     // ourself when spinning the loop below.
      84             :     MOZ_ASSERT(!aThread->RequiresTailDispatchFromCurrentThread());
      85             : 
      86             :     aThread->Dispatch(RefPtr<nsIRunnable>(this).forget());
      87             :     mozilla::MonitorAutoLock lock(mMonitor);
      88             :     while (!mDone) {
      89             :       lock.Wait();
      90             :     }
      91             :   }
      92             : 
      93           1 :   static void DispatchToThread(nsIEventTarget* aThread,
      94             :                                nsIRunnable* aRunnable,
      95             :                                bool aForceDispatch = false)
      96             :   {
      97           2 :     RefPtr<SyncRunnable> s(new SyncRunnable(aRunnable));
      98           1 :     s->DispatchToThread(aThread, aForceDispatch);
      99           1 :   }
     100             : 
     101             :   static void DispatchToThread(AbstractThread* aThread,
     102             :                                nsIRunnable* aRunnable,
     103             :                                bool aForceDispatch = false)
     104             :   {
     105             :     RefPtr<SyncRunnable> s(new SyncRunnable(aRunnable));
     106             :     s->DispatchToThread(aThread, aForceDispatch);
     107             :   }
     108             : 
     109             : protected:
     110           2 :   NS_IMETHOD Run() override
     111             :   {
     112           2 :     mRunnable->Run();
     113             : 
     114           4 :     mozilla::MonitorAutoLock lock(mMonitor);
     115           2 :     MOZ_ASSERT(!mDone);
     116             : 
     117           2 :     mDone = true;
     118           2 :     mMonitor.Notify();
     119             : 
     120           4 :     return NS_OK;
     121             :   }
     122             : 
     123             : private:
     124             :   nsCOMPtr<nsIRunnable> mRunnable;
     125             :   mozilla::Monitor mMonitor;
     126             :   bool mDone;
     127             : };
     128             : 
     129             : } // namespace mozilla
     130             : 
     131             : #endif // mozilla_SyncRunnable_h

Generated by: LCOV version 1.13