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
15GenericThread::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
29GenericThread::~GenericThread()
30{
31	kill_thread(fThreadId);
32
33	delete_sem(fExecuteUnitSem);
34}
35
36
37status_t
38GenericThread::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
81status_t
82GenericThread::ThreadStartup()
83{
84	// This function is virtual.
85	// Subclass and override this function.
86
87	return B_OK;
88}
89
90
91status_t
92GenericThread::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
104status_t
105GenericThread::ThreadShutdown()
106{
107	// This function is virtual.
108	// Subclass and override this function.
109
110	return B_OK;
111}
112
113
114void
115GenericThread::ThreadStartupFailed(status_t status)
116{
117	// This function is virtual.
118	// Subclass and override this function.
119
120	Quit();
121}
122
123
124void
125GenericThread::ExecuteUnitFailed(status_t status)
126{
127	// This function is virtual.
128	// Subclass and override this function.
129
130	Quit();
131}
132
133
134void
135GenericThread::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
144status_t
145GenericThread::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
163int32
164GenericThread::_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
174BMessage*
175GenericThread::GetDataStore()
176{
177	return fThreadDataStore;
178}
179
180
181void
182GenericThread::SetDataStore(BMessage* message)
183{
184	fThreadDataStore = message;
185}
186
187
188status_t
189GenericThread::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
210void
211GenericThread::Quit()
212{
213	fQuitRequested = true;
214}
215
216
217bool
218GenericThread::HasQuitBeenRequested()
219{
220	return fQuitRequested;
221}
222
223
224bool
225GenericThread::IsPaused()
226{
227	return fThreadIsPaused;
228}
229
230
231status_t
232GenericThread::Suspend()
233{
234	return suspend_thread(fThreadId);
235}
236
237
238status_t
239GenericThread::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
250status_t
251GenericThread::Kill()
252{
253	return kill_thread(fThreadId);
254}
255
256
257void
258GenericThread::ExitWithReturnValue(status_t return_value)
259{
260	exit_thread(return_value);
261}
262
263
264status_t
265GenericThread::SetExitCallback(void (*callback)(void*), void* data)
266{
267	return on_exit_thread(callback, data);
268}
269
270
271status_t
272GenericThread::WaitForThread(status_t* exitValue)
273{
274	return wait_for_thread(fThreadId, exitValue);
275}
276
277
278status_t
279GenericThread::Rename(char* name)
280{
281	return rename_thread(fThreadId, name);
282}
283
284
285status_t
286GenericThread::SendData(int32 code, void* buffer, size_t buffer_size)
287{
288	return send_data(fThreadId, code, buffer, buffer_size);
289}
290
291
292int32
293GenericThread::ReceiveData(thread_id* sender, void* buffer, size_t buffer_size)
294{
295	return receive_data(sender, buffer, buffer_size);
296}
297
298
299bool
300GenericThread::HasData()
301{
302	return has_data(fThreadId);
303}
304
305
306status_t
307GenericThread::SetPriority(int32 newPriority)
308{
309	return set_thread_priority(fThreadId, newPriority);
310}
311
312
313void
314GenericThread::Snooze(bigtime_t microseconds)
315{
316	Suspend();
317	snooze(microseconds);
318	Resume();
319}
320
321
322void
323GenericThread::SnoozeUntil(bigtime_t microseconds, int timebase)
324{
325	Suspend();
326	snooze_until(microseconds, timebase);
327	Resume();
328}
329
330
331status_t
332GenericThread::GetInfo(thread_info* threadInfo)
333{
334	return get_thread_info(fThreadId, threadInfo);
335}
336
337
338thread_id
339GenericThread::GetThread()
340{
341	thread_info	threadInfo;
342	GetInfo(&threadInfo);
343	return threadInfo.thread;
344}
345
346
347team_id
348GenericThread::GetTeam()
349{
350	thread_info	threadInfo;
351	GetInfo(&threadInfo);
352	return threadInfo.team;
353}
354
355
356char*
357GenericThread::GetName()
358{
359	thread_info	threadInfo;
360	GetInfo(&threadInfo);
361	return strdup(threadInfo.name);
362}
363
364
365thread_state
366GenericThread::GetState()
367{
368	thread_info	threadInfo;
369	GetInfo(&threadInfo);
370	return threadInfo.state;
371}
372
373
374sem_id
375GenericThread::GetSemaphore()
376{
377	thread_info	threadInfo;
378	GetInfo(&threadInfo);
379	return threadInfo.sem;
380}
381
382
383int32
384GenericThread::GetPriority()
385{
386	thread_info	threadInfo;
387	GetInfo(&threadInfo);
388	return threadInfo.priority;
389}
390
391
392bigtime_t
393GenericThread::GetUserTime()
394{
395	thread_info	threadInfo;
396	GetInfo(&threadInfo);
397	return threadInfo.user_time;
398}
399
400
401bigtime_t
402GenericThread::GetKernelTime()
403{
404	thread_info	threadInfo;
405	GetInfo(&threadInfo);
406	return threadInfo.kernel_time;
407}
408
409
410void*
411GenericThread::GetStackBase()
412{
413	thread_info	threadInfo;
414	GetInfo(&threadInfo);
415	return threadInfo.stack_base;
416}
417
418
419void*
420GenericThread::GetStackEnd()
421{
422	thread_info	threadInfo;
423	GetInfo(&threadInfo);
424	return threadInfo.stack_end;
425}
426
427
428void
429GenericThread::BeginUnit()
430{
431	acquire_sem(fExecuteUnitSem);
432		// thread can not be paused until it releases semaphore
433}
434
435
436void
437GenericThread::EndUnit()
438{
439	release_sem(fExecuteUnitSem);
440		// thread can now be paused
441}
442
443