1 /*
2  * Copyright 2008-2014 Arsen Chaloyan
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *     http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  *
16  * $Id: apt_task.c 2219 2014-11-11 02:35:14Z achaloyan@gmail.com $
17  */
18 
19 #ifdef WIN32
20 #pragma warning(disable: 4127)
21 #endif
22 #include <apr_ring.h>
23 #include <apr_thread_proc.h>
24 #include <apr_thread_cond.h>
25 #include <apr_portable.h>
26 #include "apt_task.h"
27 #include "apt_log.h"
28 
29 /** Internal states of the task */
30 typedef enum {
31 	TASK_STATE_IDLE,               /**< no task activity */
32 	TASK_STATE_START_REQUESTED,    /**< start of the task has been requested, but it's not running yet */
33 	TASK_STATE_RUNNING,            /**< task is running */
34 	TASK_STATE_TERMINATE_REQUESTED /**< termination of the task has been requested, but it's still running */
35 } apt_task_state_e;
36 
37 struct apt_task_t {
38 	APR_RING_ENTRY(apt_task_t) link;                 /* entry to parent task ring */
39 	APR_RING_HEAD(apt_task_head_t, apt_task_t) head; /* head of child tasks ring */
40 
41 	const char          *name;          /* name of the task */
42 	void                *obj;           /* external object associated with the task */
43 	apr_pool_t          *pool;          /* memory pool to allocate task data from */
44 	apt_task_msg_pool_t *msg_pool;      /* message pool to allocate task messages from */
45 	apr_thread_mutex_t  *data_guard;    /* mutex to protect task data */
46 	apr_thread_t        *thread_handle; /* thread handle */
47 	apt_task_state_e     state;         /* current task state */
48 	apt_task_vtable_t    vtable;        /* table of virtual methods */
49 	apt_task_t          *parent_task;   /* parent (master) task */
50 	apr_size_t           pending_start; /* number of pending start requests */
51 	apr_size_t           pending_term;  /* number of pending terminate requests */
52 	apr_size_t           pending_off;   /* number of pending taking-offline requests */
53 	apr_size_t           pending_on;    /* number of pending bringing-online requests */
54 	apt_bool_t           running;       /* task is running (TRUE if even terminate has already been requested) */
55 	apt_bool_t           auto_ready;    /* if TRUE, task is implicitly ready to process messages */
56 };
57 
58 static void* APR_THREAD_FUNC apt_task_run(apr_thread_t *thread_handle, void *data);
59 static APR_INLINE void apt_task_vtable_reset(apt_task_vtable_t *vtable);
60 
61 static apt_bool_t apt_task_core_msg_signal(apt_task_t *task, apt_task_msg_pool_t *msg_pool, apt_core_task_msg_type_e type);
62 
63 static apt_bool_t apt_task_terminate_request(apt_task_t *task);
64 
65 static apt_bool_t apt_task_start_process_internal(apt_task_t *task);
66 static apt_bool_t apt_task_terminate_process_internal(apt_task_t *task);
67 static apt_bool_t apt_task_offline_request_process(apt_task_t *task);
68 static apt_bool_t apt_task_online_request_process(apt_task_t *task);
69 
70 static apt_bool_t apt_task_offline_request_complete(apt_task_t *task);
71 static apt_bool_t apt_task_online_request_complete(apt_task_t *task);
72 
73 static void apt_task_start_complete_raise(apt_task_t *task);
74 static void apt_task_terminate_complete_raise(apt_task_t *task);
75 static void apt_task_offline_complete_raise(apt_task_t *task);
76 static void apt_task_online_complete_raise(apt_task_t *task);
77 
78 
apt_task_create(void * obj,apt_task_msg_pool_t * msg_pool,apr_pool_t * pool)79 APT_DECLARE(apt_task_t*) apt_task_create(
80 								void *obj,
81 								apt_task_msg_pool_t *msg_pool,
82 								apr_pool_t *pool)
83 {
84 	apt_task_t *task = apr_palloc(pool,sizeof(apt_task_t));
85 	task->obj = obj;
86 	task->pool = pool;
87 	task->msg_pool = msg_pool;
88 
89 	if(!task->msg_pool) {
90 		task->msg_pool = apt_task_msg_pool_create_dynamic(0,pool);
91 	}
92 
93 	task->state = TASK_STATE_IDLE;
94 	task->thread_handle = NULL;
95 	if(apr_thread_mutex_create(&task->data_guard, APR_THREAD_MUTEX_DEFAULT, task->pool) != APR_SUCCESS) {
96 		return NULL;
97 	}
98 
99 	/* reset vtable */
100 	apt_task_vtable_reset(&task->vtable);
101 	task->vtable.terminate = apt_task_terminate_request;
102 	task->vtable.process_start = apt_task_start_process_internal;
103 	task->vtable.process_terminate = apt_task_terminate_process_internal;
104 
105 	APR_RING_ELEM_INIT(task, link);
106 	APR_RING_INIT(&task->head, apt_task_t, link);
107 
108 	task->parent_task = NULL;
109 	task->pending_start = 0;
110 	task->pending_term = 0;
111 	task->pending_off = 0;
112 	task->pending_on = 0;
113 	task->auto_ready = TRUE;
114 	task->name = "Task";
115 	return task;
116 }
117 
apt_task_destroy(apt_task_t * task)118 APT_DECLARE(apt_bool_t) apt_task_destroy(apt_task_t *task)
119 {
120 	apt_task_t *child_task;
121 	APR_RING_FOREACH(child_task, &task->head, apt_task_t, link) {
122 		apt_task_destroy(child_task);
123 	}
124 
125 	if(task->state != TASK_STATE_IDLE) {
126 		apt_task_wait_till_complete(task);
127 	}
128 
129 	apt_log(APT_LOG_MARK,APT_PRIO_INFO,"Destroy Task [%s]",task->name);
130 	if(task->vtable.destroy) {
131 		task->vtable.destroy(task);
132 	}
133 
134 	apr_thread_mutex_destroy(task->data_guard);
135 	return TRUE;
136 }
137 
apt_task_add(apt_task_t * task,apt_task_t * child_task)138 APT_DECLARE(apt_bool_t) apt_task_add(apt_task_t *task, apt_task_t *child_task)
139 {
140 	if(!child_task)
141 		return FALSE;
142 
143 	child_task->parent_task = task;
144 	APR_RING_INSERT_TAIL(&task->head,child_task,apt_task_t,link);
145 	return TRUE;
146 }
147 
apt_task_start(apt_task_t * task)148 APT_DECLARE(apt_bool_t) apt_task_start(apt_task_t *task)
149 {
150 	apt_bool_t status = TRUE;
151 	apr_thread_mutex_lock(task->data_guard);
152 	if(task->state == TASK_STATE_IDLE) {
153 		apr_status_t rv;
154 		task->state = TASK_STATE_START_REQUESTED;
155 		apt_log(APT_LOG_MARK,APT_PRIO_INFO,"Start Task [%s]",task->name);
156 		if(task->vtable.start) {
157 			/* invoke virtual start method */
158 			task->vtable.start(task);
159 		}
160 		else {
161 			/* start new thread by default */
162 			rv = apr_thread_create(&task->thread_handle,NULL,apt_task_run,task,task->pool);
163 			if(rv != APR_SUCCESS) {
164 				task->state = TASK_STATE_IDLE;
165 				status = FALSE;
166 			}
167 		}
168 	}
169 	else {
170 		status = FALSE;
171 	}
172 	apr_thread_mutex_unlock(task->data_guard);
173 	return status;
174 }
175 
apt_task_offline(apt_task_t * task)176 APT_DECLARE(apt_bool_t) apt_task_offline(apt_task_t *task)
177 {
178 	return apt_task_core_msg_signal(task,task->msg_pool,CORE_TASK_MSG_TAKEOFFLINE_REQUEST);
179 }
180 
apt_task_online(apt_task_t * task)181 APT_DECLARE(apt_bool_t) apt_task_online(apt_task_t *task)
182 {
183 	return apt_task_core_msg_signal(task,task->msg_pool,CORE_TASK_MSG_BRINGONLINE_REQUEST);
184 }
185 
apt_task_terminate(apt_task_t * task,apt_bool_t wait_till_complete)186 APT_DECLARE(apt_bool_t) apt_task_terminate(apt_task_t *task, apt_bool_t wait_till_complete)
187 {
188 	apt_bool_t status = FALSE;
189 	apr_thread_mutex_lock(task->data_guard);
190 	if(task->state == TASK_STATE_START_REQUESTED || task->state == TASK_STATE_RUNNING) {
191 		task->state = TASK_STATE_TERMINATE_REQUESTED;
192 	}
193 	apr_thread_mutex_unlock(task->data_guard);
194 
195 	if(task->state == TASK_STATE_TERMINATE_REQUESTED) {
196 		/* invoke virtual terminate method */
197 		apt_log(APT_LOG_MARK,APT_PRIO_INFO,"Terminate Task [%s]",task->name);
198 		if(task->vtable.terminate) {
199 			status = task->vtable.terminate(task);
200 		}
201 
202 		if(wait_till_complete == TRUE && status == TRUE) {
203 			apt_task_wait_till_complete(task);
204 		}
205 	}
206 
207 	return status;
208 }
209 
apt_task_wait_till_complete(apt_task_t * task)210 APT_DECLARE(apt_bool_t) apt_task_wait_till_complete(apt_task_t *task)
211 {
212 	if(task->thread_handle) {
213 		apr_status_t s;
214 		apr_thread_join(&s,task->thread_handle);
215 		task->thread_handle = NULL;
216 	}
217 	return TRUE;
218 }
219 
apt_task_delay(apr_size_t msec)220 APT_DECLARE(void) apt_task_delay(apr_size_t msec)
221 {
222 	apr_sleep(1000*msec);
223 }
224 
apt_task_parent_get(const apt_task_t * task)225 APT_DECLARE(apt_task_t*) apt_task_parent_get(const apt_task_t *task)
226 {
227 	return task->parent_task;
228 }
229 
apt_task_pool_get(const apt_task_t * task)230 APT_DECLARE(apr_pool_t*) apt_task_pool_get(const apt_task_t *task)
231 {
232 	return task->pool;
233 }
234 
apt_task_object_get(const apt_task_t * task)235 APT_DECLARE(void*) apt_task_object_get(const apt_task_t *task)
236 {
237 	return task->obj;
238 }
239 
apt_task_vtable_get(apt_task_t * task)240 APT_DECLARE(apt_task_vtable_t*) apt_task_vtable_get(apt_task_t *task)
241 {
242 	return &task->vtable;
243 }
244 
apt_task_name_set(apt_task_t * task,const char * name)245 APT_DECLARE(void) apt_task_name_set(apt_task_t *task, const char *name)
246 {
247 	task->name = name;
248 }
249 
apt_task_name_get(const apt_task_t * task)250 APT_DECLARE(const char*) apt_task_name_get(const apt_task_t *task)
251 {
252 	return task->name;
253 }
254 
apt_task_msg_get(apt_task_t * task)255 APT_DECLARE(apt_task_msg_t*) apt_task_msg_get(apt_task_t *task)
256 {
257 	if(task->msg_pool) {
258 		return apt_task_msg_acquire(task->msg_pool);
259 	}
260 	return NULL;
261 }
262 
apt_task_msg_signal(apt_task_t * task,apt_task_msg_t * msg)263 APT_DECLARE(apt_bool_t) apt_task_msg_signal(apt_task_t *task, apt_task_msg_t *msg)
264 {
265 	apt_log(APT_LOG_MARK,APT_PRIO_DEBUG,"Signal Message to [%s] ["APT_PTR_FMT";%d;%d]",
266 		task->name, msg, msg->type, msg->sub_type);
267 	if(task->vtable.signal_msg) {
268 		if(task->vtable.signal_msg(task,msg) == TRUE) {
269 			return TRUE;
270 		}
271 	}
272 
273 	apt_log(APT_LOG_MARK,APT_PRIO_WARNING,"Failed to Signal Task Message [%s] [0x%x;%d;%d]",
274 		task->name, msg, msg->type, msg->sub_type);
275 	apt_task_msg_release(msg);
276 	return FALSE;
277 }
278 
apt_task_msg_parent_signal(apt_task_t * task,apt_task_msg_t * msg)279 APT_DECLARE(apt_bool_t) apt_task_msg_parent_signal(apt_task_t *task, apt_task_msg_t *msg)
280 {
281 	apt_task_t *parent_task = task->parent_task;
282 	if(parent_task) {
283 		return apt_task_msg_signal(parent_task,msg);
284 	}
285 
286 	apt_log(APT_LOG_MARK,APT_PRIO_WARNING,"Null Parent Task [%s]",task->name);
287 	apt_task_msg_release(msg);
288 	return FALSE;
289 }
290 
apt_task_core_msg_signal(apt_task_t * task,apt_task_msg_pool_t * msg_pool,apt_core_task_msg_type_e type)291 static apt_bool_t apt_task_core_msg_signal(apt_task_t *task, apt_task_msg_pool_t *msg_pool, apt_core_task_msg_type_e type)
292 {
293 	if(task && msg_pool) {
294 		apt_task_msg_t *msg = apt_task_msg_acquire(msg_pool);
295 		/* signal core task message */
296 		msg->type = TASK_MSG_CORE;
297 		msg->sub_type = type;
298 		return apt_task_msg_signal(task,msg);
299 	}
300 	return FALSE;
301 }
302 
apt_core_task_msg_process(apt_task_t * task,apt_task_msg_t * msg)303 static apt_bool_t apt_core_task_msg_process(apt_task_t *task, apt_task_msg_t *msg)
304 {
305 	switch(msg->sub_type) {
306 		case CORE_TASK_MSG_START_COMPLETE:
307 			apt_task_start_request_remove(task);
308 			break;
309 		case CORE_TASK_MSG_TERMINATE_REQUEST:
310 			if(task->vtable.process_terminate) {
311 				task->vtable.process_terminate(task);
312 			}
313 			break;
314 		case CORE_TASK_MSG_TERMINATE_COMPLETE:
315 			apt_task_terminate_request_remove(task);
316 			break;
317 		case CORE_TASK_MSG_TAKEOFFLINE_REQUEST:
318 			apt_task_offline_request_process(task);
319 			break;
320 		case CORE_TASK_MSG_TAKEOFFLINE_COMPLETE:
321 			apt_task_offline_request_complete(task);
322 			break;
323 		case CORE_TASK_MSG_BRINGONLINE_REQUEST:
324 			apt_task_online_request_process(task);
325 			break;
326 		case CORE_TASK_MSG_BRINGONLINE_COMPLETE:
327 			apt_task_online_request_complete(task);
328 			break;
329 		default: break;
330 	}
331 	return TRUE;
332 }
333 
apt_task_msg_process(apt_task_t * task,apt_task_msg_t * msg)334 APT_DECLARE(apt_bool_t) apt_task_msg_process(apt_task_t *task, apt_task_msg_t *msg)
335 {
336 	apt_bool_t status = FALSE;
337 	apt_log(APT_LOG_MARK,APT_PRIO_DEBUG,"Process Message [%s] ["APT_PTR_FMT";%d;%d]",
338 		task->name, msg, msg->type, msg->sub_type);
339 	if(msg->type == TASK_MSG_CORE) {
340 		status = apt_core_task_msg_process(task,msg);
341 	}
342 	else {
343 		if(task->vtable.process_msg) {
344 			status = task->vtable.process_msg(task,msg);
345 		}
346 	}
347 
348 	apt_task_msg_release(msg);
349 	return status;
350 }
351 
apt_task_terminate_request(apt_task_t * task)352 static apt_bool_t apt_task_terminate_request(apt_task_t *task)
353 {
354 	return apt_task_core_msg_signal(task,task->msg_pool,CORE_TASK_MSG_TERMINATE_REQUEST);
355 }
356 
apt_task_start_request_process(apt_task_t * task)357 APT_DECLARE(apt_bool_t) apt_task_start_request_process(apt_task_t *task)
358 {
359 	return apt_task_start_process_internal(task);
360 }
361 
apt_task_start_process_internal(apt_task_t * task)362 static apt_bool_t apt_task_start_process_internal(apt_task_t *task)
363 {
364 	apt_task_t *child_task;
365 	APR_RING_FOREACH(child_task, &task->head, apt_task_t, link) {
366 		if(apt_task_start(child_task) == TRUE) {
367 			task->pending_start++;
368 		}
369 	}
370 
371 	if(!task->pending_start) {
372 		/* no child task to start, just raise start-complete event */
373 		apt_task_start_complete_raise(task);
374 	}
375 	return TRUE;
376 }
377 
apt_task_terminate_request_process(apt_task_t * task)378 APT_DECLARE(apt_bool_t) apt_task_terminate_request_process(apt_task_t *task)
379 {
380 	return apt_task_terminate_process_internal(task);
381 }
382 
apt_task_terminate_process_internal(apt_task_t * task)383 static apt_bool_t apt_task_terminate_process_internal(apt_task_t *task)
384 {
385 	apt_task_t *child_task;
386 	APR_RING_FOREACH(child_task, &task->head, apt_task_t, link) {
387 #ifdef ENABLE_SIMULT_TASK_TERMINATION
388 		if(child_task->thread_handle) {
389 			apr_thread_detach(child_task->thread_handle);
390 			child_task->thread_handle = NULL;
391 		}
392 		if(apt_task_terminate(child_task,FALSE) == TRUE) {
393 			task->pending_term++;
394 		}
395 #else
396 		apt_task_terminate(child_task,TRUE);
397 #endif
398 	}
399 
400 	if(!task->pending_term) {
401 		/* no child task to terminate, just raise terminate-complete event */
402 		apt_task_terminate_complete_raise(task);
403 		task->running = FALSE;
404 	}
405 	return TRUE;
406 }
407 
apt_task_offline_request_process(apt_task_t * task)408 static apt_bool_t apt_task_offline_request_process(apt_task_t *task)
409 {
410 	apt_task_t *child_task;
411 	APR_RING_FOREACH(child_task, &task->head, apt_task_t, link) {
412 		if(apt_task_offline(child_task) == TRUE) {
413 			task->pending_off++;
414 		}
415 	}
416 
417 	if(!task->pending_off) {
418 		/* no child task, just raise offline-complete event */
419 		apt_task_offline_complete_raise(task);
420 	}
421 	return TRUE;
422 }
423 
apt_task_online_request_process(apt_task_t * task)424 static apt_bool_t apt_task_online_request_process(apt_task_t *task)
425 {
426 	apt_task_t *child_task;
427 	APR_RING_FOREACH(child_task, &task->head, apt_task_t, link) {
428 		if(apt_task_online(child_task) == TRUE) {
429 			task->pending_on++;
430 		}
431 	}
432 
433 	if(!task->pending_on) {
434 		/* no child task, just raise online-complete event */
435 		apt_task_online_complete_raise(task);
436 	}
437 	return TRUE;
438 }
439 
apt_task_auto_ready_set(apt_task_t * task,apt_bool_t auto_ready)440 APT_DECLARE(void) apt_task_auto_ready_set(apt_task_t *task, apt_bool_t auto_ready)
441 {
442 	task->auto_ready = auto_ready;
443 }
444 
apt_task_ready(apt_task_t * task)445 APT_DECLARE(apt_bool_t) apt_task_ready(apt_task_t *task)
446 {
447 	if(task->auto_ready == TRUE) {
448 		return FALSE;
449 	}
450 
451 	/* start child tasks (if any) */
452 	if(task->vtable.process_start) {
453 		task->vtable.process_start(task);
454 	}
455 	return TRUE;
456 }
457 
apt_task_running_flag_get(apt_task_t * task)458 APT_DECLARE(apt_bool_t*) apt_task_running_flag_get(apt_task_t *task)
459 {
460 	return &task->running;
461 }
462 
apt_task_start_request_add(apt_task_t * task)463 APT_DECLARE(apt_bool_t) apt_task_start_request_add(apt_task_t *task)
464 {
465 	task->pending_start++;
466 	return TRUE;
467 }
468 
apt_task_start_request_remove(apt_task_t * task)469 APT_DECLARE(apt_bool_t) apt_task_start_request_remove(apt_task_t *task)
470 {
471 	if(!task->pending_start) {
472 		/* error case, no pending start */
473 		return FALSE;
474 	}
475 	task->pending_start--;
476 	if(!task->pending_start) {
477 		apt_task_start_complete_raise(task);
478 	}
479 	return TRUE;
480 }
481 
apt_task_terminate_request_add(apt_task_t * task)482 APT_DECLARE(apt_bool_t) apt_task_terminate_request_add(apt_task_t *task)
483 {
484 	task->pending_term++;
485 	return TRUE;
486 }
487 
apt_task_terminate_request_remove(apt_task_t * task)488 APT_DECLARE(apt_bool_t) apt_task_terminate_request_remove(apt_task_t *task)
489 {
490 	if(!task->pending_term) {
491 		/* error case, no pending terminate */
492 		return FALSE;
493 	}
494 	task->pending_term--;
495 	if(!task->pending_term) {
496 		apt_task_terminate_complete_raise(task);
497 		task->running = FALSE;
498 	}
499 	return TRUE;
500 }
501 
apt_task_offline_request_complete(apt_task_t * task)502 static apt_bool_t apt_task_offline_request_complete(apt_task_t *task)
503 {
504 	if(!task->pending_off) {
505 		/* error case, no pending request */
506 		return FALSE;
507 	}
508 	task->pending_off--;
509 	if(!task->pending_off) {
510 		apt_task_offline_complete_raise(task);
511 	}
512 	return TRUE;
513 }
514 
apt_task_online_request_complete(apt_task_t * task)515 static apt_bool_t apt_task_online_request_complete(apt_task_t *task)
516 {
517 	if(!task->pending_on) {
518 		/* error case, no pending request */
519 		return FALSE;
520 	}
521 	task->pending_on--;
522 	if(!task->pending_on) {
523 		apt_task_online_complete_raise(task);
524 	}
525 	return TRUE;
526 }
527 
apt_task_start_complete_raise(apt_task_t * task)528 static void apt_task_start_complete_raise(apt_task_t *task)
529 {
530 	apt_log(APT_LOG_MARK,APT_PRIO_DEBUG,"Task Started [%s]",task->name);
531 	if(task->vtable.on_start_complete) {
532 		task->vtable.on_start_complete(task);
533 	}
534 	apt_task_core_msg_signal(task->parent_task,task->msg_pool,CORE_TASK_MSG_START_COMPLETE);
535 }
536 
apt_task_terminate_complete_raise(apt_task_t * task)537 static void apt_task_terminate_complete_raise(apt_task_t *task)
538 {
539 	apt_log(APT_LOG_MARK,APT_PRIO_DEBUG,"Task Terminated [%s]",task->name);
540 	if(task->vtable.on_terminate_complete) {
541 		task->vtable.on_terminate_complete(task);
542 	}
543 #ifdef ENABLE_SIMULT_TASK_TERMINATION
544 	apt_task_core_msg_signal(task->parent_task,task->msg_pool,CORE_TASK_MSG_TERMINATE_COMPLETE);
545 #endif
546 }
547 
apt_task_offline_complete_raise(apt_task_t * task)548 static void apt_task_offline_complete_raise(apt_task_t *task)
549 {
550 	apt_log(APT_LOG_MARK,APT_PRIO_DEBUG,"Task Taken Offline [%s]",task->name);
551 	if(task->vtable.on_offline_complete) {
552 		task->vtable.on_offline_complete(task);
553 	}
554 	apt_task_core_msg_signal(task->parent_task,task->msg_pool,CORE_TASK_MSG_TAKEOFFLINE_COMPLETE);
555 }
556 
apt_task_online_complete_raise(apt_task_t * task)557 static void apt_task_online_complete_raise(apt_task_t *task)
558 {
559 	apt_log(APT_LOG_MARK,APT_PRIO_DEBUG,"Task Brought Online [%s]",task->name);
560 	if(task->vtable.on_online_complete) {
561 		task->vtable.on_online_complete(task);
562 	}
563 	apt_task_core_msg_signal(task->parent_task,task->msg_pool,CORE_TASK_MSG_BRINGONLINE_COMPLETE);
564 }
565 
apt_task_run(apr_thread_t * thread_handle,void * data)566 static void* APR_THREAD_FUNC apt_task_run(apr_thread_t *thread_handle, void *data)
567 {
568 	apt_task_t *task = data;
569 
570 #if APR_HAS_SETTHREADNAME
571 	apr_thread_name_set(task->name);
572 #endif
573 	/* raise pre-run event */
574 	if(task->vtable.on_pre_run) {
575 		task->vtable.on_pre_run(task);
576 	}
577 	apr_thread_mutex_lock(task->data_guard);
578 	task->state = TASK_STATE_RUNNING;
579 	task->running = TRUE;
580 	apr_thread_mutex_unlock(task->data_guard);
581 
582 	if(task->auto_ready == TRUE) {
583 		/* start child tasks (if any) */
584 		if(task->vtable.process_start) {
585 			task->vtable.process_start(task);
586 		}
587 	}
588 
589 	/* run task */
590 	if(task->vtable.run) {
591 		task->vtable.run(task);
592 	}
593 
594 	apr_thread_mutex_lock(task->data_guard);
595 	task->state = TASK_STATE_IDLE;
596 	task->running = FALSE;
597 	apr_thread_mutex_unlock(task->data_guard);
598 	/* raise post-run event */
599 	if(task->vtable.on_post_run) {
600 		task->vtable.on_post_run(task);
601 	}
602 
603 	apr_thread_exit(thread_handle,APR_SUCCESS);
604 	return NULL;
605 }
606 
apt_task_vtable_reset(apt_task_vtable_t * vtable)607 static APR_INLINE void apt_task_vtable_reset(apt_task_vtable_t *vtable)
608 {
609 	vtable->destroy = NULL;
610 	vtable->start = NULL;
611 	vtable->terminate = NULL;
612 	vtable->run = NULL;
613 	vtable->signal_msg = NULL;
614 	vtable->process_msg = NULL;
615 	vtable->process_start = NULL;
616 	vtable->process_terminate = NULL;
617 	vtable->on_pre_run = NULL;
618 	vtable->on_post_run = NULL;
619 	vtable->on_start_complete = NULL;
620 	vtable->on_terminate_complete = NULL;
621 	vtable->on_offline_complete = NULL;
622 	vtable->on_online_complete = NULL;
623 }
624