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