Coverage Report

Created: 2018-09-25 14:53

/work/obj-fuzz/dist/include/mozilla/SyncRunnable.h
Line
Count
Source (jump to first uncovered line)
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
class SyncRunnable : public Runnable
34
{
35
public:
36
  explicit SyncRunnable(nsIRunnable* aRunnable)
37
    : Runnable("SyncRunnable")
38
    , mRunnable(aRunnable)
39
    , mMonitor("SyncRunnable")
40
    , mDone(false)
41
0
  {
42
0
  }
43
44
  explicit SyncRunnable(already_AddRefed<nsIRunnable> aRunnable)
45
    : Runnable("SyncRunnable")
46
    , mRunnable(std::move(aRunnable))
47
    , mMonitor("SyncRunnable")
48
    , mDone(false)
49
0
  {
50
0
  }
51
52
  void DispatchToThread(nsIEventTarget* aThread, bool aForceDispatch = false)
53
0
  {
54
0
    nsresult rv;
55
0
    bool on;
56
0
57
0
    if (!aForceDispatch) {
58
0
      rv = aThread->IsOnCurrentThread(&on);
59
0
      MOZ_ASSERT(NS_SUCCEEDED(rv));
60
0
      if (NS_SUCCEEDED(rv) && on) {
61
0
        mRunnable->Run();
62
0
        return;
63
0
      }
64
0
    }
65
0
66
0
    rv = aThread->Dispatch(this, NS_DISPATCH_NORMAL);
67
0
    if (NS_SUCCEEDED(rv)) {
68
0
      mozilla::MonitorAutoLock lock(mMonitor);
69
0
      while (!mDone) {
70
0
        lock.Wait();
71
0
      }
72
0
    }
73
0
  }
74
75
  void DispatchToThread(AbstractThread* aThread, bool aForceDispatch = false)
76
0
  {
77
0
    if (!aForceDispatch && aThread->IsCurrentThreadIn()) {
78
0
      mRunnable->Run();
79
0
      return;
80
0
    }
81
0
82
0
    // Check we don't have tail dispatching here. Otherwise we will deadlock
83
0
    // ourself when spinning the loop below.
84
0
    MOZ_ASSERT(!aThread->RequiresTailDispatchFromCurrentThread());
85
0
86
0
    aThread->Dispatch(RefPtr<nsIRunnable>(this).forget());
87
0
    mozilla::MonitorAutoLock lock(mMonitor);
88
0
    while (!mDone) {
89
0
      lock.Wait();
90
0
    }
91
0
  }
92
93
  static void DispatchToThread(nsIEventTarget* aThread,
94
                               nsIRunnable* aRunnable,
95
                               bool aForceDispatch = false)
96
0
  {
97
0
    RefPtr<SyncRunnable> s(new SyncRunnable(aRunnable));
98
0
    s->DispatchToThread(aThread, aForceDispatch);
99
0
  }
100
101
  static void DispatchToThread(AbstractThread* aThread,
102
                               nsIRunnable* aRunnable,
103
                               bool aForceDispatch = false)
104
0
  {
105
0
    RefPtr<SyncRunnable> s(new SyncRunnable(aRunnable));
106
0
    s->DispatchToThread(aThread, aForceDispatch);
107
0
  }
108
109
protected:
110
  NS_IMETHOD Run() override
111
0
  {
112
0
    mRunnable->Run();
113
0
114
0
    mozilla::MonitorAutoLock lock(mMonitor);
115
0
    MOZ_ASSERT(!mDone);
116
0
117
0
    mDone = true;
118
0
    mMonitor.Notify();
119
0
120
0
    return NS_OK;
121
0
  }
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