Author: Pekka Riikonen <priikone@silcnet.org>
- Copyright (C) 2005 - 2006 Pekka Riikonen
+ Copyright (C) 2005 - 2007 Pekka Riikonen
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
fsm->thread = FALSE;
fsm->async_call = FALSE;
fsm->started = FALSE;
- fsm->u.m.threads = 0;
fsm->u.m.lock = NULL;
+ silc_atomic_init32(&fsm->u.m.threads, 0);
return TRUE;
}
thread->u.t.fsm = fsm;
/* Add to machine */
- fsm->u.m.threads++;
+ silc_atomic_add_int32(&fsm->u.m.threads, 1);
/* Allocate lock for the machine if using real threads. */
if (real_thread && !fsm->u.m.lock)
SILC_ASSERT(f->finished);
/* Machine must not have active threads */
- if (!f->thread && f->u.m.threads)
- SILC_ASSERT(f->u.m.threads == 0);
+ if (!f->thread && silc_atomic_get_int32(&f->u.m.threads))
+ SILC_ASSERT(silc_atomic_get_int32(&f->u.m.threads) == 0);
#endif /* SILC_DEBUG */
if (!f->thread && f->u.m.lock)
/* Normal FSM operation */
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 scheduler in case we are starting this thread from another
+ real thread. */
+ if (f->thread)
+ silc_schedule_wakeup(f->schedule);
}
/* Start FSM in the specified state synchronously */
SILC_ASSERT(!f->finished);
/* Machine must not have active threads */
- if (!f->thread && f->u.m.threads)
- assert(f->u.m.threads == 0);
+ 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;
SILC_LOG_DEBUG(("Running %s %p", fsm->thread ? "thread" : "FSM", fsm));
/* Run the states */
-// do
+ do
status = fsm->next_state(fsm, fsm->fsm_context, fsm->state_context);
-// while (status == SILC_FSM_CONTINUE);
+ while (status == SILC_FSM_ST_CONTINUE);
switch (status) {
case SILC_FSM_ST_YIELD:
}
/* Remove the thread from machine */
- fsm->u.t.fsm->u.m.threads--;
+ silc_atomic_sub_int32(&fsm->u.t.fsm->u.m.threads, 1);
/* Call the destructor callback only if the underlaying machine is
still valid. */
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)
{
SilcFSMEventSignal p = context;
SilcMutex lock = p->event->fsm->u.m.lock;
+ SilcFSM fsm;
+
+ /* We have to check couple of things before delivering the signal. */
/* If the event value has went to zero while we've been waiting this
callback, the event has been been signalled already. It can happen
silc_free(p);
return;
}
+
+ /* If the waiter is not waiting anymore, don't deliver the signal */
+ silc_list_start(p->event->waiters);
+ while ((fsm = silc_list_get(p->event->waiters)))
+ if (fsm == p->fsm)
+ break;
+ if (!fsm) {
+ silc_mutex_unlock(lock);
+ silc_fsm_event_unref(p->event);
+ silc_free(p);
+ return;
+ }
silc_mutex_unlock(lock);
SILC_LOG_DEBUG(("Signalled %s %p", p->fsm->thread ? "thread" : "FSM",
silc_mutex_lock(lock);
silc_list_start(event->waiters);
- while ((fsm = silc_list_get(event->waiters)) != SILC_LIST_END) {
+ while ((fsm = silc_list_get(event->waiters))) {
/* Signal on thread termination. Wake up destination scheduler in case
caller is a real thread. */
silc_list_del(event->waiters, fsm);