Initial revision
[silc.git] / lib / silccore / silctask.h
1 /*
2
3   silctask.h
4
5   Author: Pekka Riikonen <priikone@poseidon.pspt.fi>
6
7   Copyright (C) 1998 - 2000 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; either version 2 of the License, or
12   (at your option) any later version.
13   
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.
18
19 */
20
21 #ifndef SILCTASK_H
22 #define SILCTASK_H
23
24 /* 
25    SILC Task object. 
26
27    int fd
28
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.
32
33    struct timeval timeout
34   
35        The timeout when this task is supposed to be run. This is defined
36        only if the task is a timeout task.
37
38    void *context;
39
40        Context structure passed to callback function as argument.
41
42    SilcTaskCallback callback
43
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
50        task.
51
52    int valid
53
54        Marks for validity of the task. Task that is not valid scheduler 
55        will skip. This is boolean value.
56
57    int priority
58
59        Priority of the task. This field is used internally only and it
60        should not be touched otherwise.
61
62    int iomask
63
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.
74
75    struct SilcTaskStruct *next
76    struct SilcTaskStruct *prev
77
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).
81
82 */
83
84 typedef void (*SilcTaskCallback)(void *, int, void *, int);
85
86 typedef struct SilcTaskStruct {
87   int fd;
88   struct timeval timeout;
89   void *context;
90   SilcTaskCallback callback;
91   int valid;
92   int priority;
93   int iomask;
94
95   struct SilcTaskStruct *next;
96   struct SilcTaskStruct *prev;
97 } SilcTaskObject;
98
99 typedef SilcTaskObject *SilcTask;
100
101 /* 
102    SILC Task types.
103
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.
108
109 */
110 typedef enum {
111   SILC_TASK_FD,
112   SILC_TASK_TIMEOUT,
113   SILC_TASK_GENERIC,
114 } SilcTaskType;
115
116 /* 
117    SILC Task priorities.
118
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.
122
123    SILC_TASK_PRI_LOW
124
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.
129
130    SILC_TASK_PRI_NORMAL
131
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.
137
138    SILC_TASK_PRI_HIGH
139    
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.
145
146    SILC_TASK_PRI_REALTIME
147
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
157        behaves same way.
158
159 */
160 typedef enum {
161   SILC_TASK_PRI_LOW,
162   SILC_TASK_PRI_NORMAL,
163   SILC_TASK_PRI_HIGH,
164   SILC_TASK_PRI_REALTIME,
165 } SilcTaskPriority;
166
167 /* 
168    SILC Task Queue object. 
169    
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. 
177
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.
189
190    Short description of the field following:
191
192    SilcTask task
193
194        Pointer to the tasks in the queue.
195
196    int valid
197
198        Marks for validity of the queue. If the task queue is not valid 
199        scheduler will skip it. This is boolean value.
200
201    struct timeval timeout
202
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.
208
209    SilcTask (*register_task)(SilcTaskQueue, int, 
210                              SilcTaskCallback, void *, 
211                              long, long, 
212                              SilcTaskType,
213                              SilcTaskPriority)
214
215        Registers a new task to the task queue. Arguments are as follows:
216
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
225
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.
233
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
237        scheduled.
238
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.
245
246        Generic tasks apply to all file descriptors, however, one still must
247        pass the correct file descriptor to the function when registering
248        generic tasks.
249
250    void (*unregister_task)(SilcTaskQueue, SilcTask)
251
252        Unregisters a task already in the queue. Arguments are as follows:
253
254        SilcTaskQueue queue      Queue where from the task is unregistered
255        SilcTask task            Task to be unregistered
256
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.
261
262    void (*set_iotype)(SilcTask, int type)
263
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.
269
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.
275
276    void (*reset_iotype)(SilcTask, int type)
277
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
281        to the task.
282
283 */
284
285 typedef struct SilcTaskQueueStruct {
286   SilcTask task;
287   int valid;
288   struct timeval timeout;
289
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;
298
299 typedef SilcTaskQueueObject *SilcTaskQueue;
300
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)
304
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)
308
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
312    for that task. */
313 #define SILC_TASK_READ 0
314 #define SILC_TASK_WRITE 1
315
316 /* Macros */
317
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)))
329
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)
334
335
336 /* Prototypes */
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, 
346                             SilcTaskType type, 
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);
355
356 #endif