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