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