Coverage Report

Created: 2018-09-25 14:53

/work/obj-fuzz/dist/include/mozilla/CooperativeThreadPool.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_CooperativeThreadPool_h
8
#define mozilla_CooperativeThreadPool_h
9
10
#include "mozilla/Array.h"
11
#include "mozilla/CondVar.h"
12
#include "mozilla/Mutex.h"
13
#include "mozilla/ThreadLocal.h"
14
#include "mozilla/UniquePtr.h"
15
#include "mozilla/Variant.h"
16
#include "nsCOMPtr.h"
17
#include "nsThreadUtils.h"
18
#include "prthread.h"
19
20
// Windows silliness. winbase.h defines an empty no-argument Yield macro.
21
#undef Yield
22
23
class nsIEventTarget;
24
25
namespace mozilla {
26
27
// A CooperativeThreadPool is a pool of threads that process jobs, with at most
28
// one thread running at a given time. While processing a job, a thread can
29
// yield to another thread in the pool. Threads can be blocked on abstract
30
// Resources. When a thread yields, we iterate over all threads and look for
31
// one whose Resource has become available. It's possible that no thread is
32
// available to run, in which case all threads in the pool sleep. An outside
33
// thread can get things started again by calling RecheckBlockers (presumably
34
// after it has mutated some state that it expects would cause a Resource to
35
// become available).
36
class CooperativeThreadPool
37
{
38
public:
39
  // Every pool must have a controller object, on which callbacks are invoked.
40
  class Controller
41
  {
42
  public:
43
    // Called when a new thread in the pool is started. aIndex is the index of
44
    // the thread within the pool. aName is the thread name (e.g., Main#4), and
45
    // aStackTop is the guess for the address of the top of the stack. The
46
    // thread will begin processing events immediately after OnStartThread is called.
47
    virtual void OnStartThread(size_t aIndex, const nsACString& aName, void* aStackTop) = 0;
48
49
    // Called when a thread in the pool is about to be shut down.
50
    virtual void OnStopThread(size_t aIndex) = 0;
51
52
    // Threads in the pool are either suspended or running. At most one thread
53
    // will be running at any time. All other threads will be suspended.
54
55
    // Called when a thread is resumed (un-suspended). Note that OnResumeThread
56
    // will not be called if the thread is starting up. OnStartThread will be
57
    // called instead.
58
    virtual void OnResumeThread(size_t aIndex) = 0;
59
60
    // Called when a thread in the pool is about to be suspended. Note that
61
    // OnSuspendThread will not be called if the thread is shutting
62
    // down. OnStopThread is called instead.
63
    virtual void OnSuspendThread(size_t aIndex) = 0;
64
  };
65
66
  CooperativeThreadPool(size_t aNumThreads,
67
                        Mutex& aMutex,
68
                        Controller& aController);
69
  ~CooperativeThreadPool();
70
71
  void Shutdown();
72
73
  // An abstract class representing something that can be blocked on. Examples
74
  // are an event queue (where IsAvailable would check if the queue is
75
  // non-empty) or an object that can be owned by only one thread at a time
76
  // (where IsAvailable would check if the object is unowned).
77
  class Resource {
78
  public:
79
    virtual bool IsAvailable(const MutexAutoLock& aProofOfLock) = 0;
80
  };
81
82
  // Typically called by a thread outside the pool, this will check if any
83
  // thread is blocked on a resource that has become available. In this case,
84
  // the thread will resume. Nothing is done if some thread in the pool was
85
  // already running.
86
  void RecheckBlockers(const MutexAutoLock& aProofOfLock);
87
88
  // Must be called from within the thread pool. Causes the current thread to be
89
  // blocked on aBlocker, which can be null if the thread is ready to run
90
  // unconditionally.
91
  static void Yield(Resource* aBlocker, const MutexAutoLock& aProofOfLock);
92
93
  static bool IsCooperativeThread();
94
95
  enum class AllThreadsBlocked { Blocked };
96
  using SelectedThread = Variant<size_t, AllThreadsBlocked>;
97
98
  SelectedThread CurrentThreadIndex(const MutexAutoLock& aProofOfLock) const;
99
100
  static const size_t kMaxThreads = 16;
101
102
private:
103
  class CooperativeThread
104
  {
105
    friend class CooperativeThreadPool;
106
107
  public:
108
    CooperativeThread(CooperativeThreadPool* aPool,
109
                      size_t aIndex);
110
111
    void BeginShutdown();
112
    void EndShutdown();
113
114
    void Started();
115
116
    bool IsBlocked(const MutexAutoLock& aProofOfLock);
117
0
    void SetBlocker(Resource* aResource) { mBlocker = aResource; }
118
119
    void Yield(const MutexAutoLock& aProofOfLock);
120
121
  private:
122
    static void ThreadFunc(void* aArg);
123
    void ThreadMethod();
124
125
    CooperativeThreadPool* mPool;
126
    CondVar mCondVar;
127
    Resource* mBlocker;
128
    PRThread* mThread;
129
    nsCOMPtr<nsIEventTarget> mEventTarget;
130
    const size_t mIndex;
131
    bool mRunning;
132
  };
133
134
  class StartRunnable;
135
136
  Mutex& mMutex;
137
  CondVar mShutdownCondition;
138
  nsThreadPoolNaming mThreadNaming;
139
140
  bool mRunning;
141
  const size_t mNumThreads;
142
  size_t mRunningThreads;
143
  Controller& mController;
144
  Array<UniquePtr<CooperativeThread>, kMaxThreads> mThreads;
145
146
  SelectedThread mSelectedThread;
147
148
  static MOZ_THREAD_LOCAL(CooperativeThread*) sTlsCurrentThread;
149
};
150
151
} // namespace mozilla
152
153
#endif // mozilla_CooperativeThreadPool_h