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