From d3a63a151997595647efe4b770283d5b2abd43ad Mon Sep 17 00:00:00 2001 From: Pekka Riikonen Date: Tue, 12 Dec 2006 18:38:42 +0000 Subject: [PATCH] Handle failed timeout additions (in case scheduler is stopped). --- lib/silcutil/silcfsm.c | 49 +++++++++++++++----------- lib/silcutil/silcfsm.h | 26 ++++++++++---- lib/silcutil/tests/test_silcschedule.c | 2 +- 3 files changed, 49 insertions(+), 28 deletions(-) diff --git a/lib/silcutil/silcfsm.c b/lib/silcutil/silcfsm.c index 5cd81e19..4df30aec 100644 --- a/lib/silcutil/silcfsm.c +++ b/lib/silcutil/silcfsm.c @@ -160,10 +160,11 @@ void silc_fsm_free(void *fsm) { SilcFSM f = fsm; if (!f->thread) - silc_schedule_task_add_timeout(f->schedule, silc_fsm_free_final, f, 0, 0); - else - silc_fsm_free_final(f->schedule, silc_schedule_get_context(f->schedule), - 0, 0, f); + if (silc_schedule_task_add_timeout(f->schedule, silc_fsm_free_final, + f, 0, 0)) + return; + silc_fsm_free_final(f->schedule, silc_schedule_get_context(f->schedule), + 0, 0, f); } /* Task to start real thread. We start threads through scheduler, not @@ -200,13 +201,18 @@ void silc_fsm_start(void *fsm, SilcFSMStateCallback start_state) /* Start real thread through scheduler */ if (f->thread && f->real_thread) { - silc_schedule_task_add_timeout(f->schedule, silc_fsm_start_real_thread, - f, 0, 0); + if (!silc_schedule_task_add_timeout(f->schedule, + silc_fsm_start_real_thread, + f, 0, 0)) + silc_fsm_start_real_thread(f->schedule, + silc_schedule_get_context(f->schedule), + 0, 0, f); return; } /* Normal FSM operation */ - silc_schedule_task_add_timeout(f->schedule, silc_fsm_run, f, 0, 0); + if (!silc_schedule_task_add_timeout(f->schedule, silc_fsm_run, f, 0, 0)) + silc_fsm_run(f->schedule, silc_schedule_get_context(f->schedule), 0, 0, f); } /* Start FSM in the specified state synchronously */ @@ -288,8 +294,13 @@ void silc_fsm_finish(void *fsm) SilcFSM f = fsm; SILC_ASSERT(!f->finished); - f->finished = TRUE; + + /* Machine must not have active threads */ + if (!f->thread && f->u.m.threads) + assert(f->u.m.threads == 0); + f->started = FALSE; + f->finished = TRUE; silc_schedule_task_del_by_all(f->schedule, 0, silc_fsm_run, f); f->next_later = FALSE; @@ -304,11 +315,13 @@ void silc_fsm_finish(void *fsm) } /* Normal FSM operation */ - if (f->synchronous) - silc_fsm_finish_fsm(f->schedule, silc_schedule_get_context(f->schedule), - 0, 0, fsm); - else - silc_schedule_task_add_timeout(f->schedule, silc_fsm_finish_fsm, f, 0, 0); + if (!f->synchronous) + if (silc_schedule_task_add_timeout(f->schedule, silc_fsm_finish_fsm, + f, 0, 0)) + return; + + silc_fsm_finish_fsm(f->schedule, silc_schedule_get_context(f->schedule), + 0, 0, fsm); } /* Return associated scheduler */ @@ -327,16 +340,12 @@ SilcFSM silc_fsm_get_machine(SilcFSMThread thread) return (SilcFSM)thread->u.t.fsm; } -/* Returns TRUE if FSM is started and not yet finished */ +/* Returns TRUE if FSM is started */ SilcBool silc_fsm_is_started(void *fsm) { SilcFSM f = fsm; - - if (f->started && !f->finished) - return TRUE; - - return FALSE; + return f->started; } /* Set context */ @@ -379,8 +388,6 @@ SilcBool silc_fsm_thread_wait(void *fsm, void *thread) SILC_ASSERT(t->thread); - if (t->finished) - return FALSE; t->u.t.sema = silc_fsm_sema_alloc(t->u.t.fsm, 0); if (!t->u.t.sema) return FALSE; diff --git a/lib/silcutil/silcfsm.h b/lib/silcutil/silcfsm.h index 2f27184e..48138567 100644 --- a/lib/silcutil/silcfsm.h +++ b/lib/silcutil/silcfsm.h @@ -117,6 +117,19 @@ typedef struct SilcFSMObject SilcFSMThreadStruct; * Status values that the FSM state functions return. They dicatate * how the machine will behave after returning from the state function. * + * The SILC_FSM_CONTINUE always moves to the next state synchronously. + * + * The SILC_FSM_YIELD always moves to the next state through the + * scheduler. Other threads will get running time with SILC_FSM_YIELD. + * When using real threads, using SILC_FSM_YIELD is usually unnecessary. + * + * The SILC_FSM_WAIT will suspend the machine until it is awaken. + * + * The SILC_FSM_FINISH finished the machine or thread and calls its + * destructor, if defined. If the machine is finished when it has + * running threads the machine will fatally fail. User must always + * finish the threads before finishing the machine. + * * SOURCE */ typedef enum { @@ -307,9 +320,7 @@ do { \ * * Macro used to wait for the `thread' to terminate. The machine or * thread will be suspended while it is waiting for the thread to - * terminate. If the thread to be waited has already terminated (but - * the context has not been freed yet), this will continue immediately - * to the following state without waiting. + * terminate. * * NOTES * @@ -327,9 +338,8 @@ do { \ ***/ #define SILC_FSM_THREAD_WAIT(thread) \ do { \ - if (silc_fsm_thread_wait(fsm, thread)) \ - return SILC_FSM_WAIT; \ - return SILC_FSM_CONTINUE; \ + silc_fsm_thread_wait(fsm, thread); \ + return SILC_FSM_WAIT; \ } while(0) /****f* silcutil/SilcFSMAPI/silc_fsm_alloc @@ -693,6 +703,10 @@ void silc_fsm_continue_sync(void *fsm); * possible this function may be called. This function is used with * both SilcFSM and SilcFSMThread contexts. * + * If the `fsm' is a machine and it has running threads, the machine + * will fatally fail. The caller must first finish the threads and + * then the machine. + * ***/ void silc_fsm_finish(void *fsm); diff --git a/lib/silcutil/tests/test_silcschedule.c b/lib/silcutil/tests/test_silcschedule.c index 19f94b2b..5a6824cc 100644 --- a/lib/silcutil/tests/test_silcschedule.c +++ b/lib/silcutil/tests/test_silcschedule.c @@ -95,7 +95,7 @@ int main(int argc, char **argv) silc_schedule_task_add_signal(schedule, SIGINT, interrupt, NULL); - silc_schedule_task_add_timeout(schedule, start, NULL, 0, 1); + silc_schedule_task_add_timeout(schedule, start, NULL, 1, 0); SILC_LOG_DEBUG(("Running scheduler")); silc_schedule(schedule); -- 2.43.0