1 /****h* silcutil/silcschedule.h
9 * Author: Pekka Riikonen <priikone@silcnet.org>
11 * Copyright (C) 1998 - 2001 Pekka Riikonen
13 * This program is free software; you can redistribute it and/or modify
14 * it under the terms of the GNU General Public License as published by
15 * the Free Software Foundation; either version 2 of the License, or
16 * (at your option) any later version.
18 * This program is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU General Public License for more details.
25 * The SILC Scheduler is the heart of any application. The scheduler provides
26 * the application's main loop that can handle incoming data, outgoing data,
27 * timeouts and dispatch different kind of tasks.
29 * The SILC Scheduler supports file descriptor based tasks, timeout tasks
30 * and generic tasks. File descriptor tasks are tasks that perform some
31 * operation over the specified file descriptor. These include network
32 * connections, for example. The timeout tasks are timeouts that are executed
33 * after the specified timeout has elapsed. The generic tasks are tasks that
34 * apply to all registered file descriptors thus providing one task that
35 * applies to many independent connections.
37 * The SILC Scheduler is designed to be the sole main loop of the application
38 * so that the application does not need any other main loop. However,
39 * SILC Scheduler does support running the scheduler only once, so that the
40 * scheduler does not block, and thus providing a possiblity that some
41 * external main loop is run over the SILC Scheduler. However, these
42 * applications are considered to be special cases.
44 * Typical application first initializes the scheduler and then registers
45 * the very first tasks to the scheduler and then run the scheduler. After
46 * the scheduler's run function returns the application is considered to be
49 * On WIN32 systems the SILC Scheduler is too designed to work as the main
50 * loop of the GUI application. It can handle all Windows messages and
51 * it dispatches them from the scheduler, and thus makes it possible to
52 * create GUI applications. The scheduler can also handle all kinds of
53 * WIN32 handles, this includes sockets created by the SILC Net API routines,
54 * WSAEVENT handle objects created by Winsock2 routines and arbitrary
55 * WIN32 HANDLE objects.
57 * The SILC Scheduler supports multi-threads as well. The actual scheduler
58 * must be run in single-thread but other threads may register new tasks
59 * and unregister old tasks. However, it is enforced that the actual
60 * task is always run in the main thread. The scheduler is context based
61 * which makes it possible to allocate several schedulers for one application.
62 * Since the scheduler must be run in single-thread, a multi-threaded
63 * application could be created by allocating own scheduler for each of the
68 #ifndef SILCSCHEDULE_H
69 #define SILCSCHEDULE_H
71 /****s* silcutil/SilcScheduleAPI/SilcSchedule
75 * typedef struct SilcScheduleStruct *SilcSchedule;
79 * This context is the actual Scheduler and is allocated by
80 * the silc_schedule_init funtion. The context is given as argument
81 * to all silc_schedule_* functions. It must be freed by the
82 * silc_schedule_uninit function.
85 typedef struct SilcScheduleStruct *SilcSchedule;
87 /****s* silcutil/SilcScheduleAPI/SilcTask
91 * typedef struct SilcTaskStruct *SilcTask;
95 * This object represents one task in the scheduler. It is allocated
96 * by the silc_schedule_task_add function and freed by one of the
97 * silc_schedule_task_del* functions.
100 typedef struct SilcTaskStruct *SilcTask;
102 /****d* silcutil/SilcScheduleAPI/SilcTaskType
106 * typedef enum { ... } SilcTaskType;
110 * SILC has three types of tasks, non-timeout tasks (tasks that perform
111 * over file descriptors), timeout tasks and generic tasks (tasks that
112 * apply to every file descriptor). This type is sent as argument for the
113 * task registering function, silc_schedule_task_add.
118 /* File descriptor task that performs some event over file descriptors.
119 These tasks are for example network connections. */
122 /* Timeout tasks are tasks that are executed after the specified
123 time has elapsed. After the task is executed the task is removed
124 automatically from the scheduler. It is safe to re-register the
125 task in task callback. It is also safe to unregister a task in
126 the task callback. */
129 /* Generic tasks are non-timeout tasks and they apply to all file
130 descriptors, except to those that have explicitly registered a
131 non-timeout task. These tasks are there to make it simpler and faster
132 to execute common code that applies to all connections. These are,
133 for example, receiving packets from network and sending packets to
134 network. It doesn't make much sense to register a task that receives
135 a packet from network to every connection when you can have one task
136 that applies to all connections. This is what generic tasks are for.
137 Generic tasks are not bound to any specific file descriptor, however,
138 the correct file descriptor must be passed as argument to task
139 registering function. */
144 /****d* silcutil/SilcScheduleAPI/SilcTaskEvent
148 * typedef enum { ... } SilcTaskEvent;
152 * SILC Task event types. The event type indicates the occurred
153 * event of the task. This type will be given as argument to the
154 * SilcTaskCallback function to indicate the event for the caller.
155 * The SILC_TASK_READ and SILC_TASK_WRITE may be set by the caller
156 * of the silc_schedule_set_listen_fd, if the caller needs to control
157 * the events for the task. The SILC_TASK_EXPIRE is set always only
158 * by the scheduler when timeout expires for timeout task.
163 SILC_TASK_READ = 0x0001, /* Reading */
164 SILC_TASK_WRITE = 0x0002, /* Writing */
165 SILC_TASK_EXPIRE = 0x0004, /* Timeout */
169 /****d* silcutil/SilcScheduleAPI/SilcTaskPriority
173 * typedef enum { ... } SilcTaskPriority
177 * Task priorities. Tasks may be registered with different priorities.
178 * This type defines the different task priorities. The priorities
179 * behaves same for all type of tasks, fd tasks, timeout tasks and
185 /* Lowest priority. The task is scheduled to run after its timeout
186 has expired only and only when every other task with higher priority
187 has already been run. For non-timeout tasks this priority behaves
188 same way. Life is not fair for tasks with this priority. */
191 /* Normal priority that is used mostly in SILC. This is priority that
192 should always be used unless you specificly need some other priority.
193 The scheduler will run this task as soon as its timeout has expired.
194 For non-timeout tasks this priority behaves same way. Tasks are run
195 in FIFO (First-In-First-Out) order. */
196 SILC_TASK_PRI_NORMAL,
200 /****f* silcutil/SilcScheduleAPI/silc_schedule_init
204 * typedef void (*SilcTaskCallback)(SilcSchedule schedule,
205 * SilcTaskEvent type, uint32 fd,
210 * The task callback function. This function will be called by the
211 * scheduler when some event of the task is performed. For example,
212 * when data is available from the connection this will be called.
214 * The `schedule' is the scheduler context, the `type' is the indicated
215 * event, the `fd' is the file descriptor of the task and the `context'
216 * is a caller specified context. If multiple events occurred this
217 * callback is called separately for all events.
219 * To specify task callback function in the application using the
220 * SILC_TASK_CALLBACK and SILC_TASK_CALLBACK_GLOBAL macros is
224 typedef void (*SilcTaskCallback)(SilcSchedule schedule, SilcTaskEvent type,
225 uint32 fd, void *context);
229 /****d* silcutil/SilcScheduleAPI/SILC_ALL_TASKS
233 * #define SILC_ALL_TASKS ...
237 * Marks for all tasks in the scheduler. This can be passed to
238 * silc_schedule_task_del function to delete all tasks at once.
242 #define SILC_ALL_TASKS ((SilcTask)1)
245 /****d* silcutil/SilcScheduleAPI/SILC_TASK_CALLBACK
249 * #define SILC_TASK_CALLBACK ...
253 * Generic macro to define task callback functions. This defines a
254 * static function with name `func' as a task callback function.
258 #define SILC_TASK_CALLBACK(func) \
259 static void func(SilcSchedule schedule, SilcTaskEvent type, \
260 uint32 fd, void *context)
263 /****d* silcutil/SilcScheduleAPI/SILC_TASK_CALLBACK
267 * #define SILC_TASK_CALLBACK_GLOBAL ...
271 * Generic macro to define task callback functions. This defines a
272 * function with name `func' as a task callback function. This
273 * differs from SILC_TASK_CALLBACK in that the defined function is
278 #define SILC_TASK_CALLBACK_GLOBAL(func) \
279 void func(SilcSchedule schedule, SilcTaskEvent type, \
280 uint32 fd, void *context)
285 /****f* silcutil/SilcScheduleAPI/silc_schedule_init
289 * SilcSchedule silc_schedule_init(int max_tasks);
293 * Initializes the scheduler. This returns the scheduler context that
294 * is given as argument usually to all silc_schedule_* functions.
295 * The `max_tasks' indicates the number of maximum tasks that the
296 * scheduler can handle.
299 SilcSchedule silc_schedule_init(int max_tasks);
301 /****f* silcutil/SilcScheduleAPI/silc_schedule_uninit
305 * bool silc_schedule_uninit(SilcSchedule schedule);
309 * Uninitializes the scheduler. This is called when the program is ready
310 * to end. This removes all tasks from the scheduler. Returns FALSE if the
311 * scheduler could not be uninitialized. This happens when the scheduler
312 * is still valid and silc_schedule_stop has not been called.
315 bool silc_schedule_uninit(SilcSchedule schedule);
317 /****f* silcutil/SilcScheduleAPI/silc_schedule_stop
321 * void silc_schedule_stop(SilcSchedule schedule);
325 * Stops the scheduler even if it is not supposed to be stopped yet.
326 * After calling this, one must call silc_schedule_uninit (after the
327 * silc_schedule has returned).
330 void silc_schedule_stop(SilcSchedule schedule);
332 /****f* silcutil/SilcScheduleAPI/silc_schedule
336 * void silc_schedule(SilcSchedule schedule);
340 * The SILC scheduler. This is actually the main routine in SILC programs.
341 * When this returns the program is to be ended. Before this function can
342 * be called, one must call silc_schedule_init function.
345 void silc_schedule(SilcSchedule schedule);
347 /****f* silcutil/SilcScheduleAPI/silc_schedule
351 * bool silc_schedule_one(SilcSchedule schedule, int block);
355 * Same as the silc_schedule but runs the scheduler only one round
356 * and then returns. This function is handy when the SILC scheduler
357 * is used inside some other external scheduler, for example. If
358 * the `timeout_usecs' is non-negative a timeout will be added to the
359 * scheduler. The function will not return in this timeout unless
360 * some other event occurs.
363 bool silc_schedule_one(SilcSchedule schedule, int timeout_usecs);
365 /****f* silcutil/SilcScheduleAPI/silc_schedule_wakeup
369 * void silc_schedule_wakeup(SilcSchedule schedule);
373 * Wakes up the scheduler. This is used only in multi-threaded
374 * environments where threads may add new tasks or remove old tasks
375 * from the scheduler. This is called to wake up the scheduler in the
376 * main thread so that it detects the changes in the scheduler.
377 * If threads support is not compiled in this function has no effect.
378 * Implementation of this function may be platform specific.
381 void silc_schedule_wakeup(SilcSchedule schedule);
383 /****f* silcutil/SilcScheduleAPI/silc_schedule_task_add
387 * SilcTask silc_schedule_task_add(SilcSchedule schedule, uint32 fd,
388 * SilcTaskCallback callback,
390 * long seconds, long useconds,
392 * SilcTaskPriority priority);
396 * Registers a new task to the scheduler. This same function is used
397 * to register all types of tasks. The `type' argument tells what type
398 * of the task is. Note that when registering non-timeout tasks one
399 * should also pass 0 as timeout, as the timeout will be ignored anyway.
400 * Also, note, that one cannot register timeout task with 0 timeout.
401 * There cannot be zero timeouts, passing zero means no timeout is used
402 * for the task and SILC_TASK_FD is used as default task type in
405 * The `schedule' is the scheduler context. The `fd' is the file
406 * descriptor of the task. On WIN32 systems the `fd' is not actual
407 * file descriptor but some WIN32 event handle. On WIN32 system the `fd'
408 * may be a socket created by the SILC Net API routines, WSAEVENT object
409 * created by Winsock2 network routines or arbitrary WIN32 HANDLE object.
410 * On Unix systems the `fd' is always the real file descriptor.
412 * The `callback' is the task callback that will be called when some
413 * event occurs for this task. The `context' is sent as argument to
414 * the task `callback' function. For timeout tasks the callback is
415 * called after the specified timeout has elapsed.
417 * If the `type' is SILC_TASK_TIMEOUT then `seconds' and `useconds'
418 * may be non-zero. Otherwise they should be zero. The `priority'
419 * indicates the priority of the task.
421 * It is always safe to call this function in any place. New tasks
422 * may be added also in task callbacks, and in multi-threaded environment
423 * in other threads as well.
426 SilcTask silc_schedule_task_add(SilcSchedule schedule, uint32 fd,
427 SilcTaskCallback callback, void *context,
428 long seconds, long useconds,
430 SilcTaskPriority priority);
432 /****f* silcutil/SilcScheduleAPI/silc_schedule_task_del
436 * void silc_schedule_task_del(SilcSchedule schedule, SilcTask task);
440 * Deletes the `task' from the scheduler indicated by the `schedule'.
441 * After deleting the task it is guaranteed that the task callback
442 * will not be called. If the `task' is SILC_ALL_TASKS then all
443 * tasks is removed from the scheduler.
445 * It is safe to call this function in any place. Tasks may be removed
446 * in task callbacks (including in the task's own task callback) and
447 * in multi-threaded environment in other threads as well.
450 void silc_schedule_task_del(SilcSchedule schedule, SilcTask task);
452 /****f* silcutil/SilcScheduleAPI/silc_schedule_task_del_by_fd
456 * void silc_schedule_task_del_by_fd(SilcSchedule schedule, uint32 fd);
460 * Deletes a task from the scheduler by the specified `fd'.
462 * It is safe to call this function in any place. Tasks may be removed
463 * in task callbacks (including in the task's own task callback) and
464 * in multi-threaded environment in other threads as well.
467 void silc_schedule_task_del_by_fd(SilcSchedule schedule, uint32 fd);
469 /****f* silcutil/SilcScheduleAPI/silc_schedule_task_del_by_callback
473 * void silc_schedule_task_del_by_callback(SilcSchedule schedule,
474 * SilcTaskCallback callback);
478 * Deletes a task from the scheduler by the specified `callback' task
481 * It is safe to call this function in any place. Tasks may be removed
482 * in task callbacks (including in the task's own task callback) and
483 * in multi-threaded environment in other threads as well.
486 void silc_schedule_task_del_by_callback(SilcSchedule schedule,
487 SilcTaskCallback callback);
489 /****f* silcutil/SilcScheduleAPI/silc_schedule_task_del_by_context
493 * void silc_schedule_task_del_by_context(SilcSchedule schedule,
498 * Deletes a task from the scheduler by the specified `context'.
500 * It is safe to call this function in any place. Tasks may be removed
501 * in task callbacks (including in the task's own task callback) and
502 * in multi-threaded environment in other threads as well.
505 void silc_schedule_task_del_by_context(SilcSchedule schedule, void *context);
507 /****f* silcutil/SilcScheduleAPI/silc_schedule_set_listen_fd
511 * void silc_schedule_set_listen_fd(SilcSchedule schedule, uint32 fd,
512 * SilcTaskEvent mask);
516 * Sets a file descriptor `fd' to be listened by the scheduler for
517 * `mask' events. To tell scheduler not to listen anymore for this
518 * file descriptor call the silc_schedule_unset_listen_fd function.
519 * When new task is created with silc_schedule_task_add the event
520 * for the task's fd is initially set to SILC_TASK_READ. If you need
521 * to control the task's fd's events you must call this function
522 * whenever you need to change the events. This can be called multiple
523 * times to change the events.
526 void silc_schedule_set_listen_fd(SilcSchedule schedule, uint32 fd,
529 /****f* silcutil/SilcScheduleAPI/silc_schedule_unset_listen_fd
533 * void silc_schedule_unset_listen_fd(SilcSchedule schedule, uint32 fd);
537 * Tells the scheduler not to listen anymore for the specified
538 * file descriptor `fd'. No events will be detected for the `fd'
539 * after calling this function.
542 void silc_schedule_unset_listen_fd(SilcSchedule schedule, uint32 fd);