Changed state move return values to macros: SILC_FSM_CONTINUE,
authorPekka Riikonen <priikone@silcnet.org>
Sat, 23 Dec 2006 17:55:59 +0000 (17:55 +0000)
committerPekka Riikonen <priikone@silcnet.org>
Sat, 23 Dec 2006 17:55:59 +0000 (17:55 +0000)
SILC_FSM_YIELD, SILC_FSM_WAIT and SILC_FSM_FINISH macros.
Changed FSM semaphores to FSM events.

lib/silcutil/silcfsm.c
lib/silcutil/silcfsm.h
lib/silcutil/silcfsm_i.h

index 47c9b51f8357949c8d01829af97df36f9a0c2af4..9ba6466f3f5577db8d7f90fa8f8a55a687c89638 100644 (file)
 
 SILC_TASK_CALLBACK(silc_fsm_run);
 SILC_TASK_CALLBACK(silc_fsm_finish_fsm);
-SILC_TASK_CALLBACK(silc_fsm_sema_timedout);
+SILC_TASK_CALLBACK(silc_fsm_event_timedout);
 SILC_TASK_CALLBACK(silc_fsm_start_real_thread);
-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 */
@@ -148,8 +148,8 @@ SILC_TASK_CALLBACK(silc_fsm_free_final)
   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);
 }
@@ -388,12 +388,12 @@ SilcBool silc_fsm_thread_wait(void *fsm, void *thread)
 
   SILC_ASSERT(t->thread);
 
-  t->u.t.sema = silc_fsm_sema_alloc(t->u.t.fsm, 0);
-  if (!t->u.t.sema)
+  t->u.t.event = silc_fsm_event_alloc(t->u.t.fsm);
+  if (!t->u.t.event)
     return FALSE;
 
   SILC_LOG_DEBUG(("Waiting for thread %p to terminate", thread));
-  silc_fsm_sema_wait(t->u.t.sema, fsm);
+  silc_fsm_event_wait(t->u.t.event, fsm);
   return TRUE;
 }
 
@@ -407,23 +407,23 @@ SILC_TASK_CALLBACK(silc_fsm_run)
   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_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));
     silc_fsm_finish(fsm);
@@ -447,10 +447,10 @@ SILC_TASK_CALLBACK(silc_fsm_finish_fsm)
 
   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 */
@@ -473,110 +473,109 @@ SILC_TASK_CALLBACK(silc_fsm_finish_fsm)
   }
 }
 
-/* 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 (silc_unlikely(!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));
+  SILC_LOG_DEBUG(("Initializing event %p", event));
   SILC_ASSERT(!fsm->thread);
-  memset(sema, 0, sizeof(*sema));
-  sema->fsm = fsm;
-  sema->refcnt = 0;
-  silc_list_init(sema->waiters, struct SilcFSMObject, next);
-  sema->value = value;
+  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 (silc_list_count(sema->waiters) > 0)
+  if (silc_list_count(event->waiters) > 0)
     return;
-  silc_free(sema);
+  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)
+    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);
@@ -585,11 +584,11 @@ SilcUInt32 silc_fsm_sema_timedwait(SilcFSMSema sema, void *fsm,
 
   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)
@@ -598,44 +597,44 @@ SilcUInt32 silc_fsm_sema_timedwait(SilcFSMSema sema, void *fsm,
   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;
   }
@@ -647,37 +646,37 @@ SILC_TASK_CALLBACK(silc_fsm_signal)
   /* 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 (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. */
@@ -688,23 +687,23 @@ void silc_fsm_sema_post(SilcFSMSema sema)
   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 terminate 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);
   }
index 481385675798d64dabacb0428b5e6d6afa4ce9fd..8a28360b5d3c1cfe8ff4a4322a33875bac22af04 100644 (file)
  *
  * SILC FSM Interface implements a finite state machine.  The FSM can be
  * used to implement all kinds of machines and protocols.  The FSM supports
- * also threads and can be synchronized by using FSM semaphores.  The FSM
+ * also threads and can be synchronized by using mutex locks.  The FSM
  * also supports real system threads.  It is possible to create new FSM
  * thread and then execute in real system thread, if platform supports
  * threads.
  *
- * The FSM provides semaphores because of their versatility.  The FSM
- * semaphores can be used as mutual exclusion locks to protect critical
- * sections, and as conditional variables and signallers.  The FSM
- * semaphores can safely be used to synchronize also FSM threads that are
- * executed in real system threads.  This makes SILC FSM very effective
- * tool to implement complex machines whether they are executed in single
- * thread or in multiple threads.
+ * The FSM provides also asynchronous events that can be used to wait for
+ * some events or states to occur.  The FSM events may be used as condition
+ * variables and signallers.  The FSM events can safely be used in FSM
+ * threads that are executed in real system threads.
+ *
+ * To synchronize machines that use FSM threads that are executed in real
+ * system threads the SILC Mutex API (silcmutex.h) may be used.  Normal
+ * multi-threaded coding conventions apply when programming with real FSM
+ * threads.  If the FSM threads are not real system threads, synchronization
+ * is not required.
  *
  ***/
 
@@ -106,40 +109,80 @@ typedef struct SilcFSMObject *SilcFSMThread;
  ***/
 typedef struct SilcFSMObject SilcFSMThreadStruct;
 
-/****d* silcutil/SilcFSMAPI/SilcFSMStatus
+/****d* silcutil/SilcFSMAPI/SILC_FSM_CONTINUE
  *
  * NAME
  *
- *    typedef enum { ... } SilcFSMStatus;
+ *    SILC_FSM_CONTINUE
  *
  * DESCRIPTION
  *
- *    Status values that the FSM state functions return.  They dicatate
- *    how the machine will behave after returning from the state function.
+ *    Moves to next state synchronously.  This macro is used in state
+ *    functions to immediately move to next state.  The state function
+ *    returns in this macro.  The macro has no arguments.
+ *
+ * EXAMPLE
+ *
+ *    SILC_FSM_STATE(silc_foo_state)
+ *    {
+ *      ...
+ *
+ *      // Move to next state now
+ *      silc_fsm_next(fsm, silc_foo_next_state);
+ *      SILC_FSM_CONTINUE;
+ *    }
+ *
+ ***/
+#define SILC_FSM_CONTINUE \
+  return fsm->next_state(fsm, fsm->fsm_context, fsm->state_context);
+
+/****d* silcutil/SilcFSMAPI/SILC_FSM_YIELD
+ *
+ * NAME
+ *
+ *    SILC_FSM_YIELD
  *
- *    The SILC_FSM_CONTINUE always moves to the next state synchronously.
+ * DESCRIPTION
  *
- *    The SILC_FSM_YIELD always moves to the next state through the
- *    scheduler.  Other threads will get running time with SILC_FSM_YIELD.
+ *    Moves to next state through the machine scheduler.  Other threads
+ *    running in the machine will get running time with SILC_FSM_YIELD.
  *    When using real threads, using SILC_FSM_YIELD is usually unnecessary.
+ *    The state function returns in this macro.  The macro has no arguments.
+ *
+ ***/
+#define SILC_FSM_YIELD return SILC_FSM_ST_YIELD;
+
+/****d* silcutil/SilcFSMAPI/SILC_FSM_WAIT
  *
- *    The SILC_FSM_WAIT will suspend the machine until it is awaken.
+ * NAME
  *
- *    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.
+ *    SILC_FSM_WAIT
  *
- * SOURCE
- */
-typedef enum {
-  SILC_FSM_CONTINUE,        /* Continue immediately to next state */
-  SILC_FSM_YIELD,           /* Continue to next state through scheduler */
-  SILC_FSM_WAIT,            /* Wait for some async call or timeout */
-  SILC_FSM_FINISH,          /* Finish state machine and call destructor
-                               through scheduler */
-} SilcFSMStatus;
-/***/
+ * DESCRIPTION
+ *
+ *    Suspends the machine or thread until it is awaken.  This is used
+ *    when asynchronous call is made or timer is set, or something else
+ *    that requires waiting.  The state function returns in this macro.
+ *    The macro has no arguments.
+ *
+ ***/
+#define SILC_FSM_WAIT return SILC_FSM_ST_WAIT
+
+/****d* silcutil/SilcFSMAPI/SILC_FSM_FINISH
+ *
+ * NAME
+ *
+ *    SILC_FSM_FINISH
+ *
+ * DESCRIPTION
+ *
+ *    Finishes 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.  The macro has no arguments.
+ *
+ ***/
+#define SILC_FSM_FINISH return SILC_FSM_ST_FINISH
 
 /****f* silcutil/SilcFSMAPI/SilcFSMDestructor
  *
@@ -152,10 +195,10 @@ typedef enum {
  *
  *    The destructor callback that was set in silc_fsm_alloc or in
  *    silc_fsm_init function.  It will be called when a state function
- *    returns SILC_FSM_FINISH.  This function will be called through
+ *    calls SILC_FSM_FINISH.  This function will be called through
  *    the scheduler; it will not be called immediately after the state
- *    function returns SILC_FSM_FINISH, but will be called later.
- *    The `fsm' may be freed in this function.
+ *    function calls SILC_FSM_FINISH, but will be called later.  The `fsm'
+ *    may be freed in this function.
  *
  ***/
 typedef void (*SilcFSMDestructor)(SilcFSM fsm, void *fsm_context,
@@ -173,10 +216,10 @@ typedef void (*SilcFSMDestructor)(SilcFSM fsm, void *fsm_context,
  *
  *    The destructor callback that was set in silc_fsm_thread_alloc or in
  *    silc_fsm_thread_init function.  It will be called when a state function
- *    returns SILC_FSM_FINISH.  This function will be called through
- *    the scheduler; it will not be called immediately after the state
- *    function returns SILC_FSM_FINISH, but will be called later.  The
- *    `thread' may be freed in this function.
+ *    calls SILC_FSM_FINISH.  This function will be called through the
+ *    scheduler; it will not be called immediately after the state function
+ *    calls SILC_FSM_FINISH, but will be called later.  The `thread' may
+ *    be freed in this function.
  *
  * NOTES
  *
@@ -197,7 +240,7 @@ typedef void (*SilcFSMThreadDestructor)(SilcFSMThread thread,
  *
  * DESCRIPTION
  *
- *    This macro is used to declare a FSM state function.  The `fsm' is
+ *    This macro is used to declare an FSM state function.  The `fsm' is
  *    the SilcFSM or SilcFSMThread context, the `fsm_context' is the context
  *    given as argument to silc_fsm_alloc, silc_fsm_init, silc_fsm_thread_init,
  *    or silc_fsm_thread_alloc function.  The `state_context' is the optional
@@ -206,14 +249,13 @@ typedef void (*SilcFSMThreadDestructor)(SilcFSMThread thread,
  * SOURCE
  */
 #define SILC_FSM_STATE(name)                                           \
-SilcFSMStatus name(struct SilcFSMObject *fsm, void *fsm_context,       \
-                  void *state_context)
+int name(struct SilcFSMObject *fsm, void *fsm_context, void *state_context)
 /***/
 
 /* State function callback */
-typedef SilcFSMStatus (*SilcFSMStateCallback)(struct SilcFSMObject *fsm,
-                                             void *fsm_context,
-                                             void *state_context);
+typedef int (*SilcFSMStateCallback)(struct SilcFSMObject *fsm,
+                                   void *fsm_context,
+                                   void *state_context);
 
 /****d* silcutil/SilcFSMAPI/SILC_FSM_CALL
  *
@@ -250,8 +292,8 @@ do {                                                \
   assert(!silc_fsm_set_call(fsm, TRUE));       \
   function;                                    \
   if (!silc_fsm_set_call(fsm, FALSE))          \
-    return SILC_FSM_CONTINUE;                  \
-  return SILC_FSM_WAIT;                                \
+    SILC_FSM_CONTINUE;                         \
+  SILC_FSM_WAIT;                               \
 } while(0)
 
 /****d* silcutil/SilcFSMAPI/SILC_FSM_CALL_CONTINUE
@@ -328,7 +370,7 @@ do {                                                \
  *
  *    This macro is the only way to safely make sure that the thread has
  *    terminated by the time FSM continues from the waiting state.  Using
- *    semaphores to signal from the thread before SILC_FSM_FINISH is returned
+ *    FSM events to signal from the thread before SILC_FSM_FINISH is called
  *    works with normal FSM threads, but especially with real system threads
  *    it does not guarantee that the FSM won't continue before the thread has
  *    actually terminated.  Usually this is not a problem, but it can be a
@@ -339,7 +381,7 @@ do {                                                \
 #define SILC_FSM_THREAD_WAIT(thread)           \
 do {                                           \
   silc_fsm_thread_wait(fsm, thread);           \
-  return SILC_FSM_WAIT;                                \
+  SILC_FSM_WAIT;                               \
 } while(0)
 
 /****f* silcutil/SilcFSMAPI/silc_fsm_alloc
@@ -440,29 +482,17 @@ SilcBool silc_fsm_init(SilcFSM fsm,
  *
  * NOTES
  *
- *    Note the limitations on using `real_thread' boolean to indicate running
- *    the FSM thread in a real system thread:
- *
  *    If the system does not support threads, then this function will revert
  *    back to normal FSM threads.
  *
  *    If the `real_thread' is TRUE then FSM will allocate new SilcSchedule
- *    for the FSM thread.  This is done because the SilcSchedule that the
- *    `fsm' use cannot be used in the thread.  This is limitation in the
- *    SilcSchedule implementation.  If you need scheduler in the real thread
- *    it is strongly recommended that you use the SilcSchedule that is
- *    allocated for the thread.  You can retrieve the SilcSchedule from the
- *    thread using silc_fsm_get_schedule function.  Note that, the allocated
+ *    for the FSM thread. If you need scheduler in the real thread it is
+ *    strongly recommended that you use the SilcSchedule that is allocated
+ *    for the thread.  You can retrieve the SilcSchedule from the thread
+ *    using silc_fsm_get_schedule function.  Note that, the allocated
  *    SilcSchedule will become invalid after the thread finishes.
  *
- *    You may still however use the original SilcSchedule if you wish.  In
- *    this case note its limitation: you may only add and/or remove tasks,
- *    tasks cannot be executed in the thread.  You will need to deliver the
- *    original SilcSchedule to the thread in the `thread_context' if you wish
- *    to use it.
- *
- *    If `real_thread' is FALSE then no limitations on what can be run in
- *    the thread exist.  In this case silc_fsm_get_schedule will return
+ *    If `real_thread' is FALSE the silc_fsm_get_schedule will return
  *    the SilcSchedule that was originally given to silc_fsm_alloc or
  *    silc_fsm_init.
  *
@@ -602,8 +632,8 @@ void silc_fsm_start_sync(void *fsm, SilcFSMStateCallback start_state);
  * DESCRIPTION
  *
  *    Set the next state to be executed.  If the state function that
- *    call this function returns SILC_FSM_CONTINUE, the `next_state'
- *    will be executed immediately.  If it returns SILC_FSM_YIELD it
+ *    call this function calls SILC_FSM_CONTINUE, the `next_state'
+ *    will be executed immediately.  If it calls SILC_FSM_YIELD it
  *    yields the thread and the `next_state' will be run after other
  *    threads have run first.  This function must always be used to set
  *    the next state in the machine or thread.  This function is used
@@ -613,7 +643,7 @@ void silc_fsm_start_sync(void *fsm, SilcFSMStateCallback start_state);
  *
  *    // Move to next state
  *    silc_fsm_next(fsm, next_state);
- *    return SILC_FSM_CONTINUE;
+ *    SILC_FSM_CONTINUE;
  *
  ***/
 void silc_fsm_next(void *fsm, SilcFSMStateCallback next_state);
@@ -628,7 +658,7 @@ void silc_fsm_next(void *fsm, SilcFSMStateCallback next_state);
  * DESCRIPTION
  *
  *    Set the next state to be executed later, at the specified time.
- *    The SILC_FSM_WAIT must be returned in the state function if this
+ *    The SILC_FSM_WAIT must be called in the state function if this
  *    function is called.  If any other state is returned machine operation
  *    is undefined.  The machine or thread will move to `next_state' after
  *    the specified timeout.  This function is used with both SilcFSM and
@@ -637,7 +667,7 @@ void silc_fsm_next(void *fsm, SilcFSMStateCallback next_state);
  * NOTES
  *
  *    If both `seconds' and `useconds' are 0, the effect is same as calling
- *    silc_fsm_next function, and SILC_FSM_CONTINUE must be returned.
+ *    silc_fsm_next function, and SILC_FSM_CONTINUE must be called.
  *
  *    If silc_fsm_continue or silc_fsm_continue_sync is called while the
  *    machine or thread is in SILC_FSM_WAIT state the timeout is automatically
@@ -647,7 +677,7 @@ void silc_fsm_next(void *fsm, SilcFSMStateCallback next_state);
  *
  *    // Move to next state after 10 seconds
  *    silc_fsm_next_later(fsm, next_state, 10, 0);
- *    return SILC_FSM_WAIT;
+ *    SILC_FSM_WAIT;
  *
  ***/
 void silc_fsm_next_later(void *fsm, SilcFSMStateCallback next_state,
@@ -699,7 +729,7 @@ void silc_fsm_continue_sync(void *fsm);
  *
  *    Finishes the `fsm'.  This function may be used in case the FSM
  *    needs to be finished outside FSM states.  Usually FSM is finished
- *    by returning SILC_FSM_FINISH from the state, but if this is not
+ *    by calling SILC_FSM_FINISH from the state, but if this is not
  *    possible this function may be called.  This function is used with
  *    both SilcFSM and SilcFSMThread contexts.
  *
@@ -826,110 +856,107 @@ SilcFSM silc_fsm_get_machine(SilcFSMThread thread);
  ***/
 SilcBool silc_fsm_is_started(void *fsm);
 
-/* FSM Semaphores */
+/* FSM Events */
 
-/****s* silcutil/SilcFSMAPI/SilcFSMSema
+/****s* silcutil/SilcFSMAPI/SilcFSMEvent
  *
  * NAME
  *
- *    typedef struct SilcFSMSemaObject *SilcFSMSema;
+ *    typedef struct SilcFSMEventObject *SilcFSMEvent;
  *
  * DESCRIPTION
  *
- *    The FSM semaphore context allocated with silc_fsm_sema_alloc.  The
- *    caller must free it with silc_fsm_sema_free.  It is also possible
- *    to use pre-allocated SilcFSMSemaStruct instead of SilcFSMSema context.
+ *    The FSM event context allocated with silc_fsm_event_alloc.  The
+ *    caller must free it with silc_fsm_event_free.  It is also possible
+ *    to use pre-allocated SilcFSMEventStruct instead of SilcFSMEvent context.
  *
  ***/
-typedef struct SilcFSMSemaObject *SilcFSMSema;
+typedef struct SilcFSMEventObject *SilcFSMEvent;
 
-/****s* silcutil/SilcFSMAPI/SilcFSMSemaStruct
+/****s* silcutil/SilcFSMAPI/SilcFSMEventStruct
  *
  * NAME
  *
- *    typedef struct SilcFSMSemaObject SilcFSMSemaStruct;
+ *    typedef struct SilcFSMEventObject SilcFSMEventStruct;
  *
  * DESCRIPTION
  *
- *    The FSM semaphore context that can be used as pre-allocated context.
- *    It is initialized with silc_fsm_sema_init.  It need not be
+ *    The FSM event context that can be used as pre-allocated context.
+ *    It is initialized with silc_fsm_event_init.  It need not be
  *    uninitialized.
  *
  ***/
-typedef struct SilcFSMSemaObject SilcFSMSemaStruct;
+typedef struct SilcFSMEventObject SilcFSMEventStruct;
 
-/****f* silcutil/SilcFSMAPI/silc_fsm_sema_alloc
+/****f* silcutil/SilcFSMAPI/silc_fsm_event_alloc
  *
  * SYNOPSIS
  *
- *    SilcFSMSema silc_fsm_sema_alloc(SilcFSM fsm, SilcUInt32 value);
+ *    SilcFSMEvent silc_fsm_event_alloc(SilcFSM fsm);
  *
  * DESCRIPTION
  *
- *    Allocates FSM semaphore with initial value of `value'.  Semaphores are
- *    counters for resources shared between machine and threads.  Semaphores
- *    can be waited until the semaphore value is non-zero.  The FSM will be
- *    suspended when waiting for semaphore.  When the semaphore is incremented
- *    all that are waiting for the semaphore will be signalled and awaken.
+ *    Allocates asynchronous FSM event.  FSM events are asynchronous events
+ *    that can be waited and signalled.  They can be used as condition
+ *    variables and signallers.  They can be used for example to wait that
+ *    some event happens, some thread moves to a specific state or similar.
+ *    The FSM Events may also be used in FSM threads that are executed in
+ *    real system threads.  It is safe to wait and signal the event from
+ *    threads.
  *
- *    Semaphores can be used to wait for example when thread terminates, or
- *    when thread moves into a specific state, or to protect critical
- *    sections.  The FSM semaphores can be used also in FSM threads that are
- *    executed in real system threads.
- *
- *    Use the macros SILC_FSM_SEMA_WAIT and SILC_FSM_SEMA_TIMEDWAIT to wait
- *    for semaphore.  Use the SILC_FSM_SEMA_POST macro to increment the
- *    counter and wake up all waiters.
+ *    Use the macros SILC_FSM_EVENT_WAIT and SILC_FSM_EVENT_TIMEDWAIT to wait
+ *    for the event.  Use the SILC_FSM_EVENT_SIGNAL macro to signal all the
+ *    waiters.
  *
  ***/
-SilcFSMSema silc_fsm_sema_alloc(SilcFSM fsm, SilcUInt32 value);
+SilcFSMEvent silc_fsm_event_alloc(SilcFSM fsm);
 
-/****f* silcutil/SilcFSMAPI/silc_fsm_sema_init
+/****f* silcutil/SilcFSMAPI/silc_fsm_event_init
  *
  * SYNOPSIS
  *
- *    void silc_fsm_sema_init(SilcFSMSema sema, SilcFSM fsm, SilcUInt32 value);
+ *    void silc_fsm_event_init(SilcFSMEvent event, SilcFSM fsm);
  *
  * DESCRIPTION
  *
- *    Initializes a pre-allocates semaphore context.  This call is
- *    equivalent to silc_fsm_sema_alloc except this use the pre-allocated
+ *    Initializes a pre-allocates FSM event context.  This call is
+ *    equivalent to silc_fsm_event_alloc except this use the pre-allocated
  *    context.  This fuction does not allocate any memory.
  *
  ***/
-void silc_fsm_sema_init(SilcFSMSema sema, SilcFSM fsm, SilcUInt32 value);
+void silc_fsm_event_init(SilcFSMEvent event, SilcFSM fsm);
 
-/****f* silcutil/SilcFSMAPI/silc_fsm_sema_free
+/****f* silcutil/SilcFSMAPI/silc_fsm_event_free
  *
  * SYNOPSIS
  *
- *    void silc_fsm_sema_free(SilcFSMSema sema);
+ *    void silc_fsm_event_free(SilcFSMEvent event);
  *
  * DESCRIPTION
  *
- *    Free the semaphore allocated by silc_fsm_sema_alloc function.
+ *    Free the event allocated by silc_fsm_event_alloc function.
  *
  ***/
-void silc_fsm_sema_free(SilcFSMSema sema);
+void silc_fsm_event_free(SilcFSMEvent event);
 
-/****d* silcutil/SilcFSMAPI/SILC_FSM_SEMA_WAIT
+/****d* silcutil/SilcFSMAPI/SILC_FSM_EVENT_WAIT
  *
  * NAME
  *
- *    SILC_FSM_SEMA_WAIT(semaphore)
+ *    SILC_FSM_EVENT_WAIT(event)
  *
  * DESCRIPTION
  *
- *    Macro used to wait for the `semaphore' to become non-zero.  The
- *    machine will be suspended while it is waiting for the semaphore.
+ *    Macro used to wait for the `event' to be signalled.  The machine
+ *    or thread will be suspended while it is waiting for the event.
  *    This macro can only be used in FSM state functions.  When the
- *    semaphore is signalled the FSM will re-enter the current state (or
+ *    event is signalled the FSM will re-enter the current state (or
  *    state that was set with silc_fsm_next before waiting).
  *
  * EXAMPLE
  *
  *    // Signalling example
- *    ctx->async_sema = silc_fsm_sema_alloc(fsm, 0);
+ *    ctx->async_event = silc_fsm_event_alloc(fsm);
  *    ...
  *
  *    SILC_FSM_STATE(silc_foo_state)
@@ -937,7 +964,7 @@ void silc_fsm_sema_free(SilcFSMSema sema);
  *      ...
  *
  *      // Wait here for async call to complete
- *      SILC_FSM_SEMA_WAIT(ctx->async_sema);
+ *      SILC_FSM_EVENT_WAIT(ctx->async_event);
  *
  *      // Async call completed
  *      if (ctx->async_success == FALSE)
@@ -945,41 +972,28 @@ void silc_fsm_sema_free(SilcFSMSema sema);
  *      ...
  *    }
  *
- *    // Mutual exclusion example
- *    ctx->lock = silc_fsm_sema_alloc(fsm, 1);
- *    ...
- *
- *    SILC_FSM_STATE(silc_foo_state)
- *    {
- *      ...
- *      SILC_FSM_SEMA_WAIT(ctx->lock);
- *      very critical stuff...
- *      SILC_FSM_SEMA_POST(ctx->lock);
- *      ...
- *    }
- *
  ***/
-#define SILC_FSM_SEMA_WAIT(sema)               \
+#define SILC_FSM_EVENT_WAIT(event)             \
 do {                                           \
-  if (silc_fsm_sema_wait(sema, fsm) == 0)      \
-    return SILC_FSM_WAIT;                      \
+  if (silc_fsm_event_wait(event, fsm) == 0)    \
+    SILC_FSM_WAIT;                             \
 } while(0)
 
-/****d* silcutil/SilcFSMAPI/SILC_FSM_SEMA_TIMEDWAIT
+/****d* silcutil/SilcFSMAPI/SILC_FSM_EVENT_TIMEDWAIT
  *
  * NAME
  *
- *    SILC_FSM_SEMA_TIMEDWAIT(semaphore, seconds, useconds, timedout)
+ *    SILC_FSM_EVENT_TIMEDWAIT(event, seconds, useconds, timedout)
  *
  * DESCRIPTION
  *
- *    Macro used to wait for the `semaphore' to become non-zero, or until
+ *    Macro used to wait for the `event' to be signalled, or until
  *    the timeout specified by `seconds' and `useconds' has elapsed.  If
- *    the timeout occurs before the semaphore becomes non-zero, the machine
+ *    the timeout occurs before the event is signalled, the machine
  *    will wakeup.  The `timedout' is SilcBool pointer and if it is
  *    non-NULL indication of whether timeout occurred or not is saved to
  *    the pointer.  This macro can only be used in FSM state functions.
- *    When the semaphore is signalled or timedout the FSM will re-enter
+ *    When the event is signalled or timedout the FSM will re-enter
  *    the current state (or state that was set with silc_fsm_next before
  *    waiting).
  *
@@ -991,7 +1005,7 @@ do {                                               \
  *      ...
  *
  *      // Wait here for async call to complete, or 10 seconds for timeout
- *      SILC_FSM_SEMA_TIMEDWAIT(ctx->async_sema, 10, 0, &timedout);
+ *      SILC_FSM_EVENT_TIMEDWAIT(ctx->async_event, 10, 0, &timedout);
  *
  *      // See if timeout occurred
  *      if (timedout == TRUE)
@@ -1004,24 +1018,23 @@ do {                                            \
  *    }
  *
  ***/
-#define SILC_FSM_SEMA_TIMEDWAIT(sema, seconds, useconds, ret_to)         \
-do {                                                                     \
-  if (silc_fsm_sema_timedwait(sema, fsm, seconds, useconds, ret_to) == 0) \
-    return SILC_FSM_WAIT;                                                \
+#define SILC_FSM_EVENT_TIMEDWAIT(event, seconds, useconds, ret_to)     \
+do {                                                                   \
+  if (silc_fsm_event_timedwait(event, fsm, seconds, useconds, ret_to) == 0) \
+    SILC_FSM_WAIT;                                                     \
 } while(0)
 
-/****f* silcutil/SilcFSMAPI/SILC_FSM_SEMA_POST
+/****f* silcutil/SilcFSMAPI/SILC_FSM_EVENT_SIGNAL
  *
  * SYNOPSIS
  *
- *    SILC_FSM_SEMA_POST(semaphore)
+ *    SILC_FSM_EVENT_SIGNAL(event)
  *
  * DESCRIPTION
  *
- *    Increases the semaphore counter and awakens everybody that are
- *    waiting for this semaphore.  This macro never blocks.  It can be
- *    safely called at any place in state function and in asynchronous
- *    callbacks or other functions.
+ *    Signals the `event' and awakens everybody that are waiting for this
+ *    event.  This macro never blocks.  It can be safely called at any place
+ *    in state function and in asynchronous callbacks or other functions.
  *
  * EXAMPLE
  *
@@ -1031,14 +1044,14 @@ do {                                                                      \
  *
  *      // Notify all waiters
  *      ctx->async_success = TRUE;
- *      SILC_FSM_SEMA_POST(ctx->async_sema);
+ *      SILC_FSM_EVENT_SIGNAL(ctx->async_event);
  *      ...
  *    }
  *
  ***/
-#define SILC_FSM_SEMA_POST(sema)               \
+#define SILC_FSM_EVENT_SIGNAL(event)           \
 do {                                           \
-  silc_fsm_sema_post(sema);                    \
+  silc_fsm_event_signal(event);                        \
 } while(0)
 
 #include "silcfsm_i.h"
index 09c167b66683fead0c7d7ed3b7d02adabe4b76b6..9b2e5a9ebf5e7b66240190d82d55fa036e5d3640 100644 (file)
 #error "Do not include this header directly"
 #endif
 
-/* Semaphore structure, holds list of FSM machines that are waiting
-   for this semaphore.  The SilcFSM has *next; pointer that is used
-   with SilcList. */
-struct SilcFSMSemaObject {
+/* FSM state status */
+typedef enum {
+  SILC_FSM_ST_CONTINUE,             /* Continue immediately to next state */
+  SILC_FSM_ST_YIELD,        /* Continue to next state through scheduler */
+  SILC_FSM_ST_WAIT,         /* Wait for some async call or timeout */
+  SILC_FSM_ST_FINISH,       /* Finish state machine and call destructor
+                               through scheduler */
+} SilcFSMStatus;
+
+/* Event structure, holds list of FSM machines that are waiting for this
+   event.  The SilcFSM has *next; pointer that is used with SilcList.
+   Internally events act as semaphore counters. */
+struct SilcFSMEventObject {
   SilcFSM fsm;                         /* Machine */
   SilcList waiters;                    /* List of SilcFSM pointers */
-  unsigned int value     : 21;         /* Current semaphore value */
+  unsigned int value     : 21;         /* Current event semaphore value */
   unsigned int refcnt    : 10;         /* Reference counter */
   unsigned int allocated : 1;          /* Set if allocated */
 };
@@ -40,7 +49,7 @@ struct SilcFSMObject {
   struct SilcFSMObject *next;
   void *fsm_context;                   /* Caller's context */
   SilcSchedule schedule;               /* Scheduler */
-  SilcFSMSema sema;                    /* Valid if waiting sema timeout */
+  SilcFSMEvent event;                  /* Valid if waiting event timeout */
   SilcFSMStateCallback next_state;     /* Next state in machine */
   void *state_context;                 /* Extra state specific context */
   SilcFSMDestructor destructor;                /* Destructor */
@@ -55,24 +64,24 @@ struct SilcFSMObject {
     /* Thread */
     struct {
       struct SilcFSMObject *fsm;       /* Machine */
-      SilcFSMSema sema;                        /* Semaphore for waiting termination */
+      SilcFSMEvent event;               /* Event for waiting termination */
     } t;
   } u;
   unsigned int thread           : 1;   /* Set if this is thread */
   unsigned int real_thread      : 1;    /* Set if to use real threads */
   unsigned int async_call       : 1;    /* Set if called real async call */
   unsigned int finished         : 1;    /* Set if SILC_FSM_FINISH returned */
-  unsigned int sema_timedout    : 1;    /* Set if waiting sema timedout */
+  unsigned int event_timedout   : 1;    /* Set if waiting event timedout */
   unsigned int synchronous      : 1;    /* Set if silc_fsm_start_sync called */
   unsigned int next_later       : 1;    /* Set if silc_fsm_next_later called */
   unsigned int started          : 1;    /* Set when started and not finished */
 };
 
-/* Semaphore post context */
+/* Event signal context */
 typedef struct {
-  SilcFSMSema sema;                    /* Semaphore */
+  SilcFSMEvent event;                  /* Event */
   SilcFSM fsm;                         /* Signalled FSM */
-} *SilcFSMSemaPost;
+} *SilcFSMEventSignal;
 
 /* Used internally by the SILC_FSM_CALL macros to detect whether async
    call is really async or not. */
@@ -87,11 +96,11 @@ SilcBool silc_fsm_set_call(struct SilcFSMObject *fsm, SilcBool async_call)
 /* Wait for thread to terminate */
 SilcBool silc_fsm_thread_wait(void *fsm, void *thread);
 
-/* Semaphores */
-SilcUInt32 silc_fsm_sema_wait(SilcFSMSema sema, void *fsm);
-SilcUInt32 silc_fsm_sema_timedwait(SilcFSMSema sema, void *fsm,
-                                  SilcUInt32 seconds, SilcUInt32 useconds,
-                                  SilcBool *ret_to);
-void silc_fsm_sema_post(SilcFSMSema sema);
+/* Eventphores */
+SilcUInt32 silc_fsm_event_wait(SilcFSMEvent event, void *fsm);
+SilcUInt32 silc_fsm_event_timedwait(SilcFSMEvent event, void *fsm,
+                                   SilcUInt32 seconds, SilcUInt32 useconds,
+                                   SilcBool *ret_to);
+void silc_fsm_event_signal(SilcFSMEvent event);
 
 #endif /* SILCFSM_I_H */