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