Handle failed timeout additions (in case scheduler is stopped).
authorPekka Riikonen <priikone@silcnet.org>
Tue, 12 Dec 2006 18:38:42 +0000 (18:38 +0000)
committerPekka Riikonen <priikone@silcnet.org>
Tue, 12 Dec 2006 18:38:42 +0000 (18:38 +0000)
lib/silcutil/silcfsm.c
lib/silcutil/silcfsm.h
lib/silcutil/tests/test_silcschedule.c

index 5cd81e1969a2e59786c7532f11c17242187fcf9d..4df30aec9f06748b14503d335e376b6377a4cad9 100644 (file)
@@ -160,10 +160,11 @@ void silc_fsm_free(void *fsm)
 {
   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
@@ -200,13 +201,18 @@ void silc_fsm_start(void *fsm, SilcFSMStateCallback start_state)
 
   /* 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 */
@@ -288,8 +294,13 @@ void silc_fsm_finish(void *fsm)
   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;
@@ -304,11 +315,13 @@ void silc_fsm_finish(void *fsm)
   }
 
   /* 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 */
@@ -327,16 +340,12 @@ SilcFSM silc_fsm_get_machine(SilcFSMThread thread)
   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 */
@@ -379,8 +388,6 @@ SilcBool silc_fsm_thread_wait(void *fsm, void *thread)
 
   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;
index 2f27184e5fe2ca43b54ff8d26a56455db7050faf..481385675798d64dabacb0428b5e6d6afa4ce9fd 100644 (file)
@@ -117,6 +117,19 @@ typedef struct SilcFSMObject SilcFSMThreadStruct;
  *    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 {
@@ -307,9 +320,7 @@ do {                                                \
  *
  *    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
  *
@@ -327,9 +338,8 @@ do {                                                \
  ***/
 #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
@@ -693,6 +703,10 @@ void silc_fsm_continue_sync(void *fsm);
  *    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);
 
index 19f94b2ba01d302e8e6ff970270239240777284e..5a6824ccac31003556908d9e877b9bc03110ea2d 100644 (file)
@@ -95,7 +95,7 @@ int main(int argc, char **argv)
 
   silc_schedule_task_add_signal(schedule, SIGINT, interrupt, NULL);
 
-  silc_schedule_task_add_timeout(schedule, start, NULL, 0, 1);
+  silc_schedule_task_add_timeout(schedule, start, NULL, 1, 0);
 
   SILC_LOG_DEBUG(("Running scheduler"));
   silc_schedule(schedule);