GNU General Public License for more details.
*/
-/*
- * $Id$
- * $Log$
- * Revision 1.1 2000/09/13 17:45:16 priikone
- * Splitted SILC core library. Core library includes now only
- * SILC protocol specific stuff. New utility library includes the
- * old stuff from core library that is more generic purpose stuff.
- *
- * Revision 1.2 2000/07/05 06:06:35 priikone
- * Global cosmetic change.
- *
- * Revision 1.1.1.1 2000/06/27 11:36:55 priikone
- * Imported from internal CVS/Added Log headers.
- *
- *
- */
+/* $Id$ */
#include "silcincludes.h"
/* Set the pointers */
(*new)->valid = valid;
(*new)->task = NULL;
- (*new)->register_task = silc_task_register;
- (*new)->unregister_task = silc_task_unregister;
- (*new)->set_iotype = silc_task_set_iotype;
- (*new)->reset_iotype = silc_task_reset_iotype;
}
/* Free's a task queue. */
but after tasks with higher priority. */
prev = task->prev;
while(prev != task) {
- if (prev->priority > SILC_TASK_PRI_LOW &&
- prev->priority <= SILC_TASK_PRI_REALTIME)
+ if (prev->priority > SILC_TASK_PRI_LOW)
break;
prev = prev->prev;
}
next->prev = new;
}
break;
- case SILC_TASK_PRI_HIGH:
- /* High priority. The task is added before lower priority tasks
- but after tasks with higher priority. */
- prev = task->prev;
- while(prev != task) {
- if (prev->priority > SILC_TASK_PRI_NORMAL &&
- prev->priority <= SILC_TASK_PRI_REALTIME)
- break;
- prev = prev->prev;
- }
- if (prev == task) {
- /* There are only lower priorities in the list, we will
- sit before them and become the first task in the queue. */
- prev = task->prev;
- new->prev = prev;
- new->next = task;
- task->prev = new;
- prev->next = new;
-
- /* We are now the first task in queue */
- queue->task = new;
- } else {
- /* Found a spot from the list, add the task to the list. */
- next = prev->next;
- new->prev = prev;
- new->next = next;
- prev->next = new;
- next->prev = new;
- }
- break;
- case SILC_TASK_PRI_REALTIME:
- /* Highest priority. The task is added at the head of the list.
- The last registered task is added to the very head of the list
- thus we get the LIFO (Last-In-First-Out) order. */
- prev = task->prev;
- new->prev = prev;
- new->next = task;
- prev->next = new;
- task->prev = new;
-
- /* We are the first task in the queue */
- queue->task = new;
- break;
default:
silc_free(new);
return NULL;
return new;
}
+/* Return the timeout task with smallest timeout. */
+
+static SilcTask silc_task_get_first(SilcTaskQueue queue, SilcTask first)
+{
+ SilcTask prev, task;
+
+ prev = first->prev;
+
+ if (first == prev)
+ return first;
+
+ task = first;
+ while (1) {
+ if (first == prev)
+ break;
+
+ if (silc_task_timeout_compare(&prev->timeout, &task->timeout))
+ task = prev;
+
+ prev = prev->prev;
+ }
+
+ return task;
+}
+
/* Adds a timeout task into the task queue. This function is used by
silc_task_register function. Returns a pointer to the registered
task. Timeout tasks are sorted by their timeout value in ascending
queue->task = new;
}
break;
- case SILC_TASK_PRI_HIGH:
- /* High priority. The task is added before lower priority tasks
- but after tasks with higher priority. */
- while(prev != task) {
-
- /* If we have longer timeout than with the task head of us
- we have found our spot. */
- if (silc_task_timeout_compare(&prev->timeout, &new->timeout))
- break;
-
- /* If we are equal size of timeout, priority kicks in place. */
- if (!silc_task_timeout_compare(&new->timeout, &prev->timeout))
- if (prev->priority >= SILC_TASK_PRI_HIGH)
- break;
-
- /* We have shorter timeout or higher priority, compare to next one. */
- prev = prev->prev;
- }
- /* Found a spot from the list, add the task to the list. */
- next = prev->next;
- new->prev = prev;
- new->next = next;
- prev->next = new;
- next->prev = new;
-
- if (prev == task) {
- /* Check if we are going to be the first task in the queue */
- if (silc_task_timeout_compare(&prev->timeout, &new->timeout))
- break;
- if (!silc_task_timeout_compare(&new->timeout, &prev->timeout))
- if (prev->priority >= SILC_TASK_PRI_HIGH)
- break;
-
- /* We are now the first task in queue */
- queue->task = new;
- }
- break;
- case SILC_TASK_PRI_REALTIME:
- /* Highest priority. The task is added at the head of the list.
- The last registered task is added to the very head of the list
- thus we get the LIFO (Last-In-First-Out) order. */
- next = task->next;
- while(next != task) {
-
- /* If we have shorter timeout than the next task we've found
- our spot. */
- if (silc_task_timeout_compare(&new->timeout, &next->timeout))
- break;
-
- /* If we are equal size of timeout we will be first. */
- if (!silc_task_timeout_compare(&next->timeout, &new->timeout))
- break;
-
- /* We have longer timeout, compare to next one. */
- next = next->next;
- }
- /* Found a spot from the list, add the task to the list. */
- prev = next->prev;
- new->next = next;
- new->prev = prev;
- prev->next = new;
- next->prev = new;
-
- if (next == task) {
- /* Check if we are going to be the first task in the queue */
- if (silc_task_timeout_compare(&next->timeout, &new->timeout))
- break;
-
- /* We are now the first task in queue */
- queue->task = new;
- }
default:
silc_free(new);
return NULL;
return new;
}
-/* Registers a new task into the task queue. The task becomes valid
- automatically when it is registered. Returns a pointer to the
- registered task. */
+/* Registers a new task to the task queue. Arguments are as follows:
+
+ SilcTaskQueue queue Queue where the task is to be registered
+ int fd File descriptor
+ SilcTaskCallback cb Callback function to call
+ void *context Context to be passed to callback function
+ long seconds Seconds to timeout
+ long useconds Microseconds to timeout
+ SilcTaskType type Type of the task
+ SilcTaskPriority priority Priority of the task
+
+ The same function is used to register all types of tasks. The type
+ argument tells what type of the task is. Note that when registering
+ non-timeout tasks one should also pass 0 as timeout as timeout will
+ be ignored anyway. Also, note, that one cannot register timeout task
+ with 0 timeout. There cannot be zero timeouts, passing zero means
+ no timeout is used for the task and SILC_TASK_FD_TASK is used as
+ default task type in this case.
+
+ One should be careful not to register timeout tasks to the non-timeout
+ task queue, because they will never expire. As one should not register
+ non-timeout tasks to timeout task queue because they will never get
+ scheduled.
+
+ There is a one distinct difference between timeout and non-timeout
+ tasks when they are executed. Non-timeout tasks remain on the task
+ queue after execution. Timeout tasks, however, are removed from the
+ task queue after they have expired. It is safe to re-register a task
+ in its own callback function. It is also safe to unregister a task
+ in a callback function.
+
+ Generic tasks apply to all file descriptors, however, one still must
+ pass the correct file descriptor to the function when registering
+ generic tasks. */
SilcTask silc_task_register(SilcTaskQueue queue, int fd,
SilcTaskCallback cb, void *context,
SilcTaskType type, SilcTaskPriority priority)
{
SilcTask new;
- int timeout = 0;
+ int timeout = FALSE;
SILC_LOG_DEBUG(("Registering new task, fd=%d type=%d priority=%d",
fd, type, priority));
new->timeout.tv_sec += 1;
new->timeout.tv_usec -= 1000000L;
}
- timeout = 1;
+ timeout = TRUE;
}
/* Is this first task of the queue? */
if (prev == old && next == old)
queue->task = NULL;
if (queue->task == old)
- queue->task = next;
-
+ queue->task = silc_task_get_first(queue, next);
+
silc_free(old);
return TRUE;
}
- old = old->next;
+ old = old->prev;
if (old == first)
return FALSE;
}
}
-/* Unregisters a task from the task queue. This is the unregister_task
- function pointer in task queue object. One should use this function
- to unregister tasks. This function invalidates the task. */
+/* Unregisters a task already in the queue. Arguments are as follows:
+
+ SilcTaskQueue queue Queue where from the task is unregistered
+ SilcTask task Task to be unregistered
+
+ The same function is used to unregister timeout and non-timeout
+ tasks. One can also unregister all tasks from the queue by passing
+ SILC_ALL_TASKS as task to the function. It is safe to unregister
+ a task in a callback function. */
void silc_task_unregister(SilcTaskQueue queue, SilcTask task)
{
}
}
-/* Sets the I/O mask for the task. Only one I/O type can be set at a
- time. */
+/* Unregister a task by callback function. This invalidates the task. */
+
+void silc_task_unregister_by_callback(SilcTaskQueue queue,
+ SilcTaskCallback callback)
+{
+ SilcTask next;
+
+ SILC_LOG_DEBUG(("Unregister task by callback"));
+
+ if (queue->task == NULL)
+ return;
+
+ next = queue->task;
+
+ while(1) {
+ if (next->callback == callback)
+ next->valid = FALSE;
+ if (queue->task == next->next)
+ break;
+ next = next->next;
+ }
+}
+
+/* Unregister a task by context. This invalidates the task. */
+
+void silc_task_unregister_by_context(SilcTaskQueue queue, void *context)
+{
+ SilcTask next;
+
+ SILC_LOG_DEBUG(("Unregister task by context"));
+
+ if (queue->task == NULL)
+ return;
+
+ next = queue->task;
+
+ while(1) {
+ if (next->context == context)
+ next->valid = FALSE;
+ if (queue->task == next->next)
+ break;
+ next = next->next;
+ }
+}
+
+/* Sets the I/O type of the task. The scheduler checks for this value
+ and a task must always have at least one of the I/O types set at
+ all time. When registering new task the type is set by default to
+ SILC_TASK_READ. If the task doesn't perform reading one must reset
+ the value to SILC_TASK_WRITE.
+
+ The type sent as argumenet is masked into the task. If the tasks
+ I/O mask already includes this type this function has no effect.
+ Only one I/O type can be added at once. If the task must perform
+ both reading and writing one must call this function for value
+ SILC_TASK_WRITE as well. */
void silc_task_set_iotype(SilcTask task, int type)
{
task->iomask |= (1L << type);
}
-/* Resets the I/O mask to the type sent as argument. */
+/* Resets the mask to the type sent as argument. Note that this resets
+ the previous values to zero and then adds the type sent as argument.
+ This function can be used to remove one of the types masked earlier
+ to the task. */
void silc_task_reset_iotype(SilcTask task, int type)
{