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