155a5a6bdSJérôme Duval// license: public domain
255a5a6bdSJérôme Duval// authors: jonas.sundstrom@kirilla.com
355a5a6bdSJérôme Duval
4e326cef6SJohn Scipione
5338b8dc3SIngo Weinhold#include "GenericThread.h"
655a5a6bdSJérôme Duval
7866ece31SStefano Ceccherini#include <string.h>
8866ece31SStefano Ceccherini
9e326cef6SJohn Scipione
10e326cef6SJohn ScipioneGenericThread::GenericThread(const char* threadName, int32 priority,
11e326cef6SJohn Scipione	BMessage* message)
1255a5a6bdSJérôme Duval	:
13b5d458a5SStefano Ceccherini	fThreadDataStore(message),
14e326cef6SJohn Scipione	fThreadId(spawn_thread(private_thread_function, threadName, priority,
15e326cef6SJohn Scipione		this)),
16b5d458a5SStefano Ceccherini	fExecuteUnit(create_sem(1, "ExecuteUnit sem")),
17b5d458a5SStefano Ceccherini	fQuitRequested(false),
18b5d458a5SStefano Ceccherini	fThreadIsPaused(false)
1955a5a6bdSJérôme Duval{
20b5d458a5SStefano Ceccherini	if (fThreadDataStore == NULL)
21e326cef6SJohn Scipione		fThreadDataStore = new BMessage();
2255a5a6bdSJérôme Duval}
2355a5a6bdSJérôme Duval
24b5d458a5SStefano Ceccherini
2555a5a6bdSJérôme DuvalGenericThread::~GenericThread()
2655a5a6bdSJérôme Duval{
27b5d458a5SStefano Ceccherini	kill_thread(fThreadId);
2896303159SJérôme Duval
29b5d458a5SStefano Ceccherini	delete_sem(fExecuteUnit);
3055a5a6bdSJérôme Duval}
3155a5a6bdSJérôme Duval
32b5d458a5SStefano Ceccherini
3396303159SJérôme Duvalstatus_t
3496303159SJérôme DuvalGenericThread::ThreadFunction(void)
3555a5a6bdSJérôme Duval{
36e326cef6SJohn Scipione	status_t status = B_OK;
3796303159SJérôme Duval
38e326cef6SJohn Scipione	status = ThreadStartup();
39e326cef6SJohn Scipione		// Subclass and override this function
40e326cef6SJohn Scipione	if (status != B_OK) {
4196303159SJérôme Duval		ThreadStartupFailed(status);
4255a5a6bdSJérôme Duval		return (status);
43e326cef6SJohn Scipione			// is this the right thing to do?
4455a5a6bdSJérôme Duval	}
4596303159SJérôme Duval
46e326cef6SJohn Scipione	while (1) {
47e326cef6SJohn Scipione		if (HasQuitBeenRequested()) {
48e326cef6SJohn Scipione			status = ThreadShutdown();
49e326cef6SJohn Scipione				// Subclass and override this function
50e326cef6SJohn Scipione			if (status != B_OK){
5196303159SJérôme Duval				ThreadShutdownFailed(status);
5255a5a6bdSJérôme Duval				return (status);
53e326cef6SJohn Scipione					// what do we do?
5455a5a6bdSJérôme Duval			}
5596303159SJérôme Duval
56e326cef6SJohn Scipione			delete this;
57e326cef6SJohn Scipione				// destructor
58f7266392SJonas Sundström			return B_OK;
5955a5a6bdSJérôme Duval		}
6055a5a6bdSJérôme Duval
6155a5a6bdSJérôme Duval		BeginUnit();
6255a5a6bdSJérôme Duval
63e326cef6SJohn Scipione		status = ExecuteUnit();
64e326cef6SJohn Scipione			// Subclass and override
6555a5a6bdSJérôme Duval
66e326cef6SJohn Scipione		// Subclass and override
6755a5a6bdSJérôme Duval		if (status != B_OK)
68e326cef6SJohn Scipione			ExecuteUnitFailed(status);
6996303159SJérôme Duval
7096303159SJérôme Duval		EndUnit();
7155a5a6bdSJérôme Duval	}
7255a5a6bdSJérôme Duval
7355a5a6bdSJérôme Duval	return (B_OK);
7455a5a6bdSJérôme Duval}
7555a5a6bdSJérôme Duval
76b5d458a5SStefano Ceccherini
7796303159SJérôme Duvalstatus_t
7896303159SJérôme DuvalGenericThread::ThreadStartup(void)
7955a5a6bdSJérôme Duval{
8055a5a6bdSJérôme Duval	// This function is virtual.
8155a5a6bdSJérôme Duval	// Subclass and override this function.
8255a5a6bdSJérôme Duval
8355a5a6bdSJérôme Duval	return B_OK;
8455a5a6bdSJérôme Duval}
8555a5a6bdSJérôme Duval
8655a5a6bdSJérôme Duval
8796303159SJérôme Duvalstatus_t
8896303159SJérôme DuvalGenericThread::ExecuteUnit(void)
8955a5a6bdSJérôme Duval{
9055a5a6bdSJérôme Duval	// This function is virtual.
9155a5a6bdSJérôme Duval
9255a5a6bdSJérôme Duval	// You would normally subclass and override this function
9355a5a6bdSJérôme Duval	// as it will provide you with Pause and Quit functionality
9455a5a6bdSJérôme Duval	// thanks to the unit management done by GenericThread::ThreadFunction()
9555a5a6bdSJérôme Duval
9655a5a6bdSJérôme Duval	return B_OK;
9755a5a6bdSJérôme Duval}
9855a5a6bdSJérôme Duval
99b5d458a5SStefano Ceccherini
10096303159SJérôme Duvalstatus_t
10196303159SJérôme DuvalGenericThread::ThreadShutdown(void)
10255a5a6bdSJérôme Duval{
10355a5a6bdSJérôme Duval	// This function is virtual.
10455a5a6bdSJérôme Duval	// Subclass and override this function.
10555a5a6bdSJérôme Duval
10655a5a6bdSJérôme Duval	return B_OK;
10755a5a6bdSJérôme Duval}
10855a5a6bdSJérôme Duval
109b5d458a5SStefano Ceccherini
11096303159SJérôme Duvalvoid
111e326cef6SJohn ScipioneGenericThread::ThreadStartupFailed(status_t status)
11255a5a6bdSJérôme Duval{
11355a5a6bdSJérôme Duval	// This function is virtual.
11455a5a6bdSJérôme Duval	// Subclass and override this function.
11596303159SJérôme Duval
11655a5a6bdSJérôme Duval	Quit();
11755a5a6bdSJérôme Duval}
11855a5a6bdSJérôme Duval
119b5d458a5SStefano Ceccherini
12096303159SJérôme Duvalvoid
121e326cef6SJohn ScipioneGenericThread::ExecuteUnitFailed(status_t status)
12255a5a6bdSJérôme Duval{
12355a5a6bdSJérôme Duval	// This function is virtual.
12455a5a6bdSJérôme Duval	// Subclass and override this function.
12596303159SJérôme Duval
12655a5a6bdSJérôme Duval	Quit();
12755a5a6bdSJérôme Duval}
12855a5a6bdSJérôme Duval
129b5d458a5SStefano Ceccherini
13096303159SJérôme Duvalvoid
131e326cef6SJohn ScipioneGenericThread::ThreadShutdownFailed(status_t status)
13255a5a6bdSJérôme Duval{
13355a5a6bdSJérôme Duval	// This function is virtual.
13455a5a6bdSJérôme Duval	// Subclass and override this function.
13596303159SJérôme Duval
13655a5a6bdSJérôme Duval	// (is this good default behaviour?)
13755a5a6bdSJérôme Duval}
13855a5a6bdSJérôme Duval
139b5d458a5SStefano Ceccherini
14096303159SJérôme Duvalstatus_t
14196303159SJérôme DuvalGenericThread::Start(void)
14255a5a6bdSJérôme Duval{
143e326cef6SJohn Scipione	status_t status = B_OK;
14496303159SJérôme Duval
145e326cef6SJohn Scipione	if (IsPaused()) {
146e326cef6SJohn Scipione		status = release_sem(fExecuteUnit);
14755a5a6bdSJérôme Duval		if (status != B_OK)
14855a5a6bdSJérôme Duval			return status;
14955a5a6bdSJérôme Duval
150e326cef6SJohn Scipione		fThreadIsPaused = false;
15155a5a6bdSJérôme Duval	}
15296303159SJérôme Duval
153e326cef6SJohn Scipione	status = resume_thread(fThreadId);
15496303159SJérôme Duval
15555a5a6bdSJérôme Duval	return status;
15655a5a6bdSJérôme Duval}
15755a5a6bdSJérôme Duval
158b5d458a5SStefano Ceccherini
15996303159SJérôme Duvalint32
160e326cef6SJohn ScipioneGenericThread::private_thread_function(void* pointer)
16155a5a6bdSJérôme Duval{
162e326cef6SJohn Scipione	return ((GenericThread*)pointer)->ThreadFunction();
16355a5a6bdSJérôme Duval}
16455a5a6bdSJérôme Duval
165b5d458a5SStefano Ceccherini
166e326cef6SJohn ScipioneBMessage*
16796303159SJérôme DuvalGenericThread::GetDataStore(void)
16855a5a6bdSJérôme Duval{
169e326cef6SJohn Scipione	return fThreadDataStore;
17055a5a6bdSJérôme Duval}
17155a5a6bdSJérôme Duval
172b5d458a5SStefano Ceccherini
17355a5a6bdSJérôme Duvalvoid
174e326cef6SJohn ScipioneGenericThread::SetDataStore(BMessage* message)
17555a5a6bdSJérôme Duval{
176b5d458a5SStefano Ceccherini	fThreadDataStore  =  message;
17755a5a6bdSJérôme Duval}
17855a5a6bdSJérôme Duval
179b5d458a5SStefano Ceccherini
18096303159SJérôme Duvalstatus_t
181e326cef6SJohn ScipioneGenericThread::Pause(bool shouldBlock, bigtime_t timeout)
18255a5a6bdSJérôme Duval{
183e326cef6SJohn Scipione	status_t status = B_OK;
18496303159SJérôme Duval
185e326cef6SJohn Scipione	if (shouldBlock) {
186e326cef6SJohn Scipione		// thread will wait on semaphore
187e326cef6SJohn Scipione		status = acquire_sem(fExecuteUnit);
188e326cef6SJohn Scipione	} else {
189e326cef6SJohn Scipione		// thread will timeout
190e326cef6SJohn Scipione		status = acquire_sem_etc(fExecuteUnit, 1, B_RELATIVE_TIMEOUT, timeout);
191e326cef6SJohn Scipione	}
19255a5a6bdSJérôme Duval
193e326cef6SJohn Scipione	if (status == B_OK) {
194e326cef6SJohn Scipione		fThreadIsPaused = true;
195e326cef6SJohn Scipione		return B_OK;
19655a5a6bdSJérôme Duval	}
19796303159SJérôme Duval
19855a5a6bdSJérôme Duval	return status;
19955a5a6bdSJérôme Duval}
20055a5a6bdSJérôme Duval
201b5d458a5SStefano Ceccherini
20296303159SJérôme Duvalvoid
20396303159SJérôme DuvalGenericThread::Quit(void)
20455a5a6bdSJérôme Duval{
205e326cef6SJohn Scipione	fQuitRequested = true;
20655a5a6bdSJérôme Duval}
20755a5a6bdSJérôme Duval
208b5d458a5SStefano Ceccherini
20996303159SJérôme Duvalbool
21096303159SJérôme DuvalGenericThread::HasQuitBeenRequested(void)
21155a5a6bdSJérôme Duval{
212e326cef6SJohn Scipione	return fQuitRequested;
21355a5a6bdSJérôme Duval}
21455a5a6bdSJérôme Duval
215b5d458a5SStefano Ceccherini
21696303159SJérôme Duvalbool
21796303159SJérôme DuvalGenericThread::IsPaused(void)
21855a5a6bdSJérôme Duval{
219e326cef6SJohn Scipione	return fThreadIsPaused;
22055a5a6bdSJérôme Duval}
22155a5a6bdSJérôme Duval
222b5d458a5SStefano Ceccherini
22396303159SJérôme Duvalstatus_t
22496303159SJérôme DuvalGenericThread::Suspend(void)
22555a5a6bdSJérôme Duval{
226e326cef6SJohn Scipione	return suspend_thread(fThreadId);
22755a5a6bdSJérôme Duval}
22855a5a6bdSJérôme Duval
229b5d458a5SStefano Ceccherini
23096303159SJérôme Duvalstatus_t
23196303159SJérôme DuvalGenericThread::Resume(void)
23255a5a6bdSJérôme Duval{
233e326cef6SJohn Scipione	release_sem(fExecuteUnit);
234e326cef6SJohn Scipione		// to counteract Pause()
235e326cef6SJohn Scipione	fThreadIsPaused = false;
23696303159SJérôme Duval
237e326cef6SJohn Scipione	return (resume_thread(fThreadId));
238e326cef6SJohn Scipione		// to counteract Suspend()
23955a5a6bdSJérôme Duval}
24055a5a6bdSJérôme Duval
241b5d458a5SStefano Ceccherini
24296303159SJérôme Duvalstatus_t
24396303159SJérôme DuvalGenericThread::Kill(void)
24455a5a6bdSJérôme Duval{
245b5d458a5SStefano Ceccherini	return (kill_thread(fThreadId));
24655a5a6bdSJérôme Duval}
24755a5a6bdSJérôme Duval
248b5d458a5SStefano Ceccherini
24996303159SJérôme Duvalvoid
250e326cef6SJohn ScipioneGenericThread::ExitWithReturnValue(status_t returnValue)
25155a5a6bdSJérôme Duval{
252e326cef6SJohn Scipione	exit_thread(returnValue);
25355a5a6bdSJérôme Duval}
25455a5a6bdSJérôme Duval
255b5d458a5SStefano Ceccherini
25696303159SJérôme Duvalstatus_t
257e326cef6SJohn ScipioneGenericThread::SetExitCallback(void (*callback)(void*), void* data)
25855a5a6bdSJérôme Duval{
259e326cef6SJohn Scipione	return (on_exit_thread(callback, data));
26055a5a6bdSJérôme Duval}
26155a5a6bdSJérôme Duval
262b5d458a5SStefano Ceccherini
26396303159SJérôme Duvalstatus_t
264e326cef6SJohn ScipioneGenericThread::WaitForThread(status_t* exitValue)
26555a5a6bdSJérôme Duval{
266e326cef6SJohn Scipione	return (wait_for_thread(fThreadId, exitValue));
26755a5a6bdSJérôme Duval}
26855a5a6bdSJérôme Duval
269b5d458a5SStefano Ceccherini
27096303159SJérôme Duvalstatus_t
271e326cef6SJohn ScipioneGenericThread::Rename(char* name)
27255a5a6bdSJérôme Duval{
273e326cef6SJohn Scipione	return (rename_thread(fThreadId, name));
27455a5a6bdSJérôme Duval}
27555a5a6bdSJérôme Duval
276b5d458a5SStefano Ceccherini
27796303159SJérôme Duvalstatus_t
278e326cef6SJohn ScipioneGenericThread::SendData(int32 code, void* buffer, size_t size)
27955a5a6bdSJérôme Duval{
280e326cef6SJohn Scipione	return (send_data(fThreadId, code, buffer, size));
28155a5a6bdSJérôme Duval}
28255a5a6bdSJérôme Duval
283b5d458a5SStefano Ceccherini
28496303159SJérôme Duvalint32
285e326cef6SJohn ScipioneGenericThread::ReceiveData(thread_id* sender, void* buffer, size_t size)
28655a5a6bdSJérôme Duval{
287e326cef6SJohn Scipione	return (receive_data(sender, buffer, size));
28855a5a6bdSJérôme Duval}
28996303159SJérôme Duval
290b5d458a5SStefano Ceccherini
29196303159SJérôme Duvalbool
29296303159SJérôme DuvalGenericThread::HasData(void)
29355a5a6bdSJérôme Duval{
294b5d458a5SStefano Ceccherini	return (has_data(fThreadId));
29555a5a6bdSJérôme Duval}
29696303159SJérôme Duval
297b5d458a5SStefano Ceccherini
29896303159SJérôme Duvalstatus_t
299e326cef6SJohn ScipioneGenericThread::SetPriority(int32 priority)
30055a5a6bdSJérôme Duval{
301e326cef6SJohn Scipione	return (set_thread_priority(fThreadId, priority));
30255a5a6bdSJérôme Duval}
30355a5a6bdSJérôme Duval
304b5d458a5SStefano Ceccherini
30596303159SJérôme Duvalvoid
306e326cef6SJohn ScipioneGenericThread::Snooze(bigtime_t delay)
30755a5a6bdSJérôme Duval{
30855a5a6bdSJérôme Duval	Suspend();
309e326cef6SJohn Scipione	snooze(delay);
31055a5a6bdSJérôme Duval	Resume();
31155a5a6bdSJérôme Duval}
31255a5a6bdSJérôme Duval
313b5d458a5SStefano Ceccherini
31496303159SJérôme Duvalvoid
315e326cef6SJohn ScipioneGenericThread::SnoozeUntil(bigtime_t delay, int timeBase)
31655a5a6bdSJérôme Duval{
31755a5a6bdSJérôme Duval	Suspend();
318e326cef6SJohn Scipione	snooze_until(delay, timeBase);
31955a5a6bdSJérôme Duval	Resume();
32055a5a6bdSJérôme Duval}
32155a5a6bdSJérôme Duval
322b5d458a5SStefano Ceccherini
32396303159SJérôme Duvalstatus_t
324e326cef6SJohn ScipioneGenericThread::GetInfo(thread_info* info)
32555a5a6bdSJérôme Duval{
326e326cef6SJohn Scipione	return get_thread_info(fThreadId, info);
32755a5a6bdSJérôme Duval}
32855a5a6bdSJérôme Duval
329b5d458a5SStefano Ceccherini
33096303159SJérôme Duvalthread_id
33196303159SJérôme DuvalGenericThread::GetThread(void)
33255a5a6bdSJérôme Duval{
333e326cef6SJohn Scipione	thread_info info;
334e326cef6SJohn Scipione	GetInfo(&info);
335e326cef6SJohn Scipione	return info.thread;
33655a5a6bdSJérôme Duval}
33755a5a6bdSJérôme Duval
338b5d458a5SStefano Ceccherini
33996303159SJérôme Duvalteam_id
34096303159SJérôme DuvalGenericThread::GetTeam(void)
34155a5a6bdSJérôme Duval{
342e326cef6SJohn Scipione	thread_info info;
343e326cef6SJohn Scipione	GetInfo(&info);
344e326cef6SJohn Scipione	return info.team;
34555a5a6bdSJérôme Duval}
34655a5a6bdSJérôme Duval
347b5d458a5SStefano Ceccherini
348e326cef6SJohn Scipionechar*
34996303159SJérôme DuvalGenericThread::GetName(void)
35055a5a6bdSJérôme Duval{
351e326cef6SJohn Scipione	thread_info info;
352e326cef6SJohn Scipione	GetInfo(&info);
353e326cef6SJohn Scipione	return strdup(info.name);
35455a5a6bdSJérôme Duval}
35555a5a6bdSJérôme Duval
356b5d458a5SStefano Ceccherini
35796303159SJérôme Duvalthread_state
35896303159SJérôme DuvalGenericThread::GetState(void)
35955a5a6bdSJérôme Duval{
360e326cef6SJohn Scipione	thread_info info;
361e326cef6SJohn Scipione	GetInfo(&info);
362e326cef6SJohn Scipione	return info.state;
36355a5a6bdSJérôme Duval}
36455a5a6bdSJérôme Duval
365b5d458a5SStefano Ceccherini
36696303159SJérôme Duvalsem_id
36796303159SJérôme DuvalGenericThread::GetSemaphore(void)
36855a5a6bdSJérôme Duval{
369e326cef6SJohn Scipione	thread_info info;
370e326cef6SJohn Scipione	GetInfo(&info);
371e326cef6SJohn Scipione	return info.sem;
37255a5a6bdSJérôme Duval}
37355a5a6bdSJérôme Duval
374b5d458a5SStefano Ceccherini
37596303159SJérôme Duvalint32
37696303159SJérôme DuvalGenericThread::GetPriority(void)
37755a5a6bdSJérôme Duval{
378e326cef6SJohn Scipione	thread_info info;
379e326cef6SJohn Scipione	GetInfo(&info);
380e326cef6SJohn Scipione	return info.priority;
38155a5a6bdSJérôme Duval}
38255a5a6bdSJérôme Duval
383b5d458a5SStefano Ceccherini
38496303159SJérôme Duvalbigtime_t
38596303159SJérôme DuvalGenericThread::GetUserTime(void)
38655a5a6bdSJérôme Duval{
387e326cef6SJohn Scipione	thread_info info;
388e326cef6SJohn Scipione	GetInfo(&info);
389e326cef6SJohn Scipione	return info.user_time;
39055a5a6bdSJérôme Duval}
39155a5a6bdSJérôme Duval
392b5d458a5SStefano Ceccherini
39396303159SJérôme Duvalbigtime_t
39496303159SJérôme DuvalGenericThread::GetKernelTime(void)
39555a5a6bdSJérôme Duval{
396e326cef6SJohn Scipione	thread_info info;
397e326cef6SJohn Scipione	GetInfo(&info);
398e326cef6SJohn Scipione	return info.kernel_time;
39955a5a6bdSJérôme Duval}
40055a5a6bdSJérôme Duval
401b5d458a5SStefano Ceccherini
402e326cef6SJohn Scipionevoid*
40396303159SJérôme DuvalGenericThread::GetStackBase(void)
40455a5a6bdSJérôme Duval{
405e326cef6SJohn Scipione	thread_info info;
406e326cef6SJohn Scipione	GetInfo(&info);
407e326cef6SJohn Scipione	return info.stack_base;
40855a5a6bdSJérôme Duval}
40955a5a6bdSJérôme Duval
410b5d458a5SStefano Ceccherini
411e326cef6SJohn Scipionevoid*
41296303159SJérôme DuvalGenericThread::GetStackEnd(void)
41355a5a6bdSJérôme Duval{
414e326cef6SJohn Scipione	thread_info info;
415e326cef6SJohn Scipione	GetInfo(&info);
416e326cef6SJohn Scipione	return info.stack_end;
41755a5a6bdSJérôme Duval}
41855a5a6bdSJérôme Duval
419b5d458a5SStefano Ceccherini
42096303159SJérôme Duvalvoid
42196303159SJérôme DuvalGenericThread::BeginUnit(void)
42255a5a6bdSJérôme Duval{
423e326cef6SJohn Scipione	acquire_sem(fExecuteUnit);
424e326cef6SJohn Scipione		// thread can not be paused until it releases semaphore
42555a5a6bdSJérôme Duval}
42655a5a6bdSJérôme Duval
427b5d458a5SStefano Ceccherini
42896303159SJérôme Duvalvoid
42996303159SJérôme DuvalGenericThread::EndUnit(void)
43055a5a6bdSJérôme Duval{
431e326cef6SJohn Scipione	release_sem(fExecuteUnit);
432e326cef6SJohn Scipione		// thread can now be paused
43355a5a6bdSJérôme Duval}
434