if (f->thread && f->u.t.event)
silc_fsm_event_free(f->u.t.event);
+ if (!f->thread)
+ silc_atomic_uninit32(&f->u.m.threads);
+
silc_free(f);
}
silc_fsm_start_real_thread(f->schedule,
silc_schedule_get_context(f->schedule),
0, 0, f);
+ silc_schedule_wakeup(f->schedule);
return;
}
SilcUInt32 seconds, SilcUInt32 useconds)
{
SilcFSM f = fsm;
+
f->next_state = next_state;
if (!seconds && !useconds)
return;
+
silc_schedule_task_add_timeout(f->schedule, silc_fsm_run, f,
seconds, useconds);
f->next_later = TRUE;
+
+ /* Wakeup up the scheduler just in case this was called from another
+ thread. */
+ silc_schedule_wakeup(f->schedule);
}
/* Continue after callback or async operation */
void silc_fsm_continue(void *fsm)
{
SilcFSM f = fsm;
+
if (f->next_later) {
+ /* Cancel next_later timeout */
silc_schedule_task_del_by_all(f->schedule, 0, silc_fsm_run, f);
f->next_later = FALSE;
}
+
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);
+
+ /* Wakeup up the scheduler just in case this was called from another
+ thread. */
+ silc_schedule_wakeup(f->schedule);
}
/* Continue after callback or async operation immediately */
SILC_ASSERT(!f->finished);
- /* Machine must not have active threads */
- if (!f->thread && silc_atomic_get_int32(&f->u.m.threads))
- assert(silc_atomic_get_int32(&f->u.m.threads) == 0);
-
f->started = FALSE;
f->finished = TRUE;
fsm->destructor(fsm, fsm->fsm_context, fsm->destructor_context);
} else {
+ /* Machine must not have active threads */
+ assert(silc_atomic_get_int32(&fsm->u.m.threads) == 0);
+
if (fsm->u.m.lock) {
silc_mutex_free(fsm->u.m.lock);
fsm->u.m.lock = NULL;
}
- silc_atomic_uninit32(&fsm->u.m.threads);
/* Call the destructor callback. */
if (fsm->destructor)
/* We allocate new SilcSchedule for the FSM, as the old SilcSchedule
cannot be used in this thread. Application may still use it if it
wants but we use our own. */
- fsm->schedule = silc_schedule_init(0, old);
- if (silc_unlikely(!fsm->schedule))
+ fsm->schedule = silc_schedule_init(0, old, silc_schedule_get_stack(old));
+ if (silc_unlikely(!fsm->schedule)) {
+ fsm->schedule = old;
return NULL;
+ }
/* Start the FSM thread */
if (silc_unlikely(!silc_schedule_task_add_timeout(fsm->schedule,
- silc_fsm_run, fsm, 0, 0)))
+ silc_fsm_run, fsm, 0, 0))) {
+ silc_schedule_uninit(fsm->schedule);
+ fsm->schedule = old;
return NULL;
+ }
/* Run the scheduler */
silc_schedule(fsm->schedule);