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