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.1 2000/09/13 17:45:16 priikone
24 * Splitted SILC core library. Core library includes now only
25 * SILC protocol specific stuff. New utility library includes the
26 * old stuff from core library that is more generic purpose stuff.
28 * Revision 1.2 2000/07/05 06:06:35 priikone
29 * Global cosmetic change.
31 * Revision 1.1.1.1 2000/06/27 11:36:55 priikone
32 * Imported from internal CVS/Added Log headers.
37 #include "silcincludes.h"
39 /* Allocates a new task queue into the Silc. If 'valid' is TRUE the
40 queue becomes valid task queue. If it is FALSE scheduler will skip
43 void silc_task_queue_alloc(SilcTaskQueue *new, int valid)
46 SILC_LOG_DEBUG(("Allocating new task queue"));
48 *new = silc_calloc(1, sizeof(**new));
50 /* Set the pointers */
51 (*new)->valid = valid;
53 (*new)->register_task = silc_task_register;
54 (*new)->unregister_task = silc_task_unregister;
55 (*new)->set_iotype = silc_task_set_iotype;
56 (*new)->reset_iotype = silc_task_reset_iotype;
59 /* Free's a task queue. */
61 void silc_task_queue_free(SilcTaskQueue old)
67 /* Adds a non-timeout task into the task queue. This function is used
68 by silc_task_register function. Returns a pointer to the registered
71 SilcTask silc_task_add(SilcTaskQueue queue, SilcTask new,
72 SilcTaskPriority priority)
74 SilcTask task, next, prev;
76 /* Take the first task in the queue */
80 case SILC_TASK_PRI_LOW:
81 /* Lowest priority. The task is added at the end of the list. */
88 case SILC_TASK_PRI_NORMAL:
89 /* Normal priority. The task is added before lower priority tasks
90 but after tasks with higher priority. */
93 if (prev->priority > SILC_TASK_PRI_LOW &&
94 prev->priority <= SILC_TASK_PRI_REALTIME)
99 /* There are only lower priorities in the list, we will
100 sit before them and become the first task in the queue. */
107 /* We are now the first task in queue */
110 /* Found a spot from the list, add the task to the list. */
118 case SILC_TASK_PRI_HIGH:
119 /* High priority. The task is added before lower priority tasks
120 but after tasks with higher priority. */
122 while(prev != task) {
123 if (prev->priority > SILC_TASK_PRI_NORMAL &&
124 prev->priority <= SILC_TASK_PRI_REALTIME)
129 /* There are only lower priorities in the list, we will
130 sit before them and become the first task in the queue. */
137 /* We are now the first task in queue */
140 /* Found a spot from the list, add the task to the list. */
148 case SILC_TASK_PRI_REALTIME:
149 /* Highest priority. The task is added at the head of the list.
150 The last registered task is added to the very head of the list
151 thus we get the LIFO (Last-In-First-Out) order. */
158 /* We are the first task in the queue */
169 /* Adds a timeout task into the task queue. This function is used by
170 silc_task_register function. Returns a pointer to the registered
171 task. Timeout tasks are sorted by their timeout value in ascending
172 order. The priority matters if there are more than one task with
175 SilcTask silc_task_add_timeout(SilcTaskQueue queue, SilcTask new,
176 SilcTaskPriority priority)
178 SilcTask task, prev, next;
180 /* Take the first task in the queue */
183 /* Take last task from the list */
187 case SILC_TASK_PRI_LOW:
188 /* Lowest priority. The task is added at the end of the list. */
189 while(prev != task) {
191 /* If we have longer timeout than with the task head of us
192 we have found our spot. */
193 if (silc_task_timeout_compare(&prev->timeout, &new->timeout))
196 /* If we are equal size of timeout we will be after it. */
197 if (!silc_task_timeout_compare(&new->timeout, &prev->timeout))
200 /* We have shorter timeout, compare to next one. */
203 /* Found a spot from the list, add the task to the list. */
211 /* Check if we are going to be the first task in the queue */
212 if (silc_task_timeout_compare(&prev->timeout, &new->timeout))
214 if (!silc_task_timeout_compare(&new->timeout, &prev->timeout))
217 /* We are now the first task in queue */
221 case SILC_TASK_PRI_NORMAL:
222 /* Normal priority. The task is added before lower priority tasks
223 but after tasks with higher priority. */
224 while(prev != task) {
226 /* If we have longer timeout than with the task head of us
227 we have found our spot. */
228 if (silc_task_timeout_compare(&prev->timeout, &new->timeout))
231 /* If we are equal size of timeout, priority kicks in place. */
232 if (!silc_task_timeout_compare(&new->timeout, &prev->timeout))
233 if (prev->priority >= SILC_TASK_PRI_NORMAL)
236 /* We have shorter timeout or higher priority, compare to next one. */
239 /* Found a spot from the list, add the task to the list. */
247 /* Check if we are going to be the first task in the queue */
248 if (silc_task_timeout_compare(&prev->timeout, &new->timeout))
250 if (!silc_task_timeout_compare(&new->timeout, &prev->timeout))
251 if (prev->priority >= SILC_TASK_PRI_NORMAL)
254 /* We are now the first task in queue */
258 case SILC_TASK_PRI_HIGH:
259 /* High priority. The task is added before lower priority tasks
260 but after tasks with higher priority. */
261 while(prev != task) {
263 /* If we have longer timeout than with the task head of us
264 we have found our spot. */
265 if (silc_task_timeout_compare(&prev->timeout, &new->timeout))
268 /* If we are equal size of timeout, priority kicks in place. */
269 if (!silc_task_timeout_compare(&new->timeout, &prev->timeout))
270 if (prev->priority >= SILC_TASK_PRI_HIGH)
273 /* We have shorter timeout or higher priority, compare to next one. */
276 /* Found a spot from the list, add the task to the list. */
284 /* Check if we are going to be the first task in the queue */
285 if (silc_task_timeout_compare(&prev->timeout, &new->timeout))
287 if (!silc_task_timeout_compare(&new->timeout, &prev->timeout))
288 if (prev->priority >= SILC_TASK_PRI_HIGH)
291 /* We are now the first task in queue */
295 case SILC_TASK_PRI_REALTIME:
296 /* Highest priority. The task is added at the head of the list.
297 The last registered task is added to the very head of the list
298 thus we get the LIFO (Last-In-First-Out) order. */
300 while(next != task) {
302 /* If we have shorter timeout than the next task we've found
304 if (silc_task_timeout_compare(&new->timeout, &next->timeout))
307 /* If we are equal size of timeout we will be first. */
308 if (!silc_task_timeout_compare(&next->timeout, &new->timeout))
311 /* We have longer timeout, compare to next one. */
314 /* Found a spot from the list, add the task to the list. */
322 /* Check if we are going to be the first task in the queue */
323 if (silc_task_timeout_compare(&next->timeout, &new->timeout))
326 /* We are now the first task in queue */
337 /* Registers a new task into the task queue. The task becomes valid
338 automatically when it is registered. Returns a pointer to the
341 SilcTask silc_task_register(SilcTaskQueue queue, int fd,
342 SilcTaskCallback cb, void *context,
343 long seconds, long useconds,
344 SilcTaskType type, SilcTaskPriority priority)
349 SILC_LOG_DEBUG(("Registering new task, fd=%d type=%d priority=%d",
350 fd, type, priority));
352 /* If the task is generic task, we check whether this task has already
353 been registered. Generic tasks are registered only once and after that
354 the same task applies to all file descriptors to be registered. */
355 if ((type == SILC_TASK_GENERIC) && queue->task) {
360 if ((task->callback == cb) && (task->context == context)) {
361 SILC_LOG_DEBUG(("Found matching generic task, using the match"));
363 /* Add the fd to be listened, the task found now applies to this
365 silc_schedule_set_listen_fd(fd, (1L << SILC_TASK_READ));
369 if (queue->task == task->next)
376 new = silc_calloc(1, sizeof(*new));
378 new->context = context;
381 new->priority = priority;
382 new->iomask = (1L << SILC_TASK_READ);
386 /* If the task is non-timeout task we have to tell the scheduler that we
387 would like to have these tasks scheduled at some odd distant future. */
388 if (type != SILC_TASK_TIMEOUT)
389 silc_schedule_set_listen_fd(fd, (1L << SILC_TASK_READ));
391 /* Create timeout if marked to be timeout task */
392 if (((seconds + useconds) > 0) && (type == SILC_TASK_TIMEOUT)) {
393 gettimeofday(&new->timeout, NULL);
394 new->timeout.tv_sec += seconds + (useconds / 1000000L);
395 new->timeout.tv_usec += (useconds % 1000000L);
396 if (new->timeout.tv_usec > 999999L) {
397 new->timeout.tv_sec += 1;
398 new->timeout.tv_usec -= 1000000L;
403 /* Is this first task of the queue? */
404 if (queue->task == NULL) {
410 return silc_task_add_timeout(queue, new, priority);
412 return silc_task_add(queue, new, priority);
415 /* Removes (unregisters) a task from particular task queue. This function
416 is used internally by scheduler. One should not call this function
417 to unregister tasks, instead silc_task_unregister_task function
420 int silc_task_remove(SilcTaskQueue queue, SilcTask task)
422 SilcTask first, old, next;
424 if (!queue || !queue->task)
429 /* Unregister all tasks in queue */
430 if (task == SILC_ALL_TASKS) {
431 SILC_LOG_DEBUG(("Removing all tasks at once"));
436 silc_free(next->prev);
445 SILC_LOG_DEBUG(("Removing task"));
447 /* Unregister the task */
458 if (prev == old && next == old)
460 if (queue->task == old)
473 /* Unregisters a task from the task queue. This is the unregister_task
474 function pointer in task queue object. One should use this function
475 to unregister tasks. This function invalidates the task. */
477 void silc_task_unregister(SilcTaskQueue queue, SilcTask task)
480 /* Unregister all tasks */
481 if (task == SILC_ALL_TASKS) {
483 SILC_LOG_DEBUG(("Unregistering all tasks at once"));
485 if (queue->task == NULL)
493 if (queue->task == next->next)
500 SILC_LOG_DEBUG(("Unregistering task"));
502 /* Unregister the specific task */
507 /* Unregister a task by file descriptor. This invalidates the task. */
509 void silc_task_unregister_by_fd(SilcTaskQueue queue, int fd)
513 SILC_LOG_DEBUG(("Unregister task by fd"));
515 if (queue->task == NULL)
523 if (queue->task == next->next)
529 /* Sets the I/O mask for the task. Only one I/O type can be set at a
532 void silc_task_set_iotype(SilcTask task, int type)
534 task->iomask |= (1L << type);
537 /* Resets the I/O mask to the type sent as argument. */
539 void silc_task_reset_iotype(SilcTask task, int type)
541 task->iomask = (1L << type);
544 /* Compare two time values. If the first argument is smaller than the
545 second this function returns TRUE. */
547 int silc_task_timeout_compare(struct timeval *smaller,
548 struct timeval *bigger)
550 if ((smaller->tv_sec < bigger->tv_sec) ||
551 ((smaller->tv_sec == bigger->tv_sec) &&
552 (smaller->tv_usec < bigger->tv_usec)))