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