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.
23 * Revision 1.2 2000/07/05 06:06:35 priikone
24 * Global cosmetic change.
26 * Revision 1.1.1.1 2000/06/27 11:36:55 priikone
27 * Imported from internal CVS/Added Log headers.
32 #include "silcincludes.h"
34 /* Allocates a new task queue into the Silc. If 'valid' is TRUE the
35 queue becomes valid task queue. If it is FALSE scheduler will skip
38 void silc_task_queue_alloc(SilcTaskQueue *new, int valid)
41 SILC_LOG_DEBUG(("Allocating new task queue"));
43 *new = silc_calloc(1, sizeof(**new));
45 /* Set the pointers */
46 (*new)->valid = valid;
48 (*new)->register_task = silc_task_register;
49 (*new)->unregister_task = silc_task_unregister;
50 (*new)->set_iotype = silc_task_set_iotype;
51 (*new)->reset_iotype = silc_task_reset_iotype;
54 /* Free's a task queue. */
56 void silc_task_queue_free(SilcTaskQueue old)
62 /* Adds a non-timeout task into the task queue. This function is used
63 by silc_task_register function. Returns a pointer to the registered
66 SilcTask silc_task_add(SilcTaskQueue queue, SilcTask new,
67 SilcTaskPriority priority)
69 SilcTask task, next, prev;
71 /* Take the first task in the queue */
75 case SILC_TASK_PRI_LOW:
76 /* Lowest priority. The task is added at the end of the list. */
83 case SILC_TASK_PRI_NORMAL:
84 /* Normal priority. The task is added before lower priority tasks
85 but after tasks with higher priority. */
88 if (prev->priority > SILC_TASK_PRI_LOW &&
89 prev->priority <= SILC_TASK_PRI_REALTIME)
94 /* There are only lower priorities in the list, we will
95 sit before them and become the first task in the queue. */
102 /* We are now the first task in queue */
105 /* Found a spot from the list, add the task to the list. */
113 case SILC_TASK_PRI_HIGH:
114 /* High priority. The task is added before lower priority tasks
115 but after tasks with higher priority. */
117 while(prev != task) {
118 if (prev->priority > SILC_TASK_PRI_NORMAL &&
119 prev->priority <= SILC_TASK_PRI_REALTIME)
124 /* There are only lower priorities in the list, we will
125 sit before them and become the first task in the queue. */
132 /* We are now the first task in queue */
135 /* Found a spot from the list, add the task to the list. */
143 case SILC_TASK_PRI_REALTIME:
144 /* Highest priority. The task is added at the head of the list.
145 The last registered task is added to the very head of the list
146 thus we get the LIFO (Last-In-First-Out) order. */
153 /* We are the first task in the queue */
164 /* Adds a timeout task into the task queue. This function is used by
165 silc_task_register function. Returns a pointer to the registered
166 task. Timeout tasks are sorted by their timeout value in ascending
167 order. The priority matters if there are more than one task with
170 SilcTask silc_task_add_timeout(SilcTaskQueue queue, SilcTask new,
171 SilcTaskPriority priority)
173 SilcTask task, prev, next;
175 /* Take the first task in the queue */
178 /* Take last task from the list */
182 case SILC_TASK_PRI_LOW:
183 /* Lowest priority. The task is added at the end of the list. */
184 while(prev != task) {
186 /* If we have longer timeout than with the task head of us
187 we have found our spot. */
188 if (silc_task_timeout_compare(&prev->timeout, &new->timeout))
191 /* If we are equal size of timeout we will be after it. */
192 if (!silc_task_timeout_compare(&new->timeout, &prev->timeout))
195 /* We have shorter timeout, compare to next one. */
198 /* Found a spot from the list, add the task to the list. */
206 /* Check if we are going to be the first task in the queue */
207 if (silc_task_timeout_compare(&prev->timeout, &new->timeout))
209 if (!silc_task_timeout_compare(&new->timeout, &prev->timeout))
212 /* We are now the first task in queue */
216 case SILC_TASK_PRI_NORMAL:
217 /* Normal priority. The task is added before lower priority tasks
218 but after tasks with higher priority. */
219 while(prev != task) {
221 /* If we have longer timeout than with the task head of us
222 we have found our spot. */
223 if (silc_task_timeout_compare(&prev->timeout, &new->timeout))
226 /* If we are equal size of timeout, priority kicks in place. */
227 if (!silc_task_timeout_compare(&new->timeout, &prev->timeout))
228 if (prev->priority >= SILC_TASK_PRI_NORMAL)
231 /* We have shorter timeout or higher priority, compare to next one. */
234 /* Found a spot from the list, add the task to the list. */
242 /* Check if we are going to be the first task in the queue */
243 if (silc_task_timeout_compare(&prev->timeout, &new->timeout))
245 if (!silc_task_timeout_compare(&new->timeout, &prev->timeout))
246 if (prev->priority >= SILC_TASK_PRI_NORMAL)
249 /* We are now the first task in queue */
253 case SILC_TASK_PRI_HIGH:
254 /* High priority. The task is added before lower priority tasks
255 but after tasks with higher priority. */
256 while(prev != task) {
258 /* If we have longer timeout than with the task head of us
259 we have found our spot. */
260 if (silc_task_timeout_compare(&prev->timeout, &new->timeout))
263 /* If we are equal size of timeout, priority kicks in place. */
264 if (!silc_task_timeout_compare(&new->timeout, &prev->timeout))
265 if (prev->priority >= SILC_TASK_PRI_HIGH)
268 /* We have shorter timeout or higher priority, compare to next one. */
271 /* Found a spot from the list, add the task to the list. */
279 /* Check if we are going to be the first task in the queue */
280 if (silc_task_timeout_compare(&prev->timeout, &new->timeout))
282 if (!silc_task_timeout_compare(&new->timeout, &prev->timeout))
283 if (prev->priority >= SILC_TASK_PRI_HIGH)
286 /* We are now the first task in queue */
290 case SILC_TASK_PRI_REALTIME:
291 /* Highest priority. The task is added at the head of the list.
292 The last registered task is added to the very head of the list
293 thus we get the LIFO (Last-In-First-Out) order. */
295 while(next != task) {
297 /* If we have shorter timeout than the next task we've found
299 if (silc_task_timeout_compare(&new->timeout, &next->timeout))
302 /* If we are equal size of timeout we will be first. */
303 if (!silc_task_timeout_compare(&next->timeout, &new->timeout))
306 /* We have longer timeout, compare to next one. */
309 /* Found a spot from the list, add the task to the list. */
317 /* Check if we are going to be the first task in the queue */
318 if (silc_task_timeout_compare(&next->timeout, &new->timeout))
321 /* We are now the first task in queue */
332 /* Registers a new task into the task queue. The task becomes valid
333 automatically when it is registered. Returns a pointer to the
336 SilcTask silc_task_register(SilcTaskQueue queue, int fd,
337 SilcTaskCallback cb, void *context,
338 long seconds, long useconds,
339 SilcTaskType type, SilcTaskPriority priority)
344 SILC_LOG_DEBUG(("Registering new task, fd=%d type=%d priority=%d",
345 fd, type, priority));
347 /* If the task is generic task, we check whether this task has already
348 been registered. Generic tasks are registered only once and after that
349 the same task applies to all file descriptors to be registered. */
350 if ((type == SILC_TASK_GENERIC) && queue->task) {
355 if ((task->callback == cb) && (task->context == context)) {
356 SILC_LOG_DEBUG(("Found matching generic task, using the match"));
358 /* Add the fd to be listened, the task found now applies to this
360 silc_schedule_set_listen_fd(fd, (1L << SILC_TASK_READ));
364 if (queue->task == task->next)
371 new = silc_calloc(1, sizeof(*new));
373 new->context = context;
376 new->priority = priority;
377 new->iomask = (1L << SILC_TASK_READ);
381 /* If the task is non-timeout task we have to tell the scheduler that we
382 would like to have these tasks scheduled at some odd distant future. */
383 if (type != SILC_TASK_TIMEOUT)
384 silc_schedule_set_listen_fd(fd, (1L << SILC_TASK_READ));
386 /* Create timeout if marked to be timeout task */
387 if (((seconds + useconds) > 0) && (type == SILC_TASK_TIMEOUT)) {
388 gettimeofday(&new->timeout, NULL);
389 new->timeout.tv_sec += seconds + (useconds / 1000000L);
390 new->timeout.tv_usec += (useconds % 1000000L);
391 if (new->timeout.tv_usec > 999999L) {
392 new->timeout.tv_sec += 1;
393 new->timeout.tv_usec -= 1000000L;
398 /* Is this first task of the queue? */
399 if (queue->task == NULL) {
405 return silc_task_add_timeout(queue, new, priority);
407 return silc_task_add(queue, new, priority);
410 /* Removes (unregisters) a task from particular task queue. This function
411 is used internally by scheduler. One should not call this function
412 to unregister tasks, instead silc_task_unregister_task function
415 int silc_task_remove(SilcTaskQueue queue, SilcTask task)
417 SilcTask first, old, next;
419 if (!queue || !queue->task)
424 /* Unregister all tasks in queue */
425 if (task == SILC_ALL_TASKS) {
426 SILC_LOG_DEBUG(("Removing all tasks at once"));
431 silc_free(next->prev);
440 SILC_LOG_DEBUG(("Removing task"));
442 /* Unregister the task */
453 if (prev == old && next == old)
455 if (queue->task == old)
468 /* Unregisters a task from the task queue. This is the unregister_task
469 function pointer in task queue object. One should use this function
470 to unregister tasks. This function invalidates the task. */
472 void silc_task_unregister(SilcTaskQueue queue, SilcTask task)
475 /* Unregister all tasks */
476 if (task == SILC_ALL_TASKS) {
478 SILC_LOG_DEBUG(("Unregistering all tasks at once"));
480 if (queue->task == NULL)
488 if (queue->task == next->next)
495 SILC_LOG_DEBUG(("Unregistering task"));
497 /* Unregister the specific task */
502 /* Unregister a task by file descriptor. This invalidates the task. */
504 void silc_task_unregister_by_fd(SilcTaskQueue queue, int fd)
508 SILC_LOG_DEBUG(("Unregister task by fd"));
510 if (queue->task == NULL)
518 if (queue->task == next->next)
524 /* Sets the I/O mask for the task. Only one I/O type can be set at a
527 void silc_task_set_iotype(SilcTask task, int type)
529 task->iomask |= (1L << type);
532 /* Resets the I/O mask to the type sent as argument. */
534 void silc_task_reset_iotype(SilcTask task, int type)
536 task->iomask = (1L << type);
539 /* Compare two time values. If the first argument is smaller than the
540 second this function returns TRUE. */
542 int silc_task_timeout_compare(struct timeval *smaller,
543 struct timeval *bigger)
545 if ((smaller->tv_sec < bigger->tv_sec) ||
546 ((smaller->tv_sec == bigger->tv_sec) &&
547 (smaller->tv_usec < bigger->tv_usec)))