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