/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 |