Created SILC Runtime Toolkit git repository Part II.
[runtime.git] / lib / silcutil / silcschedule.h
1 /*
2
3   silcschedule.h
4
5   Author: Pekka Riikonen <priikone@silcnet.org>
6
7   Copyright (C) 1998 - 2008 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 Schedule Interface
21  *
22  * DESCRIPTION
23  *
24  * The SILC Scheduler is the heart of any application. The scheduler provides
25  * the application's main loop that can handle incoming data, outgoing data,
26  * timeouts and dispatch different kind of tasks.
27  *
28  * The SILC Scheduler supports file descriptor based tasks and timeout tasks.
29  * File descriptor tasks are tasks that perform some operation over the
30  * specified file descriptor. These include network connections, for example.
31  * The timeout tasks are timeouts that are executed after the specified
32  * timeout has elapsed.
33  *
34  * The SILC Scheduler is designed to be the sole main loop of the application
35  * so that the application does not need any other main loop.  However,
36  * SILC Scheduler does support running the scheduler only one iteration, so
37  * that the scheduler does not block, and thus providing a possiblity that some
38  * external main loop is run over the SILC Scheduler.
39  *
40  * Typical application first initializes the scheduler and then register
41  * the very first tasks to the scheduler and then run the scheduler.  After
42  * the scheduler's run function returns the application is considered to be
43  * ended.
44  *
45  * On Windows systems the SILC Scheduler is too designed to work as the main
46  * loop of the GUI application. It can handle all Windows messages and
47  * it dispatches them from the scheduler, and thus makes it possible to
48  * create GUI applications. The scheduler can also handle all kinds of
49  * WIN32 handles, this includes sockets created by the SILC Net API routines,
50  * WSAEVENT handle objects created by Winsock2 routines and arbitrary
51  * WIN32 HANDLE objects.
52  *
53  * The SILC Scheduler supports multi-threads as well. The actual scheduler
54  * must be run in single-thread but other threads may register new tasks
55  * and unregister old tasks.  However, it is enforced that the actual
56  * task is always run in the main thread.  The scheduler is context based
57  * which makes it possible to allocate several schedulers for one application.
58  * Since the scheduler must be run in single-thread, a multi-threaded
59  * application could be created by allocating own scheduler for each of the
60  * worker threads.  Each scheduler in worker thread should be a child
61  * scheduler created from the main thread's parent schedule.
62  *
63  ***/
64
65 #ifndef SILCSCHEDULE_H
66 #define SILCSCHEDULE_H
67
68 /****s* silcutil/SilcScheduleAPI/SilcSchedule
69  *
70  * NAME
71  *
72  *    typedef struct SilcScheduleStruct *SilcSchedule;
73  *
74  * DESCRIPTION
75  *
76  *    This context is the actual Scheduler and is allocated by
77  *    the silc_schedule_init funtion.  The context is given as argument
78  *    to all silc_schedule_* functions.  It must be freed by the
79  *    silc_schedule_uninit function.
80  *
81  ***/
82 typedef struct SilcScheduleStruct *SilcSchedule;
83
84 /****s* silcutil/SilcScheduleAPI/SilcTask
85  *
86  * NAME
87  *
88  *    typedef struct SilcTaskStruct *SilcTask;
89  *
90  * DESCRIPTION
91  *
92  *    This object represents one task in the scheduler.  It is allocated
93  *    by the silc_schedule_task_add function and freed by one of the
94  *    silc_schedule_task_del* functions.
95  *
96  ***/
97 typedef struct SilcTaskStruct *SilcTask;
98
99 /****d* silcutil/SilcScheduleAPI/SilcTaskEvent
100  *
101  * NAME
102  *
103  *    typedef enum { ... } SilcTaskEvent;
104  *
105  * DESCRIPTION
106  *
107  *    SILC Task event types.  The event type indicates the occurred
108  *    event of the task.  This type will be given as argument to the
109  *    SilcTaskCallback function to indicate the event for the caller.
110  *    The SILC_TASK_READ and SILC_TASK_WRITE may be set by the caller
111  *    of the silc_schedule_set_listen_fd, if the caller needs to control
112  *    the events for the task. The SILC_TASK_EXPIRE is set always only
113  *    by the scheduler when timeout expires for timeout task.  The
114  *    SILC_TASK_INTERRUPT is set for signal callback.
115  *
116  * SOURCE
117  */
118 typedef enum {
119   SILC_TASK_READ         = 0x0001,               /* Reading */
120   SILC_TASK_WRITE        = 0x0002,               /* Writing */
121   SILC_TASK_EXPIRE       = 0x0004,               /* Timeout */
122   SILC_TASK_INTERRUPT    = 0x0008,               /* Signal */
123 } SilcTaskEvent;
124 /***/
125
126 /****f* silcutil/SilcScheduleAPI/SilcTaskCallback
127  *
128  * SYNOPSIS
129  *
130  *    typedef void (*SilcTaskCallback)(SilcSchedule schedule,
131  *                                     void *app_context,
132  *                                     SilcTaskEvent type, SilcUInt32 fd,
133  *                                     void *context);
134  *
135  * DESCRIPTION
136  *
137  *    The task callback function.  This function will be called by the
138  *    scheduler when some event of the task is performed.  For example,
139  *    when data is available from the connection this will be called.
140  *
141  *    The `schedule' is the scheduler context, the `type' is the indicated
142  *    event, the `fd' is the file descriptor of the task and the `context'
143  *    is a caller specified context. If multiple events occurred this
144  *    callback is called separately for all events.  The `app_context'
145  *    is application specific context that was given as argument to the
146  *    silc_schedule_init function.  If the task is timeout task then `fd'
147  *    is zero (0).
148  *
149  *    To specify task callback function in the application using the
150  *    SILC_TASK_CALLBACK macro is recommended.
151  *
152  *    The callback should not perform lenghty or blocking operations as
153  *    this would also block all other waiting tasks.  The task callback
154  *    should either handle the operation fast or issue an asynchronous
155  *    call (like to register 0 timeout task) to handle it later.
156  *
157  ***/
158 typedef void (*SilcTaskCallback)(SilcSchedule schedule, void *app_context,
159                                  SilcTaskEvent type, SilcUInt32 fd,
160                                  void *context);
161
162 /****f* silcutil/SilcScheduleAPI/SilcTaskEventCallback
163  *
164  * SYNOPSIS
165  *
166  *    typedef void (*SilcTaskEventCallback)(SilcSchedule schedule,
167  *                                          void *app_context,
168  *                                          SilcTask task, void *context,
169  *                                          va_list va);
170  *
171  * DESCRIPTION
172  *
173  *    Task callback for event tasks added with silc_schedule_task_add_event.
174  *    The callback of this type is called when an event task is signalled.
175  *    The signal is delivered to all that have connected to the event.
176  *
177  *    The `task' is the event task.  The `context' is the context given as
178  *    argument to silc_schedule_event_connect.  The `schedule' is the
179  *    scheduler given as argument to silc_schedule_event_connect.
180  *
181  *    If FALSE is returned in this callback function the signal delivery to
182  *    other connected entities is stopped.  Normally, TRUE is returned.
183  *    If the `task' is deleted in this callback, the signal delivery is also
184  *    stopped.
185  *
186  *    To specify task event callback function in the application using the
187  *    SILC_TASK_EVENT_CALLBACK macro is recommended.
188  *
189  ***/
190 typedef SilcBool (*SilcTaskEventCallback)(SilcSchedule schedule,
191                                           void *app_context,
192                                           SilcTask task, void *context,
193                                           va_list va);
194
195 /****f* silcutil/SilcScheduleAPI/SilcTaskNotifyCb
196  *
197  * SYNOPSIS
198  *
199  *    typedef void (*SilcTaskNotifyCb)(SilcSchedule schedule,
200  *                                     SilcBool added, SilcTask task,
201  *                                     SilcBool fd_task, SilcUInt32 fd,
202  *                                     SilcTaskEvent event,
203  *                                     long seconds, long useconds,
204  *                                     void *context);
205  *
206  * DESCRIPTION
207  *
208  *    Task notify callback.  Callback of this type can be set to scheduler
209  *    by calling silc_schedule_set_notify and will be called whenever new
210  *    task is added or old task is removed.  If `added' is TRUE then `task'
211  *    is added to scheduler.  If `added' is FALSE then `task' will be removed
212  *    from the scheduler.  If `fd_task' is TRUE the `task' is file descriptor
213  *    task and has `fd' is its file descriptor.  If `fd_task' is FALSE then
214  *    the task is timeout task and `seconds' and `useconds' specify the
215  *    timeout.  The `context' is the context given to silc_schedule_set_notify.
216  *
217  * NOTES
218  *
219  *    The `schedule' is locked while this callback is called.  This means that
220  *    new tasks cannot be added or removed inside this callback.
221  *
222  *    When timeout task expires this callback is not called.  This is called
223  *    only when task is explicitly deleted from the scheduler.  Note that,
224  *    when timeout task expires it is removed from the scheduler and `task'
225  *    will become invalid.
226  *
227  *    If fd task changes its events, this will be called as if it was a new
228  *    task with different `event' mask.
229  *
230  ***/
231 typedef void (*SilcTaskNotifyCb)(SilcSchedule schedule,
232                                  SilcBool added, SilcTask task,
233                                  SilcBool fd_task, SilcUInt32 fd,
234                                  SilcTaskEvent event,
235                                  long seconds, long useconds,
236                                  void *app_context);
237
238 /* Macros */
239
240 /****d* silcutil/SilcScheduleAPI/SILC_ALL_TASKS
241  *
242  * NAME
243  *
244  *    #define SILC_ALL_TASKS ...
245  *
246  * DESCRIPTION
247  *
248  *    Marks for all tasks in the scheduler. This can be passed to
249  *    silc_schedule_task_del function to delete all tasks at once.
250  *
251  * SOURCE
252  */
253 #define SILC_ALL_TASKS ((SilcTask)1)
254 /***/
255
256 /****d* silcutil/SilcScheduleAPI/SILC_TASK_CALLBACK
257  *
258  * NAME
259  *
260  *    #define SILC_TASK_CALLBACK ...
261  *
262  * DESCRIPTION
263  *
264  *    Generic macro to declare task callback functions. This defines a
265  *    function with name `func' as a task callback function.
266  *
267  * SOURCE
268  */
269 #define SILC_TASK_CALLBACK(func)                                        \
270 void func(SilcSchedule schedule, void *app_context, SilcTaskEvent type, \
271           SilcUInt32 fd, void *context)
272 /***/
273
274 /****d* silcutil/SilcScheduleAPI/SILC_TASK_EVENT_CALLBACK
275  *
276  * NAME
277  *
278  *    #define SILC_TASK_EVENT_CALLBACK ...
279  *
280  * DESCRIPTION
281  *
282  *    Generic macro to declare event task callback functions. This defines a
283  *    function with name `func' as a event task callback function.
284  *
285  * SOURCE
286  */
287 #define SILC_TASK_EVENT_CALLBACK(func)                                  \
288 SilcBool func(SilcSchedule schedule, void *app_context,                 \
289               SilcTask task, void *context, va_list va)
290
291 /***/
292
293 /* Prototypes */
294
295 #include "silcschedule_i.h"
296
297 /****f* silcutil/SilcScheduleAPI/silc_schedule_init
298  *
299  * SYNOPSIS
300  *
301  *    SilcSchedule silc_schedule_init(int max_tasks, void *app_context,
302  *                                    SilcStack stack, SilcSchedule parent);
303  *
304  * DESCRIPTION
305  *
306  *    Initializes the scheduler. This returns the scheduler context or NULL
307  *    on error.  The `app_context' is application specific context that is
308  *    delivered to all task callbacks. The caller must free that context.
309  *
310  *    The `max_tasks' is the maximum number of file descriptor and socket
311  *    tasks in the scheduler.  Set value to 0 to use default.  Operating
312  *    system will enforce the final limit.  On some operating systems the
313  *    limit can be significantly increased when this function is called in
314  *    priviliged mode (as super user).
315  *
316  *    If `parent' is non-NULL it will be the parent of the new scheduler.
317  *    If it is NULL this will create a new parent scheduler.  If `parent'
318  *    is already a child scheduler, this will create a new child to the
319  *    child's parent.  Even if `parent' is non-NULL the new child scheduler
320  *    is still independent scheduler and will run independently of its
321  *    parent.  However, each child and parent will share event tasks
322  *    added with silc_schedule_task_add_event.
323  *
324  *    If `stack' is non-NULL all memory allocation for the scheduler is done
325  *    from the `stack'.  Scheduler's stack may be retrieved by calling
326  *    silc_schedule_get_stack.  A stack is created for scheduler always even
327  *    if `stack' is NULL.  If it is non-NULL the created stack is a child
328  *    stack using `stack' as its parent.  This means that memory allocated
329  *    by the scheduler will be returned to the `stack' when scheduler is
330  *    destroyed.
331  *
332  ***/
333 SilcSchedule silc_schedule_init(int max_tasks, void *app_context,
334                                 SilcStack stack, SilcSchedule parent);
335
336 /****f* silcutil/SilcScheduleAPI/silc_schedule_uninit
337  *
338  * SYNOPSIS
339  *
340  *    SilcBool silc_schedule_uninit(SilcSchedule schedule);
341  *
342  * DESCRIPTION
343  *
344  *    Uninitializes the scheduler. This is called when the program is ready
345  *    to end. This removes all tasks from the scheduler. Returns FALSE if the
346  *    scheduler could not be uninitialized. This happens when the scheduler
347  *    is still valid and silc_schedule_stop has not been called.
348  *
349  *    If SilcStack was given to silc_schedule_init all memory allocated
350  *    during the life time of the scheduler will be returned back to the
351  *    given stack.
352  *
353  ***/
354 SilcBool silc_schedule_uninit(SilcSchedule schedule);
355
356 /****f* silcutil/SilcScheduleAPI/silc_schedule_stop
357  *
358  * SYNOPSIS
359  *
360  *    void silc_schedule_stop(SilcSchedule schedule);
361  *
362  * DESCRIPTION
363  *
364  *    Stops the scheduler even if it is not supposed to be stopped yet.
365  *    After calling this, one must call silc_schedule_uninit (after the
366  *    silc_schedule has returned).  After this is called it is guaranteed
367  *    that next time the scheduler enters the main loop it will be stopped.
368  *    However, untill it enters the main loop it will not detect that
369  *    it is stopped for example if this is called from another thread.
370  *
371  ***/
372 void silc_schedule_stop(SilcSchedule schedule);
373
374 /****f* silcutil/SilcScheduleAPI/silc_schedule
375  *
376  * SYNOPSIS
377  *
378  *    void silc_schedule(SilcSchedule schedule);
379  *
380  * DESCRIPTION
381  *
382  *    The SILC scheduler.  The program will run inside this function.
383  *    When this returns the program is to be ended.  Before this function
384  *    can be called, one must call silc_schedule_init function.
385  *
386  * NOTES
387  *
388  *    On Windows this will block the calling thread but will continue
389  *    to dispatch window messages, and thus can be used as the main loop
390  *    of the program.
391  *
392  *    On Symbian this will block the calling thread.  The Symbian Active
393  *    Scheduler must be running before calling this function.
394  *
395  ***/
396 void silc_schedule(SilcSchedule schedule);
397
398 /****f* silcutil/SilcScheduleAPI/silc_schedule_one
399  *
400  * SYNOPSIS
401  *
402  *    SilcBool silc_schedule_one(SilcSchedule schedule, int timeout_usecs);
403  *
404  * DESCRIPTION
405  *
406  *    Same as the silc_schedule but runs the scheduler only one round
407  *    and then returns.  This function is handy when the SILC scheduler
408  *    is used inside some other external scheduler, for example.  If
409  *    the `timeout_usecs' is non-negative a timeout will be added to the
410  *    scheduler.  The function will not return in this timeout unless
411  *    some other event occurs.
412  *
413  *    Typically this would be called from a timeout or idle task
414  *    periodically (typically from 5-50 ms) to schedule SILC tasks.  In
415  *    this case the `timeout_usecs' is usually 0 to make the function
416  *    return immediately.
417  *
418  ***/
419 SilcBool silc_schedule_one(SilcSchedule schedule, int timeout_usecs);
420
421 /****f* silcutil/SilcScheduleAPI/silc_schedule_wakeup
422  *
423  * SYNOPSIS
424  *
425  *    void silc_schedule_wakeup(SilcSchedule schedule);
426  *
427  * DESCRIPTION
428  *
429  *    Wakes up the scheduler. This is may be used in multi-threaded
430  *    environments where threads may add new tasks or remove old tasks
431  *    from the scheduler. This is called to wake up the scheduler in the
432  *    main thread so that it detects the changes in the scheduler.
433  *    If threads support is not compiled in this function has no effect.
434  *
435  ***/
436 void silc_schedule_wakeup(SilcSchedule schedule);
437
438 /****f* silcutil/SilcScheduleAPI/silc_schedule_get_parent
439  *
440  * SYNOPSIS
441  *
442  *    SilcSchedule silc_schedule_get_parent(SilcSchedule schedule);
443  *
444  * DESCRIPTION
445  *
446  *    Returns the parent scheduler of the `schedule'.  Never returns NULL.
447  *
448  ***/
449 SilcSchedule silc_schedule_get_parent(SilcSchedule schedule);
450
451 /****f* silcutil/SilcScheduleAPI/silc_schedule_get_context
452  *
453  * SYNOPSIS
454  *
455  *    void *silc_schedule_get_context(SilcSchedule schedule);
456  *
457  * DESCRIPTION
458  *
459  *    Returns the application specific context that was saved into the
460  *    scheduler in silc_schedule_init function.  The context is also
461  *    returned to application in the SilcTaskCallback, but this function
462  *    may be used to get it as well if needed.
463  *
464  ***/
465 void *silc_schedule_get_context(SilcSchedule schedule);
466
467 /****f* silcutil/SilcScheduleAPI/silc_schedule_get_stack
468  *
469  * SYNOPSIS
470  *
471  *    SilcStack silc_schedule_get_stack(SilcSchedule schedule);
472  *
473  * DESCRIPTION
474  *
475  *    Returns the stack of the `schedule'.  If it is used to make memory
476  *    allocations outside the scheduler, it is recommended that a new
477  *    child stack is created by using the returned stack as a parent and
478  *    using the child stack to make the memory allocations.
479  *
480  ***/
481 SilcStack silc_schedule_get_stack(SilcSchedule schedule);
482
483 /****f* silcutil/SilcScheduleAPI/silc_schedule_set_notify
484  *
485  * SYNOPSIS
486  *
487  *    void silc_schedule_set_notify(SilcSchedule schedule,
488  *                                  SilcTaskNotifyCb notify, void *context);
489  *
490  * DESCRIPTION
491  *
492  *    Set notify callback to scheduler.  The `notify' will be called whenever
493  *    task is added to or deleted from scheduler.
494  *
495  ***/
496 void silc_schedule_set_notify(SilcSchedule schedule,
497                               SilcTaskNotifyCb notify, void *context);
498
499 /****f* silcutil/SilcScheduleAPI/silc_schedule_set_global
500  *
501  * SYNOPSIS
502  *
503  *    void silc_schedule_set_global(SilcSchedule schedule);
504  *
505  * DESCRIPTION
506  *
507  *    Sets global SilcSchedule `schedule' that can be retrieved at any time
508  *    by using silc_schedule_get_global.  The global scheduler is global only
509  *    to the current thread.  Each thread can have their own global scheduler.
510  *    If each thread must have global scheduler this must be called in each
511  *    thread.  If the global scheduler has been set already, new call will
512  *    replace the old one.
513  *
514  *    This routine is provided only as a convenience function to store
515  *    program's or thread's scheduler in one global place.  It is not mandatory
516  *    to call this function in order to use SilcSchedule.
517  *
518  *    Many routines that require SilcSchedule as an argument will call
519  *    silc_schedule_get_global if the scheduler is not provided to try to
520  *    get global scheduler.  Almost all routines in SilcSchedule API will call
521  *    silc_schedule_get_global if the SilcSchedule is not provided as argument.
522  *
523  ***/
524 void silc_schedule_set_global(SilcSchedule schedule);
525
526 /****f* silcutil/SilcScheduleAPI/silc_schedule_get_global
527  *
528  * SYNOPSIS
529  *
530  *    SilcSchedule silc_schedule_get_global(void);
531  *
532  * DESCRIPTION
533  *
534  *    Returns the thread's global scheduler that was set by calling
535  *    silc_schedule_set_global or NULL if global scheduler has not been set.
536  *
537  ***/
538 SilcSchedule silc_schedule_get_global(void);
539
540 /****f* silcutil/SilcScheduleAPI/silc_schedule_task_add_fd
541  *
542  * SYNOPSIS
543  *
544  *    SilcTask
545  *    silc_schedule_task_add_fd(SilcSchedule schedule, SilcUInt32 fd,
546  *                              SilcTaskCallback callback, void *context);
547  *
548  * DESCRIPTION
549  *
550  *    Add file descriptor task to scheduler.  The `fd' may be either real
551  *    file descriptor, socket or on some platforms an opaque file descriptor
552  *    handle.  To receive events for the file descriptor set the correct
553  *    request events with silc_schedule_set_listen_fd function.
554  *
555  *    The task will be initially set for SILC_TASK_READ events.  Setting that
556  *    event immediately after this call returns is not necessary.
557  *
558  *    This returns the new task or NULL on error.  If a task with `fd' has
559  *    already been added this will return the existing task pointer.
560  *
561  *    If `schedule' is NULL this will call silc_schedule_get_global to try to
562  *    get global scheduler.
563  *
564  ***/
565 #define silc_schedule_task_add_fd(schedule, fd, callback, context)      \
566   silc_schedule_task_add(schedule, fd, callback, context, 0, 0, SILC_TASK_FD)
567
568 /****f* silcutil/SilcScheduleAPI/silc_schedule_task_add_timeout
569  *
570  * SYNOPSIS
571  *
572  *    SilcTask
573  *    silc_schedule_task_add_timeout(SilcSchedule schedule,
574  *                                   SilcTaskCallback callback, void *context,
575  *                                   long seconds, long useconds);
576  *
577  * DESCRIPTION
578  *
579  *    Add timeout task to scheduler.  The `callback' will be called once
580  *    the specified timeout has elapsed.  The task will be removed from the
581  *    scheduler automatically once the task expires.  The event returned
582  *    to the `callback' is SILC_TASK_EXPIRE.  A task added with zero (0)
583  *    timeout will be executed immediately next time tasks are scheduled.
584  *
585  *    If `schedule' is NULL this will call silc_schedule_get_global to try to
586  *    get global scheduler.
587  *
588  ***/
589 #define silc_schedule_task_add_timeout(schedule, callback, context, s, u) \
590   silc_schedule_task_add(schedule, 0, callback, context, s, u,          \
591                          SILC_TASK_TIMEOUT)
592
593 /****f* silcutil/SilcScheduleAPI/silc_schedule_task_add_signal
594  *
595  * SYNOPSIS
596  *
597  *    SilcTask
598  *    silc_schedule_task_add_signal(SilcSchedule schedule, int signal,
599  *                                  SilcTaskCallback callback, void *context);
600  *
601  * DESCRIPTION
602  *
603  *    Add platform specific process signal handler to scheduler.  On Unix
604  *    systems the `signal' is one of the signal specified in signal(7).  On
605  *    other platforms this function may not be available at all, and has no
606  *    effect when called.  The event delivered to the `callback' is
607  *    SILC_TASK_INTERRUPT.
608  *
609  *    If `schedule' is NULL this will call silc_schedule_get_global to try to
610  *    get global scheduler.
611  *
612  * NOTES
613  *
614  *    One signal may be registered only one callback.  Adding second callback
615  *    for signal that already has one will fail.
616  *
617  *    This function always returns NULL.  To remove signal from scheduler by
618  *    the signal call silc_schedule_task_del_by_fd.
619  *
620  ***/
621 #define silc_schedule_task_add_signal(schedule, sig, callback, context) \
622   silc_schedule_task_add(schedule, sig, callback, context, 0, 0,        \
623                          SILC_TASK_SIGNAL)
624
625 /****f* silcutil/SilcScheduleAPI/silc_schedule_task_add_event
626  *
627  * SYNOPSIS
628  *
629  *    SilcTask
630  *    silc_schedule_task_add_event(SilcSchedule schedule,
631  *                                 const char *event, ...);
632  *
633  * DESCRIPTION
634  *
635  *    Adds an event task to scheduler.  These tasks are asynchronous events
636  *    that one or more receivers may connect to and receive information or
637  *    data when the event is signalled.  Event tasks are fast and may be
638  *    used to efficiently deliver events and data to multiple receivers.  The
639  *    `event' is the name of the event, and can be used to connect to the
640  *    event and to signal it.
641  *
642  *    The events are global among the `scheduler', its parent scheduler and
643  *    any of its child schedulers.  It does not matter to which scheduler
644  *    event is added to, connected to or signalled.  Signal will reach any
645  *    connected entity, as long as it is the parent or one of the fellow
646  *    children of `schedule'.
647  *
648  *    To connect to an event call silc_schedule_event_connect.
649  *    To disconnect from event call silc_schedule_event_disconnect.
650  *    To signal event call silc_schedule_event_signal.
651  *    To delete event task call silc_schedule_task_del or
652  *    silc_schedule_task_del_event.
653  *
654  *    The variable argument list is used to describe the arguments of the
655  *    event.  The variable arguments are a list of zero or more SilcParam
656  *    values.  This function returns the event task context or NULL on error.
657  *
658  * EXAMPLE
659  *
660  *    // Register 'connected' event
661  *    silc_schedule_task_add_event(schedule, "connected",
662  *                                 SILC_PARAM_UINT32,
663  *                                 SILC_PARAM_BUFFER);
664  *
665  *    // Connect to 'connected' event
666  *    silc_schedule_event_connect(schedule, "connected", NULL,
667  *                                connected_cb, ctx);
668  *
669  *    // Signal 'connected' event
670  *    silc_schedule_event_signal(schedule, "connected", NULL, integer, buf);
671  *
672  *    // 'connected' event handler
673  *    SILC_TASK_CALLBACK(connected_cb)
674  *    {
675  *      FooCtx ctx = context;
676  *      SilcUInt32 integer;
677  *      SilcBuffer buf;
678  *
679  *      integer = va_arg(va, SilcUInt32);
680  *      buf = va_arg(va, SilcBuffer);
681  *      ...
682  *    }
683  *
684  ***/
685 SilcTask silc_schedule_task_add_event(SilcSchedule schedule,
686                                       const char *event, ...);
687
688 /****f* silcutil/SilcScheduleAPI/silc_schedule_task_del
689  *
690  * SYNOPSIS
691  *
692  *    SilcBool silc_schedule_task_del(SilcSchedule schedule, SilcTask task);
693  *
694  * DESCRIPTION
695  *
696  *    Deletes the `task' from the scheduler indicated by the `schedule'.
697  *    After deleting the task it is guaranteed that the task callback
698  *    will not be called. If the `task' is SILC_ALL_TASKS then all
699  *    tasks is removed from the scheduler.  Returns always TRUE.
700  *
701  *    It is safe to call this function in any place. Tasks may be removed
702  *    in task callbacks (including in the task's own task callback) and
703  *    in multi-threaded environment in other threads as well.
704  *
705  *    If `schedule' is NULL this will call silc_schedule_get_global to try to
706  *    get global scheduler.
707  *
708  ***/
709 SilcBool silc_schedule_task_del(SilcSchedule schedule, SilcTask task);
710
711 /****f* silcutil/SilcScheduleAPI/silc_schedule_task_del_by_fd
712  *
713  * SYNOPSIS
714  *
715  *    SilcBool silc_schedule_task_del_by_fd(SilcSchedule schedule,
716  *                                          SilcUInt32 fd);
717  *
718  * DESCRIPTION
719  *
720  *    Deletes a task from the scheduler by the specified `fd'.  Returns
721  *    FALSE if such fd task does not exist.
722  *
723  *    It is safe to call this function in any place. Tasks may be removed
724  *    in task callbacks (including in the task's own task callback) and
725  *    in multi-threaded environment in other threads as well.
726  *
727  *    If `schedule' is NULL this will call silc_schedule_get_global to try to
728  *    get global scheduler.
729  *
730  ***/
731 SilcBool silc_schedule_task_del_by_fd(SilcSchedule schedule, SilcUInt32 fd);
732
733 /****f* silcutil/SilcScheduleAPI/silc_schedule_task_del_by_callback
734  *
735  * SYNOPSIS
736  *
737  *    SilcBool silc_schedule_task_del_by_callback(SilcSchedule schedule,
738  *                                                SilcTaskCallback callback);
739  *
740  * DESCRIPTION
741  *
742  *    Deletes a task from the scheduler by the specified `callback' task
743  *    callback function.  Returns FALSE if such task with such callback
744  *    does not exist.
745  *
746  *    It is safe to call this function in any place. Tasks may be removed
747  *    in task callbacks (including in the task's own task callback) and
748  *    in multi-threaded environment in other threads as well.
749  *
750  *    If `schedule' is NULL this will call silc_schedule_get_global to try to
751  *    get global scheduler.
752  *
753  ***/
754 SilcBool silc_schedule_task_del_by_callback(SilcSchedule schedule,
755                                             SilcTaskCallback callback);
756
757 /****f* silcutil/SilcScheduleAPI/silc_schedule_task_del_by_context
758  *
759  * SYNOPSIS
760  *
761  *    SilcBool silc_schedule_task_del_by_context(SilcSchedule schedule,
762  *                                               void *context);
763  *
764  * DESCRIPTION
765  *
766  *    Deletes a task from the scheduler by the specified `context'.  Returns
767  *    FALSE if such task with such context does not exist.
768  *
769  *    It is safe to call this function in any place. Tasks may be removed
770  *    in task callbacks (including in the task's own task callback) and
771  *    in multi-threaded environment in other threads as well.
772  *
773  *    If `schedule' is NULL this will call silc_schedule_get_global to try to
774  *    get global scheduler.
775  *
776  ***/
777 SilcBool silc_schedule_task_del_by_context(SilcSchedule schedule,
778                                            void *context);
779
780 /****f* silcutil/SilcScheduleAPI/silc_schedule_task_del_by_all
781  *
782  * SYNOPSIS
783  *
784  *    SilcBool silc_schedule_task_del_by_all(SilcSchedule schedule, int fd,
785  *                                           SilcTaskCallback callback,
786  *                                           void *context);
787  *
788  * DESCRIPTION
789  *
790  *    Deletes a task from the scheduler by the specified `fd', `callback'
791  *    and `context'.  Returns FALSE if such task does not exist.
792  *
793  *    It is safe to call this function in any place. Tasks may be removed
794  *    in task callbacks (including in the task's own task callback) and
795  *    in multi-threaded environment in other threads as well.
796  *
797  *    If `schedule' is NULL this will call silc_schedule_get_global to try to
798  *    get global scheduler.
799  *
800  ***/
801 SilcBool silc_schedule_task_del_by_all(SilcSchedule schedule, int fd,
802                                        SilcTaskCallback callback,
803                                        void *context);
804
805 /****f* silcutil/SilcScheduleAPI/silc_schedule_task_del_event
806  *
807  * SYNOPSIS
808  *
809  *    void silc_schedule_task_del_event(SilcSchedule schedule,
810  *                                      const char *event);
811  *
812  * DESCRIPTION
813  *
814  *    Deletes event task by the event name `event'.  Returns FALSE if the
815  *    event does not exist.  Events can be deleted by calling the
816  *    silc_schedule_task_del also.
817  *
818  *    If `schedule' is NULL this will call silc_schedule_get_global to try to
819  *    get global scheduler.
820  *
821  ***/
822 SilcBool silc_schedule_task_del_event(SilcSchedule schedule,
823                                       const char *event);
824
825 /****f* silcutil/SilcScheduleAPI/silc_schedule_set_listen_fd
826  *
827  * SYNOPSIS
828  *
829  *    SilcBool silc_schedule_set_listen_fd(SilcSchedule schedule,
830  *                                         SilcUInt32 fd,
831  *                                         SilcTaskEvent mask,
832  *                                         SilcBool send_events);
833  *
834  * DESCRIPTION
835  *
836  *    Sets a file descriptor `fd' to be listened by the scheduler for
837  *    `mask' events.  To tell scheduler not to listen anymore for this
838  *    file descriptor call the silc_schedule_unset_listen_fd function.
839  *    When new task is created with silc_schedule_task_add the event
840  *    for the task's fd is initially set to SILC_TASK_READ. If you need
841  *    to control the task's fd's events you must call this function
842  *    whenever you need to change the events. This can be called multiple
843  *    times to change the events.
844  *
845  *    If the `send_events' is TRUE then this function sends the events
846  *    in `mask' to the application.  If FALSE then they are sent only
847  *    after the event occurs in reality.  In normal cases the `send_events'
848  *    is set to FALSE.
849  *
850  *    If `schedule' is NULL this will call silc_schedule_get_global to try to
851  *    get global scheduler.
852  *
853  *    Returns FALSE if the operation could not performed and TRUE if it
854  *    was a success.
855  *
856  ***/
857 SilcBool silc_schedule_set_listen_fd(SilcSchedule schedule, SilcUInt32 fd,
858                                      SilcTaskEvent mask, SilcBool send_events);
859
860 /****f* silcutil/SilcScheduleAPI/silc_schedule_get_fd_events
861  *
862  * SYNOPSIS
863  *
864  *    SilcTaskEvent silc_schedule_get_fd_events(SilcSchedule schedule,
865  *                                              SilcUInt32 fd);
866  *
867  * DESCRIPTION
868  *
869  *    Returns the file descriptor `fd' current requested events mask,
870  *    or 0 on error.
871  *
872  *    If `schedule' is NULL this will call silc_schedule_get_global to try to
873  *    get global scheduler.
874  *
875  ***/
876 SilcTaskEvent silc_schedule_get_fd_events(SilcSchedule schedule,
877                                           SilcUInt32 fd);
878
879 /****f* silcutil/SilcScheduleAPI/silc_schedule_unset_listen_fd
880  *
881  * SYNOPSIS
882  *
883  *    void silc_schedule_unset_listen_fd(SilcSchedule schedule, SilcUInt32 fd);
884  *
885  * DESCRIPTION
886  *
887  *    Tells the scheduler not to listen anymore for the specified
888  *    file descriptor `fd'. No events will be detected for the `fd'
889  *    after calling this function.
890  *
891  *    If `schedule' is NULL this will call silc_schedule_get_global to try to
892  *    get global scheduler.
893  *
894  ***/
895 void silc_schedule_unset_listen_fd(SilcSchedule schedule, SilcUInt32 fd);
896
897 /****f* silcutil/SilcScheduleAPI/silc_schedule_event_connect
898  *
899  * SYNOPSIS
900  *
901  *    SilcBool silc_schedule_event_connect(SilcSchedule schedule,
902  *                                         const char *event, SilcTask task,
903  *                                         SilcTaskEventCallback callback,
904  *                                         void *context);
905  *
906  * DESCRIPTION
907  *
908  *    Connects to an event task.  The `event' or `task' must be non-NULL.
909  *    If `event' is non-NULL it is the name of the event to connect to.  If
910  *    the `task' is non-NULL it is the event task to connect to.  The event
911  *    SilcTask pointer is returned by silc_schedule_task_add_event when the
912  *    even is added to scheduler.
913  *
914  *    The `callback' with `context' and with `schedule' are called when the
915  *    even task is signalled with silc_schedule_event_signal.
916  *
917  *    Returns FALSE on error or if the `callback' with `context' has already
918  *    been connected.  Otherwise, returns TRUE.
919  *
920  * EXAMPLE
921  *
922  *    silc_schedule_event_connect(schedule, "foo event", NULL,
923  *                                foo_signal_callback, foo_context);
924  *
925  ***/
926 SilcBool silc_schedule_event_connect(SilcSchedule schedule,
927                                      const char *event, SilcTask task,
928                                      SilcTaskEventCallback callback,
929                                      void *context);
930
931 /****f* silcutil/SilcScheduleAPI/silc_schedule_event_disconnect
932  *
933  * SYNOPSIS
934  *
935  *    SilcBool silc_schedule_event_disconnect(SilcSchedule schedule,
936  *                                            const char *event, SilcTask task,
937  *                                            SilcTaskEventCallback callback,
938  *                                            void *context);
939  *
940  * DESCRIPTION
941  *
942  *    Disconnects the `callback' and `context' from an event task.  The `event'
943  *    or `task' must be non-NULL.  If `event' is non-NULL it is the name of
944  *    the event.  If `task' is non-NULL it is the event task.
945  *
946  *    Returns FALSE on error or if the `callback' with `context' has not been
947  *    connected.  Otherwise, returns TRUE.
948  *
949  ***/
950 SilcBool silc_schedule_event_disconnect(SilcSchedule schedule,
951                                         const char *event, SilcTask task,
952                                         SilcTaskEventCallback callback,
953                                         void *context);
954
955 /****f* silcutil/SilcScheduleAPI/silc_schedule_event_signal
956  *
957  * SYNOPSIS
958  *
959  *    SilcBool silc_schedule_event_signal(SilcSchedule schedule,
960  *                                        const char *event,
961  *                                        SilcTask task, ...);
962  *
963  * DESCRIPTION
964  *
965  *    Signals an event task.  The `event' or `task' must be non-NULL.  If
966  *    `event' is non-NULL it is the name of the event to signal.  If the `task'
967  *    is non-NULL it is the task to be signalled.  It is marginally faster
968  *    to use the `task' pointer directly instead of `event' to send the signal.
969  *
970  *    The variable arguments are the arguments to be sent in the signal to
971  *    the connected entities.  The silc_schedule_task_add_event defines what
972  *    arguments must be sent to each signal.
973  *
974  *    Signal delivery is synchronous; the signal is delivered inside this
975  *    function.  If a receiver was originally in another thread, the signal
976  *    is delivered in the thread where this function is called.  This means
977  *    that concurrency control (locking) is required if the application uses
978  *    events in multiple threads.
979  *
980  * EXAMPLE
981  *
982  *    silc_schedule_event_signal(schedule, "foo event", NULL, intarg, buffer);
983  *
984  ***/
985 SilcBool silc_schedule_event_signal(SilcSchedule schedule, const char *event,
986                                     SilcTask task, ...);
987
988 #endif