5 Author: Pekka Riikonen <priikone@poseidon.pspt.fi>
7 Copyright (C) 1998 - 2000 Pekka Riikonen
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; either version 2 of the License, or
12 (at your option) any later version.
14 This program is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 GNU General Public License for more details.
29 File descriptor. This usually is a network socket but can be
30 any file descriptor. On generic tasks, that applies to all file
31 descriptors, this is set to -1.
33 struct timeval timeout
35 The timeout when this task is supposed to be run. This is defined
36 only if the task is a timeout task.
40 Context structure passed to callback function as argument.
42 SilcTaskCallback callback
44 The callback function Silc scheduler calls when this task is scheduled
45 to be run. First argument is the task queue this task belongs to. This
46 is a void pointer and the task queue has to casted out of it. Second
47 argument is the type of the event just occured inside the scheduler
48 (SILC_TASK_READ or SILC_TASK_WRITE). Third argument is the context
49 structure of the task. Last argument is the file descriptor of the
54 Marks for validity of the task. Task that is not valid scheduler
55 will skip. This is boolean value.
59 Priority of the task. This field is used internally only and it
60 should not be touched otherwise.
64 I/O mask which tells to the scheduler for what kind of I/O this
65 task is ready. If the task is ready for both reading and writing
66 SILC_TASK_READ and SILC_TASK_WRITE are masked into this variable.
67 Masking is done by OR'ing (1 << SILC_TASK_*) values. One can check
68 the mask by AND'ing (1L << SILC_TASK_*) against the mask. At the
69 registering of a new task this mask is set to SILC_TASK_READ by
70 default. If a task doesn't perform reading this value must be
71 reset to SILC_TASK_WRITE. If it performs both reading and writing
72 SILC_TASK_WRITE must be added to the mask. A task must always be
73 ready for at least for one I/O type.
75 struct SilcTaskStruct *next
76 struct SilcTaskStruct *prev
78 Next and previous task. If the task is first in the list, prev is
79 set to the last task in the list. If the task is last in the list,
80 next is set to the first task in the list (forms a circular list).
84 typedef void (*SilcTaskCallback)(void *, int, void *, int);
86 typedef struct SilcTaskStruct {
88 struct timeval timeout;
90 SilcTaskCallback callback;
95 struct SilcTaskStruct *next;
96 struct SilcTaskStruct *prev;
99 typedef SilcTaskObject *SilcTask;
104 SILC has three types of tasks, non-timeout tasks (tasks that perform
105 over file descriptors), timeout tasks and generic tasks (tasks that apply
106 to every file descriptor). This type is sent as argument for the
107 task registering function.
117 SILC Task priorities.
119 Following description of the priorities uses timeout tasks as example
120 how the priority behaves. However, non-timeout tasks behaves same as
121 timeout tasks with following priorities.
125 Lowest priority. The task is scheduled to run after its timeout
126 has expired only and only when every other task with higher priority
127 has already been run. For non-timeout tasks this priority behaves
128 same way. Life is not fair for tasks with this priority.
132 Normal priority that is used mostly in Silc. This is priority that
133 should always be used unless you specificly need some other priority.
134 The scheduler will run this task as soon as its timeout has expired.
135 For non-timeout tasks this priority behaves same way. Tasks are run
136 in FIFO (First-In-First-Out) order.
140 High priority for important tasks. This priority should be used only
141 for important tasks. Life is very fair for tasks with this priority.
142 These tasks are run as soon as its timeout has expired. They are run
143 before normal or lower tasks, respectively. For non-timeout tasks
144 this priority behaves same way. Tasks are run in FIFO order.
146 SILC_TASK_PRI_REALTIME
148 Highest priority. This priority should be used very carefully because
149 it can make the scheduler extremely unfair to other tasks. The task
150 will be run as soon as its timeout has expired. The task is run before
151 any other task. It is also quaranteed that the last registered task
152 with this priority is the first task to be run when its timeout
153 expires. Tasks are run in LIFO (Last-In-First-Out) order. To make
154 scheduler fair there should never be more than one task in the queue
155 with this priority. Currently none of the tasks in SILC are important
156 enough to use this priority. For non-timeout tasks this priority
162 SILC_TASK_PRI_NORMAL,
164 SILC_TASK_PRI_REALTIME,
168 SILC Task Queue object.
170 Usually there are three task queues in SILC. Tasks with timeouts
171 has their own queue, tasks without timeout has one as well and generic
172 tasks has their own also. Scheduler has timeout queue hooks and
173 non-timeout queue hooks in the scheduler and it does not check for
174 timeouts in non-timeout hooks and vice versa, respectively. Ie. Register
175 timeout queues to their own SilcTaskQueue pointer and non-timeout queues
176 to their own pointer.
178 Generic tasks, mentioned earlier, has their own task queue. These tasks
179 are non-timeout tasks and they apply to all file descriptors, except to
180 those that have explicitly registered a non-timeout task. These tasks
181 are there to make it simpler and faster to execute common code that
182 applies to all connections. These are, for example, receiving packets
183 from network and sending packets to network. It doesn't make much sense
184 to register a task that receives a packet from network to every connection
185 when you can have one task that applies to all connections. This is what
186 generic tasks are for. Generic tasks are not bound to any specific file
187 descriptor, however, the correct file descriptor must be passed as
188 argument to task registering function.
190 Short description of the field following:
194 Pointer to the tasks in the queue.
198 Marks for validity of the queue. If the task queue is not valid
199 scheduler will skip it. This is boolean value.
201 struct timeval timeout
203 Timeout when earliest some tasks in this queue should expire. The
204 value of this timeout is updated automatically by schedule. This
205 is used only and only if this queue is a timeout queue. For normal
206 task queue this is not defined. This is meant only for internal
207 use and it should be considered to be read-only field.
209 SilcTask (*register_task)(SilcTaskQueue, int,
210 SilcTaskCallback, void *,
215 Registers a new task to the task queue. Arguments are as follows:
217 SilcTaskQueue queue Queue where the task is to be registered
218 int fd File descriptor
219 SilcTaskCallback cb Callback function to call
220 void *context Context to be passed to callback function
221 long seconds Seconds to timeout
222 long useconds Microseconds to timeout
223 SilcTaskType type Type of the task
224 SilcTaskPriority priority Priority of the task
226 The same function is used to register all types of tasks. The type
227 argument tells what type of the task is. Note that when registering
228 non-timeout tasks one should also pass 0 as timeout as timeout will
229 be ignored anyway. Also, note, that one cannot register timeout task
230 with 0 timeout. There cannot be zero timeouts, passing zero means
231 no timeout is used for the task and SILC_TASK_FD_TASK is used as
232 default task type in this case.
234 One should be careful not to register timeout tasks to the non-timeout
235 task queue, because they will never expire. As one should not register
236 non-timeout tasks to timeout task queue because they will never get
239 There is a one distinct difference between timeout and non-timeout
240 tasks when they are executed. Non-timeout tasks remain on the task
241 queue after execution. Timeout tasks, however, are removed from the
242 task queue after they have expired. It is safe to re-register a task
243 in its own callback function. It is also safe to unregister a task
244 in a callback function.
246 Generic tasks apply to all file descriptors, however, one still must
247 pass the correct file descriptor to the function when registering
250 void (*unregister_task)(SilcTaskQueue, SilcTask)
252 Unregisters a task already in the queue. Arguments are as follows:
254 SilcTaskQueue queue Queue where from the task is unregistered
255 SilcTask task Task to be unregistered
257 The same function is used to unregister timeout and non-timeout
258 tasks. One can also unregister all tasks from the queue by passing
259 SILC_ALL_TASKS as task to the function. It is safe to unregister
260 a task in a callback function.
262 void (*set_iotype)(SilcTask, int type)
264 Sets the I/O type of the task. The scheduler checks for this value
265 and a task must always have at least one of the I/O types set at
266 all time. When registering new task the type is set by default to
267 SILC_TASK_READ. If the task doesn't perform reading one must reset
268 the value to SILC_TASK_WRITE.
270 The type sent as argumenet is masked into the task. If the tasks
271 I/O mask already includes this type this function has no effect.
272 Only one I/O type can be added at once. If the task must perform
273 both reading and writing one must call this function for value
274 SILC_TASK_WRITE as well.
276 void (*reset_iotype)(SilcTask, int type)
278 Resets the mask to the type sent as argument. Note that this resets
279 the previous values to zero and then adds the type sent as argument.
280 This function can be used to remove one of the types masked earlier
285 typedef struct SilcTaskQueueStruct {
288 struct timeval timeout;
290 /* Method functions */
291 SilcTask (*register_task)(struct SilcTaskQueueStruct *, int,
292 SilcTaskCallback, void *, long, long,
293 SilcTaskType, SilcTaskPriority);
294 void (*unregister_task)(struct SilcTaskQueueStruct *, SilcTask);
295 void (*set_iotype)(SilcTask, int type);
296 void (*reset_iotype)(SilcTask, int type);
297 } SilcTaskQueueObject;
299 typedef SilcTaskQueueObject *SilcTaskQueue;
301 /* Marks for all tasks in a task queue. This can be passed to
302 unregister_task function to cancel all tasks at once. */
303 #define SILC_ALL_TASKS ((SilcTask)1)
305 /* Marks for all task queues. This can be passed to
306 silc_task_queue_unregister function to cancel all task queues at once. */
307 #define SILC_ALL_TASK_QUEUES ((SilcTaskQueue)1)
309 /* Silc Task event types. One of these are passed to the task callback
310 function from the schedule. These values are also masked into a task
311 so that scheduler knows for what kind of I/O it needs to perform
313 #define SILC_TASK_READ 0
314 #define SILC_TASK_WRITE 1
318 /* These can be used instead of calling directly the registering function.
319 XXX: These are not used currently, maybe they should be :) */
320 #define SILC_REGISTER_FD_TASK(queue, fd, cb, ctx, pri) \
321 (silc_task_register((queue), (fd), (cb), (ctx), 0, 0, \
322 SILC_TASK_FD, (pri)))
323 #define SILC_REGISTER_TIMEOUT_TASK(queue, fd, cb, ctx, sec, usec, pri) \
324 (silc_task_register((queue), (fd), (cb), (ctx), (sec), (usec), \
325 SILC_TASK_TIMEOUT, (pri)))
326 #define SILC_REGISTER_GENERIC_TASK(queue, fd, cb, ctx, pri) \
327 (silc_task_register((queue), (fd), (cb), (ctx), 0, 0, \
328 SILC_TASK_GENERIC, (pri)))
330 /* Generic macro to define task callback functions. This defines a function
331 with name 'func' as a task callback function. */
332 #define SILC_TASK_CALLBACK(func) \
333 static void func(void *qptr, int type, void *context, int fd)
337 void silc_task_queue_alloc(SilcTaskQueue *new, int valid);
338 void silc_task_queue_free(SilcTaskQueue old);
339 SilcTask silc_task_add(SilcTaskQueue queue, SilcTask new,
340 SilcTaskPriority priority);
341 SilcTask silc_task_add_timeout(SilcTaskQueue queue, SilcTask new,
342 SilcTaskPriority priority);
343 SilcTask silc_task_register(SilcTaskQueue queue, int fd,
344 SilcTaskCallback cb, void *context,
345 long seconds, long useconds,
347 SilcTaskPriority priority);
348 int silc_task_remove(SilcTaskQueue queue, SilcTask task);
349 void silc_task_unregister(SilcTaskQueue queue, SilcTask task);
350 void silc_task_unregister_by_fd(SilcTaskQueue queue, int fd);
351 void silc_task_set_iotype(SilcTask task, int type);
352 void silc_task_reset_iotype(SilcTask task, int type);
353 int silc_task_timeout_compare(struct timeval *smaller,
354 struct timeval *bigger);