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