#include "silc.h"
SILC_TASK_CALLBACK(silc_fsm_run);
-SILC_TASK_CALLBACK(silc_fsm_finish);
-SILC_TASK_CALLBACK(silc_fsm_sema_timedout);
+SILC_TASK_CALLBACK(silc_fsm_finish_fsm);
+SILC_TASK_CALLBACK(silc_fsm_event_timedout);
SILC_TASK_CALLBACK(silc_fsm_start_real_thread);
-static void *silc_fsm_thread(void *context);
-static void silc_fsm_thread_termination_post(SilcFSMSema sema);
-static void silc_fsm_sema_ref(SilcFSMSema sema);
-static void silc_fsm_sema_unref(SilcFSMSema sema);
+static void silc_fsm_thread_termination_signal(SilcFSMEvent event);
+static void silc_fsm_event_ref(SilcFSMEvent event);
+static void silc_fsm_event_unref(SilcFSMEvent event);
+void *silc_fsm_thread(void *context);
/* Allocate FSM */
SilcFSM fsm;
fsm = silc_calloc(1, sizeof(*fsm));
- if (!fsm)
+ if (silc_unlikely(!fsm))
return NULL;
- if (!silc_fsm_init(fsm, fsm_context, destructor,
- destructor_context, schedule)) {
+ if (silc_unlikely(!silc_fsm_init(fsm, fsm_context, destructor,
+ destructor_context, schedule))) {
silc_free(fsm);
return NULL;
}
fsm->schedule = schedule;
fsm->thread = FALSE;
fsm->async_call = FALSE;
+ fsm->started = FALSE;
fsm->u.m.threads = 0;
fsm->u.m.lock = NULL;
SilcFSMThread thread;
thread = silc_calloc(1, sizeof(*thread));
- if (!thread)
+ if (silc_unlikely(!thread))
return NULL;
silc_fsm_thread_init(thread, fsm, thread_context, destructor,
SILC_LOG_DEBUG(("Initializing new thread %p (%s)",
thread, real_thread ? "real" : "FSM"));
-#if defined(SILC_DEBUG)
- assert(!fsm->thread);
-#endif /* SILC_DEBUG */
+ SILC_ASSERT(!fsm->thread);
thread->fsm_context = thread_context;
thread->state_context = NULL;
thread->schedule = fsm->schedule;
thread->thread = TRUE;
thread->async_call = FALSE;
+ thread->started = FALSE;
thread->real_thread = real_thread;
thread->u.t.fsm = fsm;
#if defined(SILC_DEBUG)
/* We must be finished */
- assert(f->finished);
+ SILC_ASSERT(f->finished);
/* Machine must not have active threads */
if (!f->thread && f->u.m.threads)
- assert(f->u.m.threads == 0);
+ SILC_ASSERT(f->u.m.threads == 0);
#endif /* SILC_DEBUG */
if (!f->thread && f->u.m.lock)
silc_mutex_free(f->u.m.lock);
- if (f->thread && f->u.t.sema)
- silc_fsm_sema_free(f->u.t.sema);
+ if (f->thread && f->u.t.event)
+ silc_fsm_event_free(f->u.t.event);
silc_free(f);
}
void silc_fsm_free(void *fsm)
{
SilcFSM f = fsm;
- silc_schedule_task_add_timeout(f->schedule, silc_fsm_free_final, f, 0, 1);
+ if (!f->thread)
+ 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
f->finished = FALSE;
f->next_state = start_state;
f->synchronous = FALSE;
+ f->started = TRUE;
/* 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, 1);
+ 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, 1);
+ 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 */
f->finished = FALSE;
f->next_state = start_state;
f->synchronous = TRUE;
+ f->started = TRUE;
/* Start real thread directly */
if (f->thread && f->real_thread) {
return;
silc_schedule_task_add_timeout(f->schedule, silc_fsm_run, f,
seconds, useconds);
+ f->next_later = TRUE;
}
/* Continue after callback or async operation */
void silc_fsm_continue(void *fsm)
{
SilcFSM f = fsm;
- silc_schedule_task_add_timeout(f->schedule, silc_fsm_run, f, 0, 1);
+ if (f->next_later) {
+ 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);
}
/* Continue after callback or async operation immediately */
void silc_fsm_continue_sync(void *fsm)
{
SilcFSM f = fsm;
+ if (f->next_later) {
+ silc_schedule_task_del_by_all(f->schedule, 0, silc_fsm_run, f);
+ f->next_later = FALSE;
+ }
silc_fsm_run(f->schedule, silc_schedule_get_context(f->schedule), 0, 0, f);
}
+/* Finish FSM */
+
+void silc_fsm_finish(void *fsm)
+{
+ SilcFSM f = fsm;
+
+ SILC_ASSERT(!f->finished);
+
+ /* 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;
+
+ /* If we are thread and using real threads, the FSM thread will finish
+ after the real thread has finished, in the main thread. */
+ if (f->thread && f->real_thread) {
+ /* Stop the real thread's scheduler to finish the thread */
+ silc_schedule_stop(f->schedule);
+ silc_schedule_wakeup(f->schedule);
+ return;
+ }
+
+ /* Normal FSM operation */
+ 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 */
SilcSchedule silc_fsm_get_schedule(void *fsm)
SilcFSM silc_fsm_get_machine(SilcFSMThread thread)
{
- assert(thread->thread);
+ SILC_ASSERT(thread->thread);
return (SilcFSM)thread->u.t.fsm;
}
+/* Returns TRUE if FSM is started */
+
+SilcBool silc_fsm_is_started(void *fsm)
+{
+ SilcFSM f = fsm;
+ return f->started;
+}
+
/* Set context */
void silc_fsm_set_context(void *fsm, void *fsm_context)
SilcBool silc_fsm_thread_wait(void *fsm, void *thread)
{
SilcFSM t = thread;
-#if defined(SILC_DEBUG)
- assert(t->thread);
-#endif /* SILC_DEBUG */
- t->u.t.sema = silc_fsm_sema_alloc(t->u.t.fsm, 0);
- if (!t->u.t.sema)
+
+ SILC_ASSERT(t->thread);
+
+ t->u.t.event = silc_fsm_event_alloc(t->u.t.fsm);
+ if (!t->u.t.event)
return FALSE;
- silc_fsm_sema_wait(t->u.t.sema, fsm);
+
+ SILC_LOG_DEBUG(("Waiting for thread %p to terminate", thread));
+ silc_fsm_event_wait(t->u.t.event, fsm);
return TRUE;
}
/* Run the states */
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_YIELD:
+ case SILC_FSM_ST_YIELD:
/* Continue through scheduler */
silc_fsm_continue(fsm);
break;
- case SILC_FSM_WAIT:
+ case SILC_FSM_ST_WAIT:
/* The machine is in hold */
SILC_LOG_DEBUG(("State wait %p", fsm));
fsm->synchronous = FALSE;
break;
- case SILC_FSM_FINISH:
+ case SILC_FSM_ST_FINISH:
/* Finish the state machine */
SILC_LOG_DEBUG(("State finish %p", fsm));
-#if defined(SILC_DEBUG)
- assert(!fsm->finished);
-#endif /* SILC_DEBUG */
- fsm->finished = TRUE;
-
- /* If we are thread and using real threads, the FSM thread will finish
- in the main thread, not in the created thread. */
- if (fsm->thread && fsm->real_thread) {
- silc_schedule_task_add_timeout(app_context, silc_fsm_finish, fsm, 0, 1);
- silc_schedule_wakeup(app_context);
- silc_schedule_stop(fsm->schedule);
- break;
- }
-
- /* Normal FSM operation */
- if (fsm->synchronous)
- silc_fsm_finish(fsm->schedule, app_context, 0, 0, fsm);
- else
- silc_schedule_task_add_timeout(fsm->schedule, silc_fsm_finish,
- fsm, 0, 1);
+ silc_fsm_finish(fsm);
break;
default:
/* Finishes the FSM. This is always executed in the main thread, even
for FSM threads that were run in real threads. */
-SILC_TASK_CALLBACK(silc_fsm_finish)
+SILC_TASK_CALLBACK(silc_fsm_finish_fsm)
{
SilcFSM fsm = context;
if (fsm->thread) {
/* This is thread, send signal */
- if (fsm->u.t.sema) {
- silc_fsm_thread_termination_post(fsm->u.t.sema);
- silc_fsm_sema_free(fsm->u.t.sema);
- fsm->u.t.sema = NULL;
+ if (fsm->u.t.event) {
+ silc_fsm_thread_termination_signal(fsm->u.t.event);
+ silc_fsm_event_free(fsm->u.t.event);
+ fsm->u.t.event = NULL;
}
/* Remove the thread from machine */
}
}
-/* Allocate FSM semaphore */
+/* Allocate FSM event */
-SilcFSMSema silc_fsm_sema_alloc(SilcFSM fsm, SilcUInt32 value)
+SilcFSMEvent silc_fsm_event_alloc(SilcFSM fsm)
{
- SilcFSMSema sema;
+ SilcFSMEvent event;
- sema = silc_calloc(1, sizeof(*sema));
- if (!sema)
+ event = silc_calloc(1, sizeof(*event));
+ if (silc_unlikely(!event))
return NULL;
- silc_fsm_sema_init(sema, fsm, value);
- sema->allocated = TRUE;
+ silc_fsm_event_init(event, fsm);
+ event->allocated = TRUE;
- return sema;
+ return event;
}
-/* Initializes FSM semaphore */
+/* Initializes FSM event */
-void silc_fsm_sema_init(SilcFSMSema sema, SilcFSM fsm, SilcUInt32 value)
+void silc_fsm_event_init(SilcFSMEvent event, SilcFSM fsm)
{
- SILC_LOG_DEBUG(("Initializing semaphore %p", sema));
-#if defined(SILC_DEBUG)
- assert(!fsm->thread);
-#endif /* SILC_DEBUG */
- memset(sema, 0, sizeof(*sema));
- sema->fsm = fsm;
- sema->refcnt = 0;
- silc_list_init(sema->waiters, struct SilcFSMObject, next);
- sema->value = value;
+ SILC_LOG_DEBUG(("Initializing event %p", event));
+ SILC_ASSERT(!fsm->thread);
+ memset(event, 0, sizeof(*event));
+ event->fsm = fsm;
+ event->refcnt = 0;
+ silc_list_init(event->waiters, struct SilcFSMObject, next);
}
-/* Free semaphore */
+/* Free event */
-void silc_fsm_sema_free(SilcFSMSema sema)
+void silc_fsm_event_free(SilcFSMEvent event)
{
- if (sema->refcnt > 0)
+ if (event->refcnt > 0)
return;
-#if defined(SILC_DEBUG)
- assert(silc_list_count(sema->waiters) == 0);
-#endif /* SILC_DEBUG */
- silc_free(sema);
+ if (silc_list_count(event->waiters) > 0)
+ return;
+ silc_free(event);
}
-/* Reference semaphore */
+/* Reference event */
-static void silc_fsm_sema_ref(SilcFSMSema sema)
+static void silc_fsm_event_ref(SilcFSMEvent event)
{
- sema->refcnt++;
+ event->refcnt++;
}
-/* Unreference semaphore */
+/* Unreference event */
-static void silc_fsm_sema_unref(SilcFSMSema sema)
+static void silc_fsm_event_unref(SilcFSMEvent event)
{
- sema->refcnt--;
- if (sema->refcnt == 0 && sema->allocated)
- silc_fsm_sema_free(sema);
+ event->refcnt--;
+ if (event->refcnt == 0 && event->allocated)
+ silc_fsm_event_free(event);
}
-/* Wait until semaphore is non-zero. */
+/* Wait until event is non-zero. */
-SilcUInt32 silc_fsm_sema_wait(SilcFSMSema sema, void *fsm)
+SilcUInt32 silc_fsm_event_wait(SilcFSMEvent event, void *fsm)
{
- SilcMutex lock = sema->fsm->u.m.lock;
+ SilcMutex lock = event->fsm->u.m.lock;
silc_mutex_lock(lock);
- if (!sema->value) {
+ if (!event->value) {
#if defined(SILC_DEBUG)
SilcFSM entry;
- silc_list_start(sema->waiters);
- while ((entry = silc_list_get(sema->waiters)) != SILC_LIST_END)
- assert(entry != fsm);
+ silc_list_start(event->waiters);
+ while ((entry = silc_list_get(event->waiters)))
+ SILC_ASSERT(entry != fsm);
#endif /* SILC_DEBUG */
- SILC_LOG_DEBUG(("Waiting for semaphore %p", sema));
+ SILC_LOG_DEBUG(("Waiting for event %p", event));
/* Add the FSM to waiter list */
- silc_list_add(sema->waiters, fsm);
+ silc_list_add(event->waiters, fsm);
silc_mutex_unlock(lock);
return 0;
}
- SILC_LOG_DEBUG(("Acquired semaphore %p", sema));
+ SILC_LOG_DEBUG(("Received event %p", event));
/* It is possible that this FSM is in the list so remove it */
- silc_list_del(sema->waiters, fsm);
- sema->value--;
+ silc_list_del(event->waiters, fsm);
+ event->value--;
silc_mutex_unlock(lock);
return 1;
}
-/* Wait util semaphore is non-zero, or timeout occurs. */
+/* Wait util event is non-zero, or timeout occurs. */
-SilcUInt32 silc_fsm_sema_timedwait(SilcFSMSema sema, void *fsm,
- SilcUInt32 seconds, SilcUInt32 useconds,
- SilcBool *ret_to)
+SilcUInt32 silc_fsm_event_timedwait(SilcFSMEvent event, void *fsm,
+ SilcUInt32 seconds, SilcUInt32 useconds,
+ SilcBool *ret_to)
{
- SilcMutex lock = sema->fsm->u.m.lock;
+ SilcMutex lock = event->fsm->u.m.lock;
SilcFSM f = fsm;
SilcUInt32 value;
silc_mutex_lock(lock);
- if (f->sema_timedout) {
- SILC_LOG_DEBUG(("Semaphore was timedout"));
- f->sema_timedout = FALSE;
+ if (f->event_timedout) {
+ SILC_LOG_DEBUG(("Event waiting timedout"));
+ f->event_timedout = FALSE;
if (ret_to)
*ret_to = TRUE;
silc_mutex_unlock(lock);
silc_mutex_unlock(lock);
- value = silc_fsm_sema_wait(sema, fsm);
+ value = silc_fsm_event_wait(event, fsm);
if (!value) {
- silc_schedule_task_add_timeout(f->schedule, silc_fsm_sema_timedout,
+ silc_schedule_task_add_timeout(f->schedule, silc_fsm_event_timedout,
f, seconds, useconds);
- f->sema = sema;
+ f->event = event;
}
if (ret_to)
return value;
}
-/* Semaphore timedout */
+/* Event timedout */
-SILC_TASK_CALLBACK(silc_fsm_sema_timedout)
+SILC_TASK_CALLBACK(silc_fsm_event_timedout)
{
SilcFSM fsm = context;
- SilcMutex lock = fsm->sema->fsm->u.m.lock;
+ SilcMutex lock = fsm->event->fsm->u.m.lock;
- SILC_LOG_DEBUG(("Semaphore %p timedout", fsm->sema));
+ SILC_LOG_DEBUG(("Event %p timedout", fsm->event));
- /* Remove the waiter from the semaphore */
+ /* Remove the waiter from the event waiters list */
silc_mutex_lock(lock);
- silc_list_del(fsm->sema->waiters, fsm);
+ silc_list_del(fsm->event->waiters, fsm);
/* Continue */
- if (fsm->sema) {
+ if (fsm->event) {
silc_fsm_continue(fsm);
- fsm->sema_timedout = TRUE;
- fsm->sema = NULL;
+ fsm->event_timedout = TRUE;
+ fsm->event = NULL;
}
silc_mutex_unlock(lock);
}
-/* Signalled, semaphore */
+/* Signalled, event */
SILC_TASK_CALLBACK(silc_fsm_signal)
{
- SilcFSMSemaPost p = context;
- SilcMutex lock = p->sema->fsm->u.m.lock;
+ SilcFSMEventSignal p = context;
+ SilcMutex lock = p->event->fsm->u.m.lock;
- /* If the semaphore value has went to zero while we've been waiting this
- callback, sempahore has been been signalled already. It can happen
- when using real threads because the FSM may not be waiting state when
- the sempahore is posted. */
+ /* 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
+ when using real threads because the FSM may not be in waiting state
+ when the sempahore is posted. */
silc_mutex_lock(lock);
- if (!p->sema->value) {
+ if (!p->event->value) {
silc_mutex_unlock(lock);
- silc_fsm_sema_unref(p->sema);
+ silc_fsm_event_unref(p->event);
silc_free(p);
return;
}
/* Signal */
silc_fsm_continue_sync(p->fsm);
- silc_fsm_sema_unref(p->sema);
+ silc_fsm_event_unref(p->event);
silc_free(p);
}
-/* Increase semaphore */
+/* Signal event */
-void silc_fsm_sema_post(SilcFSMSema sema)
+void silc_fsm_event_signal(SilcFSMEvent event)
{
SilcFSM fsm;
- SilcFSMSemaPost p;
- SilcMutex lock = sema->fsm->u.m.lock;
+ SilcFSMEventSignal p;
+ SilcMutex lock = event->fsm->u.m.lock;
- SILC_LOG_DEBUG(("Posting semaphore %p", sema));
+ SILC_LOG_DEBUG(("Signal event %p", event));
silc_mutex_lock(lock);
- sema->value++;
- silc_list_start(sema->waiters);
- while ((fsm = silc_list_get(sema->waiters)) != SILC_LIST_END) {
- if (fsm->sema) {
- silc_schedule_task_del_by_all(fsm->schedule, 0, silc_fsm_sema_timedout,
+ event->value++;
+ silc_list_start(event->waiters);
+ while ((fsm = silc_list_get(event->waiters)) != SILC_LIST_END) {
+ if (fsm->event) {
+ silc_schedule_task_del_by_all(fsm->schedule, 0, silc_fsm_event_timedout,
fsm);
- fsm->sema = NULL;
+ fsm->event = NULL;
}
p = silc_calloc(1, sizeof(*p));
- if (!p)
+ if (silc_unlikely(!p))
continue;
- p->sema = sema;
+ p->event = event;
p->fsm = fsm;
- silc_fsm_sema_ref(sema);
+ silc_fsm_event_ref(event);
/* Signal through scheduler. Wake up destination scheduler in case
caller is a real thread. */
- silc_schedule_task_add_timeout(fsm->schedule, silc_fsm_signal, p, 0, 1);
+ silc_schedule_task_add_timeout(fsm->schedule, silc_fsm_signal, p, 0, 0);
silc_schedule_wakeup(fsm->schedule);
}
silc_mutex_unlock(lock);
}
-/* Post thread termination semaphore. Special function used only to
+/* Post thread termination event. Special function used only to
signal thread termination when SILC_FSM_THREAD_WAIT was used. */
-static void silc_fsm_thread_termination_post(SilcFSMSema sema)
+static void silc_fsm_thread_termination_signal(SilcFSMEvent event)
{
SilcFSM fsm;
- SilcMutex lock = sema->fsm->u.m.lock;
+ SilcMutex lock = event->fsm->u.m.lock;
- SILC_LOG_DEBUG(("Post thread termination semaphore %p", sema));
+ SILC_LOG_DEBUG(("Post thread terminate event %p", event));
silc_mutex_lock(lock);
- silc_list_start(sema->waiters);
- while ((fsm = silc_list_get(sema->waiters)) != SILC_LIST_END) {
+ silc_list_start(event->waiters);
+ while ((fsm = silc_list_get(event->waiters)) != SILC_LIST_END) {
/* Signal on thread termination. Wake up destination scheduler in case
caller is a real thread. */
- silc_list_del(sema->waiters, fsm);
+ silc_list_del(event->waiters, fsm);
silc_fsm_continue(fsm);
silc_schedule_wakeup(fsm->schedule);
}
/* Real thread */
-static void *silc_fsm_thread(void *context)
+void *silc_fsm_thread(void *context)
{
SilcFSM fsm = context;
SilcSchedule old = fsm->schedule;
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 (!fsm->schedule)
+ if (silc_unlikely(!fsm->schedule))
return NULL;
/* Start the FSM thread */
- if (!silc_schedule_task_add_timeout(fsm->schedule, silc_fsm_run, fsm, 0, 1))
+ if (silc_unlikely(!silc_schedule_task_add_timeout(fsm->schedule,
+ silc_fsm_run, fsm, 0, 0)))
return NULL;
/* Run the scheduler */
fsm->schedule = old;
+ /* Finish the FSM thread in the main thread */
+ SILC_ASSERT(fsm->finished);
+ silc_schedule_task_add_timeout(fsm->schedule, silc_fsm_finish_fsm,
+ fsm, 0, 0);
+ silc_schedule_wakeup(fsm->schedule);
+
return NULL;
}