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