1 /*
2 * Copyright 2003-2009, Haiku, Inc. All Rights Reserved.
3 * Distributed under the terms of the MIT License.
4 *
5 * Authors:
6 * Jonas Sundström, jonas@kirilla.com
7 */
8
9
10 #include "GenericThread.h"
11
12 #include <string.h>
13
14
GenericThread(const char * thread_name,int32 priority,BMessage * message)15 GenericThread::GenericThread(const char* thread_name, int32 priority,
16 BMessage* message)
17 :
18 fThreadDataStore(message),
19 fThreadId(spawn_thread(_ThreadFunction, thread_name, priority, this)),
20 fExecuteUnitSem(create_sem(1, "fExecuteUnitSem")),
21 fQuitRequested(false),
22 fThreadIsPaused(false)
23 {
24 if (fThreadDataStore == NULL)
25 fThreadDataStore = new BMessage();
26 }
27
28
~GenericThread()29 GenericThread::~GenericThread()
30 {
31 kill_thread(fThreadId);
32
33 delete_sem(fExecuteUnitSem);
34 }
35
36
37 status_t
ThreadFunction()38 GenericThread::ThreadFunction()
39 {
40 status_t status = B_OK;
41
42 status = ThreadStartup();
43 // Subclass and override this function
44
45 if (status != B_OK) {
46 ThreadStartupFailed(status);
47 return status;
48 // is this the right thing to do?
49 }
50
51 while (1) {
52 if (HasQuitBeenRequested()) {
53 status = ThreadShutdown();
54 // Subclass and override this function
55
56 if (status != B_OK) {
57 ThreadShutdownFailed(status);
58 return status;
59 }
60
61 delete this;
62 return B_OK;
63 }
64
65 BeginUnit();
66
67 status = ExecuteUnit();
68 // Subclass and override
69
70 if (status != B_OK)
71 ExecuteUnitFailed(status);
72 // Subclass and override
73
74 EndUnit();
75 }
76
77 return B_OK;
78 }
79
80
81 status_t
ThreadStartup()82 GenericThread::ThreadStartup()
83 {
84 // This function is virtual.
85 // Subclass and override this function.
86
87 return B_OK;
88 }
89
90
91 status_t
ExecuteUnit()92 GenericThread::ExecuteUnit()
93 {
94 // This function is virtual.
95
96 // You would normally subclass and override this function
97 // as it will provide you with Pause and Quit functionality
98 // thanks to the unit management done by GenericThread::ThreadFunction()
99
100 return B_OK;
101 }
102
103
104 status_t
ThreadShutdown()105 GenericThread::ThreadShutdown()
106 {
107 // This function is virtual.
108 // Subclass and override this function.
109
110 return B_OK;
111 }
112
113
114 void
ThreadStartupFailed(status_t status)115 GenericThread::ThreadStartupFailed(status_t status)
116 {
117 // This function is virtual.
118 // Subclass and override this function.
119
120 Quit();
121 }
122
123
124 void
ExecuteUnitFailed(status_t status)125 GenericThread::ExecuteUnitFailed(status_t status)
126 {
127 // This function is virtual.
128 // Subclass and override this function.
129
130 Quit();
131 }
132
133
134 void
ThreadShutdownFailed(status_t status)135 GenericThread::ThreadShutdownFailed(status_t status)
136 {
137 // This function is virtual.
138 // Subclass and override this function.
139
140 // (is this good default behaviour?)
141 }
142
143
144 status_t
Start()145 GenericThread::Start()
146 {
147 status_t status = B_OK;
148
149 if (IsPaused()) {
150 status = release_sem(fExecuteUnitSem);
151 if (status != B_OK)
152 return status;
153
154 fThreadIsPaused = false;
155 }
156
157 status = resume_thread(fThreadId);
158
159 return status;
160 }
161
162
163 int32
_ThreadFunction(void * simple_thread_ptr)164 GenericThread::_ThreadFunction(void* simple_thread_ptr)
165 {
166 status_t status = B_OK;
167
168 status = ((GenericThread*) simple_thread_ptr)->ThreadFunction();
169
170 return status;
171 }
172
173
174 BMessage*
GetDataStore()175 GenericThread::GetDataStore()
176 {
177 return fThreadDataStore;
178 }
179
180
181 void
SetDataStore(BMessage * message)182 GenericThread::SetDataStore(BMessage* message)
183 {
184 fThreadDataStore = message;
185 }
186
187
188 status_t
Pause(bool doBlock,bigtime_t timeout)189 GenericThread::Pause(bool doBlock, bigtime_t timeout)
190 {
191 status_t status = B_OK;
192
193 if (doBlock)
194 status = acquire_sem(fExecuteUnitSem);
195 // thread will wait on semaphore
196 else
197 status = acquire_sem_etc(fExecuteUnitSem, 1, B_RELATIVE_TIMEOUT,
198 timeout);
199 // thread will timeout
200
201 if (status == B_OK) {
202 fThreadIsPaused = true;
203 return B_OK;
204 }
205
206 return status;
207 }
208
209
210 void
Quit()211 GenericThread::Quit()
212 {
213 fQuitRequested = true;
214 }
215
216
217 bool
HasQuitBeenRequested()218 GenericThread::HasQuitBeenRequested()
219 {
220 return fQuitRequested;
221 }
222
223
224 bool
IsPaused()225 GenericThread::IsPaused()
226 {
227 return fThreadIsPaused;
228 }
229
230
231 status_t
Suspend()232 GenericThread::Suspend()
233 {
234 return suspend_thread(fThreadId);
235 }
236
237
238 status_t
Resume()239 GenericThread::Resume()
240 {
241 release_sem(fExecuteUnitSem);
242 // to counteract Pause()
243 fThreadIsPaused = false;
244
245 return resume_thread(fThreadId);
246 // to counteract Suspend()
247 }
248
249
250 status_t
Kill()251 GenericThread::Kill()
252 {
253 return kill_thread(fThreadId);
254 }
255
256
257 void
ExitWithReturnValue(status_t return_value)258 GenericThread::ExitWithReturnValue(status_t return_value)
259 {
260 exit_thread(return_value);
261 }
262
263
264 status_t
SetExitCallback(void (* callback)(void *),void * data)265 GenericThread::SetExitCallback(void (*callback)(void*), void* data)
266 {
267 return on_exit_thread(callback, data);
268 }
269
270
271 status_t
WaitForThread(status_t * exitValue)272 GenericThread::WaitForThread(status_t* exitValue)
273 {
274 return wait_for_thread(fThreadId, exitValue);
275 }
276
277
278 status_t
Rename(char * name)279 GenericThread::Rename(char* name)
280 {
281 return rename_thread(fThreadId, name);
282 }
283
284
285 status_t
SendData(int32 code,void * buffer,size_t buffer_size)286 GenericThread::SendData(int32 code, void* buffer, size_t buffer_size)
287 {
288 return send_data(fThreadId, code, buffer, buffer_size);
289 }
290
291
292 int32
ReceiveData(thread_id * sender,void * buffer,size_t buffer_size)293 GenericThread::ReceiveData(thread_id* sender, void* buffer, size_t buffer_size)
294 {
295 return receive_data(sender, buffer, buffer_size);
296 }
297
298
299 bool
HasData()300 GenericThread::HasData()
301 {
302 return has_data(fThreadId);
303 }
304
305
306 status_t
SetPriority(int32 newPriority)307 GenericThread::SetPriority(int32 newPriority)
308 {
309 return set_thread_priority(fThreadId, newPriority);
310 }
311
312
313 void
Snooze(bigtime_t microseconds)314 GenericThread::Snooze(bigtime_t microseconds)
315 {
316 Suspend();
317 snooze(microseconds);
318 Resume();
319 }
320
321
322 void
SnoozeUntil(bigtime_t microseconds,int timebase)323 GenericThread::SnoozeUntil(bigtime_t microseconds, int timebase)
324 {
325 Suspend();
326 snooze_until(microseconds, timebase);
327 Resume();
328 }
329
330
331 status_t
GetInfo(thread_info * threadInfo)332 GenericThread::GetInfo(thread_info* threadInfo)
333 {
334 return get_thread_info(fThreadId, threadInfo);
335 }
336
337
338 thread_id
GetThread()339 GenericThread::GetThread()
340 {
341 thread_info threadInfo;
342 GetInfo(&threadInfo);
343 return threadInfo.thread;
344 }
345
346
347 team_id
GetTeam()348 GenericThread::GetTeam()
349 {
350 thread_info threadInfo;
351 GetInfo(&threadInfo);
352 return threadInfo.team;
353 }
354
355
356 char*
GetName()357 GenericThread::GetName()
358 {
359 thread_info threadInfo;
360 GetInfo(&threadInfo);
361 return strdup(threadInfo.name);
362 }
363
364
365 thread_state
GetState()366 GenericThread::GetState()
367 {
368 thread_info threadInfo;
369 GetInfo(&threadInfo);
370 return threadInfo.state;
371 }
372
373
374 sem_id
GetSemaphore()375 GenericThread::GetSemaphore()
376 {
377 thread_info threadInfo;
378 GetInfo(&threadInfo);
379 return threadInfo.sem;
380 }
381
382
383 int32
GetPriority()384 GenericThread::GetPriority()
385 {
386 thread_info threadInfo;
387 GetInfo(&threadInfo);
388 return threadInfo.priority;
389 }
390
391
392 bigtime_t
GetUserTime()393 GenericThread::GetUserTime()
394 {
395 thread_info threadInfo;
396 GetInfo(&threadInfo);
397 return threadInfo.user_time;
398 }
399
400
401 bigtime_t
GetKernelTime()402 GenericThread::GetKernelTime()
403 {
404 thread_info threadInfo;
405 GetInfo(&threadInfo);
406 return threadInfo.kernel_time;
407 }
408
409
410 void*
GetStackBase()411 GenericThread::GetStackBase()
412 {
413 thread_info threadInfo;
414 GetInfo(&threadInfo);
415 return threadInfo.stack_base;
416 }
417
418
419 void*
GetStackEnd()420 GenericThread::GetStackEnd()
421 {
422 thread_info threadInfo;
423 GetInfo(&threadInfo);
424 return threadInfo.stack_end;
425 }
426
427
428 void
BeginUnit()429 GenericThread::BeginUnit()
430 {
431 acquire_sem(fExecuteUnitSem);
432 // thread can not be paused until it releases semaphore
433 }
434
435
436 void
EndUnit()437 GenericThread::EndUnit()
438 {
439 release_sem(fExecuteUnitSem);
440 // thread can now be paused
441 }
442
443