From b2b2847e30b6119863eee0d1f02aaa518fa0167c Mon Sep 17 00:00:00 2001 From: Pekka Riikonen Date: Sat, 23 Dec 2006 17:55:59 +0000 Subject: [PATCH] Changed state move return values to macros: SILC_FSM_CONTINUE, SILC_FSM_YIELD, SILC_FSM_WAIT and SILC_FSM_FINISH macros. Changed FSM semaphores to FSM events. --- lib/silcutil/silcfsm.c | 215 +++++++++++++-------------- lib/silcutil/silcfsm.h | 313 ++++++++++++++++++++------------------- lib/silcutil/silcfsm_i.h | 43 +++--- 3 files changed, 296 insertions(+), 275 deletions(-) diff --git a/lib/silcutil/silcfsm.c b/lib/silcutil/silcfsm.c index 47c9b51f..9ba6466f 100644 --- a/lib/silcutil/silcfsm.c +++ b/lib/silcutil/silcfsm.c @@ -21,11 +21,11 @@ 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); } diff --git a/lib/silcutil/silcfsm.h b/lib/silcutil/silcfsm.h index 48138567..8a28360b 100644 --- a/lib/silcutil/silcfsm.h +++ b/lib/silcutil/silcfsm.h @@ -23,18 +23,21 @@ * * 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" diff --git a/lib/silcutil/silcfsm_i.h b/lib/silcutil/silcfsm_i.h index 09c167b6..9b2e5a9e 100644 --- a/lib/silcutil/silcfsm_i.h +++ b/lib/silcutil/silcfsm_i.h @@ -24,13 +24,22 @@ #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 */ -- 2.24.0