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