Added silc_fsm_finish.
[crypto.git] / lib / silcutil / silcfsm.h
1 /*
2
3   silcfsm.h
4
5   Author: Pekka Riikonen <priikone@silcnet.org>
6
7   Copyright (C) 2005, 2006 Pekka Riikonen
8
9   This program is free software; you can redistribute it and/or modify
10   it under the terms of the GNU General Public License as published by
11   the Free Software Foundation; version 2 of the License.
12
13   This program is distributed in the hope that it will be useful,
14   but WITHOUT ANY WARRANTY; without even the implied warranty of
15   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16   GNU General Public License for more details.
17
18 */
19
20 /****h* silcutil/SILC Finite State Machine
21  *
22  * DESCRIPTION
23  *
24  * SILC FSM Interface implements a finite state machine.  The FSM can be
25  * used to implement all kinds of machines and protocols.  The FSM supports
26  * also threads and can be synchronized by using FSM semaphores.  The FSM
27  * also supports real system threads.  It is possible to create new FSM
28  * thread and then execute in real system thread, if platform supports
29  * threads.
30  *
31  * The FSM provides semaphores because of their versatility.  The FSM
32  * semaphores can be used as mutual exclusion locks to protect critical
33  * sections, and as conditional variables and signallers.  The FSM
34  * semaphores can safely be used to synchronize also FSM threads that are
35  * executed in real system threads.  This makes SILC FSM very effective
36  * tool to implement complex machines whether they are executed in single
37  * thread or in multiple threads.
38  *
39  ***/
40
41 #ifndef SILCFSM_H
42 #define SILCFSM_H
43
44 /****s* silcutil/SilcFSMAPI/SilcFSM
45  *
46  * NAME
47  *
48  *    typedef struct SilcFSMObject *SilcFSM;
49  *
50  * DESCRIPTION
51  *
52  *    The actual FSM context and is allocated with silc_fsm_alloc and
53  *    given as argument to all silc_fsm_* functions.  It is freed by
54  *    silc_fsm_free function.  It is also possible to use pre-allocated
55  *    FSM context by using SilcFSMStruct instead of SilcFSM.
56  *
57  ***/
58 typedef struct SilcFSMObject *SilcFSM;
59
60 /****s* silcutil/SilcFSMAPI/SilcFSMStruct
61  *
62  * NAME
63  *
64  *    typedef struct SilcFSMObject SilcFSMStruct;
65  *
66  * DESCRIPTION
67  *
68  *    The actual FSM context and can be used as pre-allocated FSM context,
69  *    instead of SilcFSM context.  This context is initialized with the
70  *    silc_fsm_init function.  It need not be uninitialized.
71  *
72  ***/
73 typedef struct SilcFSMObject SilcFSMStruct;
74
75 /****s* silcutil/SilcFSMAPI/SilcFSMThread
76  *
77  * NAME
78  *
79  *    typedef struct SilcFSMObject *SilcFSMThread;
80  *
81  * DESCRIPTION
82  *
83  *    FSM thread context.  The SILC FSM supports threads, virtual machine
84  *    threads (inside FSM) and actual real system threads if platorm
85  *    supports them.  In a complex machine certain complex operations may
86  *    be desired to execute in a thread.  The SilcFSMThread is allocated
87  *    by silc_fsm_thread_alloc and feed by silc_fsm_free.  It is also
88  *    possible to use pre-allocated thread by using SilcFSMThreadStruct
89  *    instead of SilcFSMThread.
90  *
91  ***/
92 typedef struct SilcFSMObject *SilcFSMThread;
93
94 /****s* silcutil/SilcFSMAPI/SilcFSM
95  *
96  * NAME
97  *
98  *    typedef struct SilcFSMObject SilcFSMThreadStruct;
99  *
100  * DESCRIPTION
101  *
102  *    FSM thread context and can be used as a pre-allocated FSM thread context,
103  *    instead of SilcFSMThread context.  This context is initialized with the
104  *    silc_fsm_thread_init function.  It need not be uninitialized.
105  *
106  ***/
107 typedef struct SilcFSMObject SilcFSMThreadStruct;
108
109 /****d* silcutil/SilcFSMAPI/SilcFSMStatus
110  *
111  * NAME
112  *
113  *    typedef enum { ... } SilcFSMStatus;
114  *
115  * DESCRIPTION
116  *
117  *    Status values that the FSM state functions return.  They dicatate
118  *    how the machine will behave after returning from the state function.
119  *
120  * SOURCE
121  */
122 typedef enum {
123   SILC_FSM_CONTINUE,         /* Continue immediately to next state */
124   SILC_FSM_YIELD,            /* Continue to next state through scheduler */
125   SILC_FSM_WAIT,             /* Wait for some async call or timeout */
126   SILC_FSM_FINISH,           /* Finish state machine and call destructor
127                                 through scheduler */
128 } SilcFSMStatus;
129 /***/
130
131 /****f* silcutil/SilcFSMAPI/SilcFSMDestructor
132  *
133  * SYNOPSIS
134  *
135  *    typedef void (*SilcFSMDestructor)(SilcFSM fsm, void *fsm_context,
136  *                                      void *destructor_context);
137  *
138  * DESCRIPTION
139  *
140  *    The destructor callback that was set in silc_fsm_alloc or in
141  *    silc_fsm_init function.  It will be called when a state function
142  *    returns SILC_FSM_FINISH.  This function will be called through
143  *    the scheduler; it will not be called immediately after the state
144  *    function returns SILC_FSM_FINISH, but will be called later.
145  *    The `fsm' may be freed in this function.
146  *
147  ***/
148 typedef void (*SilcFSMDestructor)(SilcFSM fsm, void *fsm_context,
149                                   void *destructor_context);
150
151 /****f* silcutil/SilcFSMAPI/SilcFSMThreadDestructor
152  *
153  * SYNOPSIS
154  *
155  *    typedef void (*SilcFSMThreadDestructor)(SilcFSMThread thread,
156  *                                            void *thread_context,
157  *                                            void *destructor_context);
158  *
159  * DESCRIPTION
160  *
161  *    The destructor callback that was set in silc_fsm_thread_alloc or in
162  *    silc_fsm_thread_init function.  It will be called when a state function
163  *    returns SILC_FSM_FINISH.  This function will be called through
164  *    the scheduler; it will not be called immediately after the state
165  *    function returns SILC_FSM_FINISH, but will be called later.  The
166  *    `thread' may be freed in this function.
167  *
168  * NOTES
169  *
170  *    Even if the `thread' was executed in real system thread, this callback
171  *    is always received in the main machine thread, not in the created
172  *    thread.
173  *
174  ***/
175 typedef void (*SilcFSMThreadDestructor)(SilcFSMThread thread,
176                                         void *thread_context,
177                                         void *destructor_context);
178
179 /****d* silcutil/SilcFSMAPI/SILC_FSM_STATE
180  *
181  * NAME
182  *
183  *    #define SILC_FSM_STATE(name)
184  *
185  * DESCRIPTION
186  *
187  *    This macro is used to declare a FSM state function.  The `fsm' is
188  *    the SilcFSM or SilcFSMThread context, the `fsm_context' is the context
189  *    given as argument to silc_fsm_alloc, silc_fsm_init, silc_fsm_thread_init,
190  *    or silc_fsm_thread_alloc function.  The `state_context' is the optional
191  *    state specific context set with silc_fsm_set_state_context function.
192  *
193  * SOURCE
194  */
195 #define SILC_FSM_STATE(name)                                            \
196 SilcFSMStatus name(struct SilcFSMObject *fsm, void *fsm_context,        \
197                    void *state_context)
198 /***/
199
200 /* State function callback */
201 typedef SilcFSMStatus (*SilcFSMStateCallback)(struct SilcFSMObject *fsm,
202                                               void *fsm_context,
203                                               void *state_context);
204
205 /****d* silcutil/SilcFSMAPI/SILC_FSM_CALL
206  *
207  * NAME
208  *
209  *    SILC_FSM_CALL(function)
210  *
211  * DESCRIPTION
212  *
213  *    Macro used to call asynchronous calls from state function.  If the
214  *    call is not really asynchronous then this will cause the machine to
215  *    directly proceed to next state.  If the call is truly asynchronous
216  *    then this will set the machine to wait state.  The silc_fsm_next
217  *    must be called before this macro, so that the next state is set.
218  *
219  * NOTES
220  *
221  *    The state function returns in this macro.
222  *
223  * EXAMPLE
224  *
225  *    // Simple example
226  *    silc_fsm_next(fsm, some_next_state);
227  *    SILC_FSM_CALL(silc_some_async_call(server, some_callback, context));
228  *
229  *    // More complex example
230  *    silc_fsm_next(fsm, some_next_state);
231  *    SILC_FSM_CALL((some_context->operation =
232  *                   silc_some_async_call(server, some_callback, context)));
233  *
234  ***/
235 #define SILC_FSM_CALL(function)                 \
236 do {                                            \
237   assert(!silc_fsm_set_call(fsm, TRUE));        \
238   function;                                     \
239   if (!silc_fsm_set_call(fsm, FALSE))           \
240     return SILC_FSM_CONTINUE;                   \
241   return SILC_FSM_WAIT;                         \
242 } while(0)
243
244 /****d* silcutil/SilcFSMAPI/SILC_FSM_CALL_CONTINUE
245  *
246  * NAME
247  *
248  *    SILC_FSM_CALL_CONTINUE(fsm)
249  *
250  * DESCRIPTION
251  *
252  *    Macro used to proceed after asynchornous call.  This is called in the
253  *    callback of the asynchronous call to continue in the state machine.
254  *
255  * EXAMPLE
256  *
257  *    void some_callback(void *context) {
258  *      SilcFSM fsm = context;
259  *      ...
260  *      // Continue to the next state
261  *      SILC_FSM_CALL_CONTINUE(fsm);
262  *    }
263  *
264  ***/
265 #define SILC_FSM_CALL_CONTINUE(fsm)             \
266 do {                                            \
267   if (!silc_fsm_set_call(fsm, FALSE))           \
268     silc_fsm_continue(fsm);                     \
269 } while(0)
270
271 /****d* silcutil/SilcFSMAPI/SILC_FSM_CALL_CONTINUE_SYNC
272  *
273  * NAME
274  *
275  *    SILC_FSM_CALL_CONTINUE_SYNC(fsm)
276  *
277  * DESCRIPTION
278  *
279  *    Macro used to proceed after asynchornous call.  This is called in the
280  *    callback of the asynchronous call to continue in the state machine.
281  *    This continues to the next state synchronously, not through the
282  *    scheduler.
283  *
284  * EXAMPLE
285  *
286  *    void some_callback(void *context) {
287  *      SilcFSM fsm = context;
288  *      ...
289  *      // Continue to the next state immediately
290  *      SILC_FSM_CALL_CONTINUE_SYNC(fsm);
291  *    }
292  *
293  ***/
294 #define SILC_FSM_CALL_CONTINUE_SYNC(fsm)        \
295 do {                                            \
296   if (!silc_fsm_set_call(fsm, FALSE))           \
297     silc_fsm_continue_sync(fsm);                \
298 } while(0)
299
300 /****d* silcutil/SilcFSMAPI/SILC_FSM_THREAD_WAIT
301  *
302  * NAME
303  *
304  *    SILC_FSM_THREAD_WAIT(thread)
305  *
306  * DESCRIPTION
307  *
308  *    Macro used to wait for the `thread' to terminate.  The machine or
309  *    thread will be suspended while it is waiting for the thread to
310  *    terminate.  If the thread to be waited has already terminated (but
311  *    the context has not been freed yet), this will continue immediately
312  *    to the following state without waiting.
313  *
314  * NOTES
315  *
316  *    The state function returns in this macro.
317  *
318  *    This macro is the only way to safely make sure that the thread has
319  *    terminated by the time FSM continues from the waiting state.  Using
320  *    semaphores to signal from the thread before SILC_FSM_FINISH is returned
321  *    works with normal FSM threads, but especially with real system threads
322  *    it does not guarantee that the FSM won't continue before the thread has
323  *    actually terminated.  Usually this is not a problem, but it can be a
324  *    problem if the FSM is waiting to be freed.  In this case using this
325  *    macro is strongly recommended.
326  *
327  ***/
328 #define SILC_FSM_THREAD_WAIT(thread)            \
329 do {                                            \
330   if (silc_fsm_thread_wait(fsm, thread))        \
331     return SILC_FSM_WAIT;                       \
332   return SILC_FSM_CONTINUE;                     \
333 } while(0)
334
335 /****f* silcutil/SilcFSMAPI/silc_fsm_alloc
336  *
337  * SYNOPSIS
338  *
339  *    SilcFSM silc_fsm_alloc(void *fsm_context,
340  *                           SilcFSMDestructor destructor,
341  *                           void *destructor_context,
342  *                           SilcSchedule schedule);
343  *
344  * DESCRIPTION
345  *
346  *    Allocates SILC Finite State Machine context.  The `destructor' with
347  *    `destructor_context' will be called when the machines finishes.  The
348  *    caller must free the returned context with silc_fsm_free.  The
349  *    `fsm_context' is delivered to every FSM state function.  The `schedule'
350  *    is the caller's scheduler and the FSM will be run in the scheduler.
351  *
352  * EXAMPLE
353  *
354  *    SilcAsyncOperation silc_async_call(Callback callback, void *cb_context)
355  *    {
356  *      SilcAsyncOperation op;
357  *      SilcFSM fsm;
358  *      ...
359  *
360  *      // Allocate async operation so that caller can control us, like abort
361  *      op = silc_async_alloc(silc_async_call_abort, NULL, ourcontext);
362  *
363  *      // Start FSM
364  *      fsm = silc_fsm_alloc(ourcontext, fsm_destructor, ourcontext,
365  *                           schedule);
366  *      silc_fsm_start(fsm, first_state);
367  *      ...
368  *
369  *      // Return async operation for upper layer
370  *      return op;
371  *    }
372  *
373  ***/
374 SilcFSM silc_fsm_alloc(void *fsm_context,
375                        SilcFSMDestructor destructor,
376                        void *destructor_context,
377                        SilcSchedule schedule);
378
379 /****f* silcutil/SilcFSMAPI/silc_fsm_init
380  *
381  * SYNOPSIS
382  *
383  *    SilcBool silc_fsm_init(SilcFSM fsm,
384  *                           void *fsm_context,
385  *                           SilcFSMDestructor destructor,
386  *                           void *destructor_context,
387  *                           SilcSchedule schedule);
388  *
389  * DESCRIPTION
390  *
391  *    Initializes a pre-allocated SilcFSM context.  This call is equivalent
392  *    to silc_fsm_alloc except that this takes the pre-allocated context
393  *    as argument.  The silc_fsm_free must not be called if this was called.
394  *    Returns TRUE if the initialization is Ok or FALSE if error occurred.
395  *    This function does not allocate any memory.  The `schedule' is the
396  *    caller's scheduler and the FSM will be run in the scheduler.
397  *
398  * EXAMPLE
399  *
400  *    SilcFSMStruct fsm;
401  *
402  *    silc_fsm_init(&fsm, application, fsm_destructor, application, schedule);
403  *    silc_fsm_start(&fsm, first_state);
404  *
405  ***/
406 SilcBool silc_fsm_init(SilcFSM fsm,
407                        void *fsm_context,
408                        SilcFSMDestructor destructor,
409                        void *destructor_context,
410                        SilcSchedule schedule);
411
412 /****f* silcutil/SilcFSMAPI/silc_fsm_thread_alloc
413  *
414  * SYNOPSIS
415  *
416  *    SilcFSMThread silc_fsm_thread_alloc(SilcFSM fsm,
417  *                                        void *thread_context,
418  *                                        SilcFSMThreadDestructor destructor,
419  *                                        void *destructor_context,
420  *                                        SilcBool real_thread);
421  *
422  * DESCRIPTION
423  *
424  *    Allocates FSM thread context.  The thread will be executed in the
425  *    FSM machine indicated by `fsm'.  The caller must free the returned
426  *    thread context with silc_fsm_free.  If the 'real_thread' is TRUE
427  *    then the thread will actually be executed in real thread, if platform
428  *    supports them.  The `thread_context' is delivered to every state
429  *    function in the thread.
430  *
431  * NOTES
432  *
433  *    Note the limitations on using `real_thread' boolean to indicate running
434  *    the FSM thread in a real system thread:
435  *
436  *    If the system does not support threads, then this function will revert
437  *    back to normal FSM threads.
438  *
439  *    If the `real_thread' is TRUE then FSM will allocate new SilcSchedule
440  *    for the FSM thread.  This is done because the SilcSchedule that the
441  *    `fsm' use cannot be used in the thread.  This is limitation in the
442  *    SilcSchedule implementation.  If you need scheduler in the real thread
443  *    it is strongly recommended that you use the SilcSchedule that is
444  *    allocated for the thread.  You can retrieve the SilcSchedule from the
445  *    thread using silc_fsm_get_schedule function.  Note that, the allocated
446  *    SilcSchedule will become invalid after the thread finishes.
447  *
448  *    You may still however use the original SilcSchedule if you wish.  In
449  *    this case note its limitation: you may only add and/or remove tasks,
450  *    tasks cannot be executed in the thread.  You will need to deliver the
451  *    original SilcSchedule to the thread in the `thread_context' if you wish
452  *    to use it.
453  *
454  *    If `real_thread' is FALSE then no limitations on what can be run in
455  *    the thread exist.  In this case silc_fsm_get_schedule will return
456  *    the SilcSchedule that was originally given to silc_fsm_alloc or
457  *    silc_fsm_init.
458  *
459  * EXAMPLE
460  *
461  *    SILC_FSM_STATE(silc_foo_state)
462  *    {
463  *      SilcFSMThread thread;
464  *      ...
465  *
466  *      // Execute the route lookup in thread
467  *      thread = silc_fsm_thread_alloc(fsm, fsm_context, NULL, NULL, FALSE);
468  *      silc_fsm_start(thread, silc_route_lookup_start);
469  *
470  *      // Wait here for the thread to terminate. Set the state where to go
471  *      // after the thread has terminated.
472  *      silc_fsm_next(fsm, silc_foo_route_lookup_finished);
473  *      SILC_FSM_THREAD_WAIT(thread);
474  *    }
475  *
476  ***/
477 SilcFSMThread silc_fsm_thread_alloc(SilcFSM fsm,
478                                     void *thread_context,
479                                     SilcFSMThreadDestructor destructor,
480                                     void *destructor_context,
481                                     SilcBool real_thread);
482
483 /****f* silcutil/SilcFSMAPI/silc_fsm_thread_init
484  *
485  * SYNOPSIS
486  *
487  *    void silc_fsm_thread_init(SilcFSMThread thread,
488  *                              SilcFSM fsm,
489  *                              void *thread_context,
490  *                              SilcFSMThreadDestructor destructor,
491  *                              void *destructor_context,
492  *                              SilcBool real_thread);
493  *
494  * DESCRIPTION
495  *
496  *    Initializes a pre-allocated SilcFSMThread context.  This call is
497  *    equivalent to silc_fsm_thread_alloc except that this takes the
498  *    pre-allocated context as argument.  The silc_fsm_free must not be
499  *    called if this was called.  If the `real_thread' is TRUE then the
500  *    thread will actually be executed in real thread, if platform supports
501  *    them.
502  *
503  * NOTES
504  *
505  *    See the notes from the silc_fsm_thread_alloc.
506  *
507  * EXAMPLE
508  *
509  *    SilcFSMThreadStruct thread;
510  *
511  *    silc_fsm_thread_init(&thread, fsm, application, NULL, NULL, FALSE);
512  *    silc_fsm_start(&thread, first_state);
513  *
514  ***/
515 void silc_fsm_thread_init(SilcFSMThread thread,
516                           SilcFSM fsm,
517                           void *thread_context,
518                           SilcFSMThreadDestructor destructor,
519                           void *destructor_context,
520                           SilcBool real_thread);
521
522 /****f* silcutil/SilcFSMAPI/silc_fsm_free
523  *
524  * SYNOPSIS
525  *
526  *    void silc_fsm_free(void *fsm);
527  *
528  * DESCRIPTION
529  *
530  *    Free the SILC FSM context that was allocated with silc_fsm_alloc,
531  *    or free the SILC FSM thread context that was allocated with
532  *    silc_fsm_thread_alloc.  This function is used with both SilcFSM
533  *    and SilcFSMThread contexts.
534  *
535  * NOTES
536  *
537  *    When freeing FSM, it must not have any active threads.
538  *
539  ***/
540 void silc_fsm_free(void *fsm);
541
542 /****f* silcutil/SilcFSMAPI/silc_fsm_start
543  *
544  * SYNOPSIS
545  *
546  *    void silc_fsm_start(void *fsm, SilcFSMStateCallback start_state);
547  *
548  * DESCRIPTION
549  *
550  *    This function must be called after the SILC FSM context was created.
551  *    This actually starts the state machine.  Note that, the machine is
552  *    started later after this function returns.  The `start_state' is the
553  *    state where the machine or thread is started.  This function is used
554  *    with both SilcFSM and SilcFSMThread contexts.
555  *
556  * EXAMPLE
557  *
558  *    SilcFSM fsm;
559  *
560  *    fsm = silc_fsm_alloc(context, destructor, context, schedule);
561  *    silc_fsm_start(fsm, first_state);
562  *
563  ***/
564 void silc_fsm_start(void *fsm, SilcFSMStateCallback start_state);
565
566 /****f* silcutil/SilcFSMAPI/silc_fsm_start_sync
567  *
568  * SYNOPSIS
569  *
570  *    void silc_fsm_start_sync(void *fsm, SilcFSMStateCallback start_state);
571  *
572  * DESCRIPTION
573  *
574  *    This function is same as silc_fsm_start, except that the FSM will
575  *    be started immediately inside this function.  After this function
576  *    returns the `start_state' has already been executed.  If the machine
577  *    is completely synchronous (no waiting used in the machine) then
578  *    the machine will have finished once this function returns.  Also
579  *    note that if the machine is completely synchronous the destructor
580  *    will also be called from inside this function.  This function is used
581  *    with both SilcFSM and SilcFSMThread contexts.
582  *
583  ***/
584 void silc_fsm_start_sync(void *fsm, SilcFSMStateCallback start_state);
585
586 /****f* silcutil/SilcFSMAPI/silc_fsm_next
587  *
588  * SYNOPSIS
589  *
590  *    void silc_fsm_next(void *fsm, SilcFSMStateCallback next_state);
591  *
592  * DESCRIPTION
593  *
594  *    Set the next state to be executed.  If the state function that
595  *    call this function returns SILC_FSM_CONTINUE, the `next_state'
596  *    will be executed immediately.  If it returns SILC_FSM_YIELD it
597  *    yields the thread and the `next_state' will be run after other
598  *    threads have run first.  This function must always be used to set
599  *    the next state in the machine or thread.  This function is used
600  *    with both SilcFSM and SilcFSMThread contexts.
601  *
602  * EXAMPLE
603  *
604  *    // Move to next state
605  *    silc_fsm_next(fsm, next_state);
606  *    return SILC_FSM_CONTINUE;
607  *
608  ***/
609 void silc_fsm_next(void *fsm, SilcFSMStateCallback next_state);
610
611 /****f* silcutil/SilcFSMAPI/silc_fsm_next_later
612  *
613  * SYNOPSIS
614  *
615  *    void silc_fsm_next_later(void *fsm, SilcFSMStateCallback next_state,
616  *                             SilcUInt32 seconds, SilcUInt32 useconds);
617  *
618  * DESCRIPTION
619  *
620  *    Set the next state to be executed later, at the specified time.
621  *    The SILC_FSM_WAIT must be returned in the state function if this
622  *    function is called.  If any other state is returned machine operation
623  *    is undefined.  The machine or thread will move to `next_state' after
624  *    the specified timeout.  This function is used with both SilcFSM and
625  *    SilcFSMThread contexts.
626  *
627  * NOTES
628  *
629  *    If both `seconds' and `useconds' are 0, the effect is same as calling
630  *    silc_fsm_next function, and SILC_FSM_CONTINUE must be returned.
631  *
632  *    If silc_fsm_continue or silc_fsm_continue_sync is called while the
633  *    machine or thread is in SILC_FSM_WAIT state the timeout is automatically
634  *    canceled and the state moves to the next state.
635  *
636  * EXAMPLE
637  *
638  *    // Move to next state after 10 seconds
639  *    silc_fsm_next_later(fsm, next_state, 10, 0);
640  *    return SILC_FSM_WAIT;
641  *
642  ***/
643 void silc_fsm_next_later(void *fsm, SilcFSMStateCallback next_state,
644                          SilcUInt32 seconds, SilcUInt32 useconds);
645
646 /****f* silcutil/SilcFSMAPI/silc_fsm_continue
647  *
648  * SYNOPSIS
649  *
650  *    void silc_fsm_continue(void *fsm);
651  *
652  * DESCRIPTION
653  *
654  *    Continues in the state machine from a SILC_FSM_WAIT state.  This can
655  *    be called from outside waiting FSM to continue to the next state.
656  *    This function can be used instead of SILC_FSM_CALL_CONTINUE macro
657  *    in case the SILC_FSM_CALL was not used.  This must not be used if
658  *    SILC_FSM_CALL was used.  This function is used with both SilcFSM and
659  *    SilcFSMThread contexts.
660  *
661  ***/
662 void silc_fsm_continue(void *fsm);
663
664 /****f* silcutil/SilcFSMAPI/silc_fsm_continue_sync
665  *
666  * SYNOPSIS
667  *
668  *    void silc_fsm_continue_sync(void *fsm);
669  *
670  * DESCRIPTION
671  *
672  *    Continues immediately in the state machine from a SILC_FSM_WAIT state.
673  *    This can be called from outside waiting FSM to immediately continue to
674  *    the next state.  This function can be used instead of the
675  *    SILC_FSM_CALL_CONTINUE_SYNC macro in case the SILC_FSM_CALL was not used.
676  *    This must not be used if SILC_FSM_CALL was used.  This function is used
677  *    with both SilcFSM and SilcFSMThread contexts.
678  *
679  ***/
680 void silc_fsm_continue_sync(void *fsm);
681
682 /****f* silcutil/SilcFSMAPI/silc_fsm_finish
683  *
684  * SYNOPSIS
685  *
686  *    void silc_fsm_finish(void *fsm);
687  *
688  * DESCRIPTION
689  *
690  *    Finishes the `fsm'.  This function may be used in case the FSM
691  *    needs to be finished outside FSM states.  Usually FSM is finished
692  *    by returning SILC_FSM_FINISH from the state, but if this is not
693  *    possible this function may be called.  This function is used with
694  *    both SilcFSM and SilcFSMThread contexts.
695  *
696  ***/
697 void silc_fsm_finish(void *fsm);
698
699 /****f* silcutil/SilcFSMAPI/silc_fsm_set_context
700  *
701  * SYNOPSIS
702  *
703  *    void silc_fsm_set_context(void *fsm, void *fsm_context);
704  *
705  * DESCRIPTION
706  *
707  *    Set new context for the `fsm'.  This function can be used to change
708  *    the context inside the `fsm', if needed.  This function is used with
709  *    both SilcFSM and SilcFSMThread contexts.  The context is the
710  *    `fsm_context' in the state function (SILC_FSM_STATE).
711  *
712  ***/
713 void silc_fsm_set_context(void *fsm, void *fsm_context);
714
715 /****f* silcutil/SilcFSMAPI/silc_fsm_get_context
716  *
717  * SYNOPSIS
718  *
719  *    void *silc_fsm_get_context(void *fsm);
720  *
721  * DESCRIPTION
722  *
723  *    Returns the context associated with the `fsm'.  It is the context that
724  *    was given to silc_fsm_alloc, silc_fsm_init, silc_fsm_thread_alloc or
725  *    silc_fsm_thread_init.  This function is used with both SilcFSM and
726  *    SilcFSMThread contexts.
727  *
728  ***/
729 void *silc_fsm_get_context(void *fsm);
730
731 /****f* silcutil/SilcFSMAPI/silc_fsm_set_state_context
732  *
733  * SYNOPSIS
734  *
735  *    void silc_fsm_set_state_context(void *fsm, void *state_context);
736  *
737  * DESCRIPTION
738  *
739  *    Set's a state specific context for the `fsm'.  This function can be
740  *    used to change the state context inside the `fsm', if needed.  This
741  *    function is used with both SilcFSM and SilcFSMThread contexts.  The
742  *    context is the `state_context' in the state function (SILC_FSM_STATE).
743  *
744  ***/
745 void silc_fsm_set_state_context(void *fsm, void *state_context);
746
747 /****f* silcutil/SilcFSMAPI/silc_fsm_get_state_context
748  *
749  * SYNOPSIS
750  *
751  *    void *silc_fsm_get_state_context(void *fsm);
752  *
753  * DESCRIPTION
754  *
755  *    Returns the state context associated with the `fsm'.  It is the context
756  *    that was set with silc_fsm_set_state_context function.  This function
757  *    is used with both SilcFSM and SilcFSMThread contexts.
758  *
759  ***/
760 void *silc_fsm_get_state_context(void *fsm);
761
762 /****f* silcutil/SilcFSMAPI/silc_fsm_get_schedule
763  *
764  * SYNOPSIS
765  *
766  *    SilcSchedule silc_fsm_get_schedule(void *fsm);
767  *
768  * DESCRIPTION
769  *
770  *    Returns the SilcSchedule that has been associated with the `fsm'.
771  *    If caller needs scheduler it may retrieve it with this function.  This
772  *    function is used with both SilcFSM and SilcFSMThread contexts.
773  *
774  *    If the `fsm' is thread and real system threads are being used, and this
775  *    is called from the thread, it will return the SilcSchedule that was
776  *    allocated by the FSM for the thread.  It is strongly recommended to
777  *    use this SilcSchedule if you are using real threads, and you need
778  *    scheduler in the thread.  Note that, once the thread finishes the
779  *    returned SilcSchedule becomes invalid.
780  *
781  *    In other times this returns the SilcSchedule pointer that was given
782  *    to silc_fsm_alloc or silc_fsm_init.
783  *
784  ***/
785 SilcSchedule silc_fsm_get_schedule(void *fsm);
786
787 /****f* silcutil/SilcFSMAPI/silc_fsm_get_machine
788  *
789  * SYNOPSIS
790  *
791  *    SilcFSM silc_fsm_get_machine(SilcFSMThread thread);
792  *
793  * DESCRIPTION
794  *
795  *    Returns the machine from the FSM thread indicated by `thread'.
796  *
797  ***/
798 SilcFSM silc_fsm_get_machine(SilcFSMThread thread);
799
800
801 /* FSM Semaphores */
802
803 /****s* silcutil/SilcFSMAPI/SilcFSMSema
804  *
805  * NAME
806  *
807  *    typedef struct SilcFSMSemaObject *SilcFSMSema;
808  *
809  * DESCRIPTION
810  *
811  *    The FSM semaphore context allocated with silc_fsm_sema_alloc.  The
812  *    caller must free it with silc_fsm_sema_free.  It is also possible
813  *    to use pre-allocated SilcFSMSemaStruct instead of SilcFSMSema context.
814  *
815  ***/
816 typedef struct SilcFSMSemaObject *SilcFSMSema;
817
818 /****s* silcutil/SilcFSMAPI/SilcFSMSemaStruct
819  *
820  * NAME
821  *
822  *    typedef struct SilcFSMSemaObject SilcFSMSemaStruct;
823  *
824  * DESCRIPTION
825  *
826  *    The FSM semaphore context that can be used as pre-allocated context.
827  *    It is initialized with silc_fsm_sema_init.  It need not be
828  *    uninitialized.
829  *
830  ***/
831 typedef struct SilcFSMSemaObject SilcFSMSemaStruct;
832
833 /****f* silcutil/SilcFSMAPI/silc_fsm_sema_alloc
834  *
835  * SYNOPSIS
836  *
837  *    SilcFSMSema silc_fsm_sema_alloc(SilcFSM fsm, SilcUInt32 value);
838  *
839  * DESCRIPTION
840  *
841  *    Allocates FSM semaphore with initial value of `value'.  Semaphores are
842  *    counters for resources shared between machine and threads.  Semaphores
843  *    can be waited until the semaphore value is non-zero.  The FSM will be
844  *    suspended when waiting for semaphore.  When the semaphore is incremented
845  *    all that are waiting for the semaphore will be signalled and awaken.
846  *
847  *    Semaphores can be used to wait for example when thread terminates, or
848  *    when thread moves into a specific state, or to protect critical
849  *    sections.  The FSM semaphores can be used also in FSM threads that are
850  *    executed in real system threads.
851  *
852  *    Use the macros SILC_FSM_SEMA_WAIT and SILC_FSM_SEMA_TIMEDWAIT to wait
853  *    for semaphore.  Use the SILC_FSM_SEMA_POST macro to increment the
854  *    counter and wake up all waiters.
855  *
856  ***/
857 SilcFSMSema silc_fsm_sema_alloc(SilcFSM fsm, SilcUInt32 value);
858
859 /****f* silcutil/SilcFSMAPI/silc_fsm_sema_init
860  *
861  * SYNOPSIS
862  *
863  *    void silc_fsm_sema_init(SilcFSMSema sema, SilcFSM fsm, SilcUInt32 value);
864  *
865  * DESCRIPTION
866  *
867  *    Initializes a pre-allocates semaphore context.  This call is
868  *    equivalent to silc_fsm_sema_alloc except this use the pre-allocated
869  *    context.  This fuction does not allocate any memory.
870  *
871  ***/
872 void silc_fsm_sema_init(SilcFSMSema sema, SilcFSM fsm, SilcUInt32 value);
873
874 /****f* silcutil/SilcFSMAPI/silc_fsm_sema_free
875  *
876  * SYNOPSIS
877  *
878  *    void silc_fsm_sema_free(SilcFSMSema sema);
879  *
880  * DESCRIPTION
881  *
882  *    Free the semaphore allocated by silc_fsm_sema_alloc function.
883  *
884  ***/
885 void silc_fsm_sema_free(SilcFSMSema sema);
886
887 /****d* silcutil/SilcFSMAPI/SILC_FSM_SEMA_WAIT
888  *
889  * NAME
890  *
891  *    SILC_FSM_SEMA_WAIT(semaphore)
892  *
893  * DESCRIPTION
894  *
895  *    Macro used to wait for the `semaphore' to become non-zero.  The
896  *    machine will be suspended while it is waiting for the semaphore.
897  *    This macro can only be used in FSM state functions.  When the
898  *    semaphore is signalled the FSM will re-enter the current state (or
899  *    state that was set with silc_fsm_next before waiting).
900  *
901  * EXAMPLE
902  *
903  *    // Signalling example
904  *    ctx->async_sema = silc_fsm_sema_alloc(fsm, 0);
905  *    ...
906  *
907  *    SILC_FSM_STATE(silc_foo_state)
908  *    {
909  *      ...
910  *
911  *      // Wait here for async call to complete
912  *      SILC_FSM_SEMA_WAIT(ctx->async_sema);
913  *
914  *      // Async call completed
915  *      if (ctx->async_success == FALSE)
916  *        fatal(error);
917  *      ...
918  *    }
919  *
920  *    // Mutual exclusion example
921  *    ctx->lock = silc_fsm_sema_alloc(fsm, 1);
922  *    ...
923  *
924  *    SILC_FSM_STATE(silc_foo_state)
925  *    {
926  *      ...
927  *      SILC_FSM_SEMA_WAIT(ctx->lock);
928  *      very critical stuff...
929  *      SILC_FSM_SEMA_POST(ctx->lock);
930  *      ...
931  *    }
932  *
933  ***/
934 #define SILC_FSM_SEMA_WAIT(sema)                \
935 do {                                            \
936   if (silc_fsm_sema_wait(sema, fsm) == 0)       \
937     return SILC_FSM_WAIT;                       \
938 } while(0)
939
940 /****d* silcutil/SilcFSMAPI/SILC_FSM_SEMA_TIMEDWAIT
941  *
942  * NAME
943  *
944  *    SILC_FSM_SEMA_TIMEDWAIT(semaphore, seconds, useconds, timedout)
945  *
946  * DESCRIPTION
947  *
948  *    Macro used to wait for the `semaphore' to become non-zero, or until
949  *    the timeout specified by `seconds' and `useconds' has elapsed.  If
950  *    the timeout occurs before the semaphore becomes non-zero, the machine
951  *    will wakeup.  The `timedout' is SilcBool pointer and if it is
952  *    non-NULL indication of whether timeout occurred or not is saved to
953  *    the pointer.  This macro can only be used in FSM state functions.
954  *    When the semaphore is signalled or timedout the FSM will re-enter
955  *    the current state (or state that was set with silc_fsm_next before
956  *    waiting).
957  *
958  * EXAMPLE
959  *
960  *    SILC_FSM_STATE(silc_foo_state)
961  *    {
962  *      SilcBool timedout;
963  *      ...
964  *
965  *      // Wait here for async call to complete, or 10 seconds for timeout
966  *      SILC_FSM_SEMA_TIMEDWAIT(ctx->async_sema, 10, 0, &timedout);
967  *
968  *      // See if timeout occurred
969  *      if (timedout == TRUE)
970  *        fatal(error);
971  *
972  *      // Async call completed
973  *      if (ctx->async_success == FALSE)
974  *        fatal(error);
975  *      ...
976  *    }
977  *
978  ***/
979 #define SILC_FSM_SEMA_TIMEDWAIT(sema, seconds, useconds, ret_to)          \
980 do {                                                                      \
981   if (silc_fsm_sema_timedwait(sema, fsm, seconds, useconds, ret_to) == 0) \
982     return SILC_FSM_WAIT;                                                 \
983 } while(0)
984
985 /****f* silcutil/SilcFSMAPI/SILC_FSM_SEMA_POST
986  *
987  * SYNOPSIS
988  *
989  *    SILC_FSM_SEMA_POST(semaphore)
990  *
991  * DESCRIPTION
992  *
993  *    Increases the semaphore counter and awakens everybody that are
994  *    waiting for this semaphore.  This macro never blocks.  It can be
995  *    safely called at any place in state function and in asynchronous
996  *    callbacks or other functions.
997  *
998  * EXAMPLE
999  *
1000  *    SILC_FSM_STATE(silc_foo_async_completion)
1001  *    {
1002  *      ...
1003  *
1004  *      // Notify all waiters
1005  *      ctx->async_success = TRUE;
1006  *      SILC_FSM_SEMA_POST(ctx->async_sema);
1007  *      ...
1008  *    }
1009  *
1010  ***/
1011 #define SILC_FSM_SEMA_POST(sema)                \
1012 do {                                            \
1013   silc_fsm_sema_post(sema);                     \
1014 } while(0)
1015
1016 #include "silcfsm_i.h"
1017
1018 #endif /* SILCFSM_H */