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