1 //===-- MIUtilThreadBaseStd.cpp ---------------------------------*- C++ -*-===//
2 //
3 // The LLVM Compiler Infrastructure
4 //
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
7 //
8 //===----------------------------------------------------------------------===//
9
10 // Third Party Headers:
11 #include <assert.h>
12
13 // In-house headers:
14 #include "MICmnThreadMgrStd.h"
15 #include "MIUtilThreadBaseStd.h"
16
17 //++
18 //------------------------------------------------------------------------------------
19 // Details: Constructor.
20 // Type: None.
21 // Args: None.
22 // Return: None.
23 // Throws: None.
24 //--
CMIUtilThreadActiveObjBase()25 CMIUtilThreadActiveObjBase::CMIUtilThreadActiveObjBase()
26 : m_references(0), m_bHasBeenKilled(false) {}
27
28 //++
29 //------------------------------------------------------------------------------------
30 // Details: Destructor.
31 // Type: None.
32 // Args: None.
33 // Return: None.
34 // Throws: None.
35 //--
~CMIUtilThreadActiveObjBase()36 CMIUtilThreadActiveObjBase::~CMIUtilThreadActiveObjBase() {
37 // Make sure our thread is not alive before we die
38 m_thread.Join();
39 }
40
41 //++
42 //------------------------------------------------------------------------------------
43 // Details: Check if an object is already running.
44 // Type: Method.
45 // Args: None.
46 // Return: MIstatus::success - Functional succeeded.
47 // MIstatus::failure - Functional failed.
48 // Throws: None.
49 //--
ThreadIsActive()50 bool CMIUtilThreadActiveObjBase::ThreadIsActive() {
51 // Create a new thread to occupy this threads Run() function
52 return m_thread.IsActive();
53 }
54
55 //++
56 //------------------------------------------------------------------------------------
57 // Details: Set up *this thread.
58 // Type: Method.
59 // Args: None.
60 // Return: MIstatus::success - Functional succeeded.
61 // MIstatus::failure - Functional failed.
62 // Throws: None.
63 //--
ThreadExecute()64 bool CMIUtilThreadActiveObjBase::ThreadExecute() {
65 // Create a new thread to occupy this threads Run() function
66 return m_thread.Start(ThreadEntry, this);
67 }
68
69 //++
70 //------------------------------------------------------------------------------------
71 // Details: Acquire a reference to CMIUtilThreadActiveObjBase.
72 // Type: Method.
73 // Args: None.
74 // Return: MIstatus::success - Functional succeeded.
75 // MIstatus::failure - Functional failed.
76 // Throws: None.
77 //--
Acquire()78 bool CMIUtilThreadActiveObjBase::Acquire() {
79 // Access to this function is serial
80 CMIUtilThreadLock serial(m_mutex);
81
82 // >0 == *this thread is alive
83 m_references++;
84
85 return MIstatus::success;
86 }
87
88 //++
89 //------------------------------------------------------------------------------------
90 // Details: Release a reference to CMIUtilThreadActiveObjBase.
91 // Type: Method.
92 // Args: None.
93 // Return: MIstatus::success - Functional succeeded.
94 // MIstatus::failure - Functional failed.
95 // Throws: None.
96 //--
Release()97 bool CMIUtilThreadActiveObjBase::Release() {
98 // Access to this function is serial
99 CMIUtilThreadLock serial(m_mutex);
100
101 // 0 == kill off *this thread
102 m_references--;
103
104 return MIstatus::success;
105 }
106
107 //++
108 //------------------------------------------------------------------------------------
109 // Details: Force this thread to stop, regardless of references
110 // Type: Method.
111 // Args: None.
112 // Return: MIstatus::success - Functional succeeded.
113 // MIstatus::failure - Functional failed.
114 // Throws: None.
115 //--
ThreadKill()116 bool CMIUtilThreadActiveObjBase::ThreadKill() {
117 // Access to this function is serial
118 CMIUtilThreadLock serial(m_mutex);
119
120 // Set this thread to killed status
121 m_bHasBeenKilled = true;
122
123 return MIstatus::success;
124 }
125
126 //++
127 //------------------------------------------------------------------------------------
128 // Details: Proxy to thread join.
129 // Type: Method.
130 // Args: None.
131 // Return: MIstatus::success - Functional succeeded.
132 // MIstatus::failure - Functional failed.
133 // Throws: None.
134 //--
ThreadJoin()135 bool CMIUtilThreadActiveObjBase::ThreadJoin() { return m_thread.Join(); }
136
137 //++
138 //------------------------------------------------------------------------------------
139 // Details: This function is the entry point of this object thread.
140 // It is a trampoline to an instances operation manager.
141 // Type: Static method.
142 // Args: vpThisClass - (R) From the system (our CMIUtilThreadActiveObjBase
143 // from the ctor).
144 // Return: MIuint - 0 = success.
145 // Throws: None.
146 //--
ThreadEntry(void * vpThisClass)147 MIuint CMIUtilThreadActiveObjBase::ThreadEntry(void *vpThisClass) {
148 // The argument is a pointer to a CMIUtilThreadActiveObjBase class
149 // as passed from the initialize function, so we can safely cast it.
150 assert(vpThisClass != nullptr);
151 CMIUtilThreadActiveObjBase *pActive =
152 reinterpret_cast<CMIUtilThreadActiveObjBase *>(vpThisClass);
153
154 // Start the management routine of this object
155 pActive->ThreadManage();
156
157 // Thread death
158 return 0;
159 }
160
161 //++
162 //------------------------------------------------------------------------------------
163 // Details: This function forms a small management routine, to handle the
164 // thread's running.
165 // Type: Method.
166 // Args: None.
167 // Return: None.
168 // Throws: None.
169 //--
ThreadManage()170 void CMIUtilThreadActiveObjBase::ThreadManage() {
171 bool bAlive = true;
172
173 // Infinite loop
174 while (bAlive) {
175 // Scope the lock while we access m_isDying
176 {
177 // Lock down access to the interface
178 CMIUtilThreadLock serial(m_mutex);
179
180 // Quit the run loop if we are dying
181 if (m_references == 0)
182 break;
183 }
184 // Execute the run routine
185 if (!ThreadRun(bAlive))
186 // Thread's run function failed (MIstatus::failure)
187 break;
188
189 // We will die if we have been signaled to die
190 bAlive &= !m_bHasBeenKilled;
191 }
192
193 // Execute the finish routine just before we die
194 // to give the object a chance to clean up
195 ThreadFinish();
196
197 m_thread.Finish();
198 }
199
200 //---------------------------------------------------------------------------------------
201 //---------------------------------------------------------------------------------------
202 //---------------------------------------------------------------------------------------
203
204 //
CMIUtilThread()205 CMIUtilThread::CMIUtilThread() : m_pThread(nullptr), m_bIsActive(false) {}
206
207 //++
208 //------------------------------------------------------------------------------------
209 // Details: CMIUtilThread destructor.
210 // Type: Method.
211 // Args: None.
212 // Return: None.
213 // Throws: None.
214 //--
~CMIUtilThread()215 CMIUtilThread::~CMIUtilThread() { Join(); }
216
217 //++
218 //------------------------------------------------------------------------------------
219 // Details: Wait for thread to stop.
220 // Type: Method.
221 // Args: None.
222 // Return: MIstatus::success - Functional succeeded.
223 // MIstatus::failure - Functional failed.
224 // Throws: None.
225 //--
Join()226 bool CMIUtilThread::Join() {
227 if (m_pThread != nullptr) {
228 // Wait for this thread to die
229 m_pThread->join();
230
231 // Scope the thread lock while we modify the pointer
232 {
233 CMIUtilThreadLock _lock(m_mutex);
234 delete m_pThread;
235 m_pThread = nullptr;
236 }
237 }
238
239 return MIstatus::success;
240 }
241
242 //++
243 //------------------------------------------------------------------------------------
244 // Details: Is the thread doing work.
245 // Type: Method.
246 // Args: None.
247 // Return: bool - True = Yes active, false = not active.
248 // Throws: None.
249 //--
IsActive()250 bool CMIUtilThread::IsActive() {
251 // Lock while we access the thread status
252 CMIUtilThreadLock _lock(m_mutex);
253 return m_bIsActive;
254 }
255
256 //++
257 //------------------------------------------------------------------------------------
258 // Details: Finish this thread
259 // Type: Method.
260 // Args: None.
261 // Return: None.
262 // Throws: None.
263 //--
Finish()264 void CMIUtilThread::Finish() {
265 // Lock while we access the thread status
266 CMIUtilThreadLock _lock(m_mutex);
267 m_bIsActive = false;
268 }
269
270 //++
271 //------------------------------------------------------------------------------------
272 // Details: Set up *this thread.
273 // Type: Method.
274 // Args: vpFn (R) - Function pointer to thread's main function.
275 // vpArg (R) - Pointer arguments to pass to the thread.
276 // Return: MIstatus::success - Functional succeeded.
277 // MIstatus::failure - Functional failed.
278 // Throws: None.
279 //--
Start(FnThreadProc vpFn,void * vpArg)280 bool CMIUtilThread::Start(FnThreadProc vpFn, void *vpArg) {
281 // Lock while we access the thread pointer and status
282 CMIUtilThreadLock _lock(m_mutex);
283
284 // Create the std thread, which starts immediately and update its status
285 m_pThread = new std::thread(vpFn, vpArg);
286 m_bIsActive = true;
287
288 // We expect to always be able to create one
289 assert(m_pThread != nullptr);
290
291 return MIstatus::success;
292 }
293
294 //---------------------------------------------------------------------------------------
295 //---------------------------------------------------------------------------------------
296 //---------------------------------------------------------------------------------------
297
298 //++
299 //------------------------------------------------------------------------------------
300 // Details: Take resource.
301 // Type: Method.
302 // Args: None.
303 // Return: None.
304 // Throws: None.
305 //--
Lock()306 void CMIUtilThreadMutex::Lock() { m_mutex.lock(); }
307
308 //++
309 //------------------------------------------------------------------------------------
310 // Details: Release resource.
311 // Type: Method.
312 // Args: None.
313 // Return: None.
314 // Throws: None.
315 //--
Unlock()316 void CMIUtilThreadMutex::Unlock() { m_mutex.unlock(); }
317
318 //++
319 //------------------------------------------------------------------------------------
320 // Details: Take resource if available. Immediately return in either case.
321 // Type: Method.
322 // Args: None.
323 // Return: True - mutex has been locked.
324 // False - mutex could not be locked.
325 // Throws: None.
326 //--
TryLock()327 bool CMIUtilThreadMutex::TryLock() { return m_mutex.try_lock(); }
328