{
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
/* 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 */
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;
}
/* 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 */
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 */
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;
* 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 {
*
* 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
*
***/
#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
* 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);