Created SILC GIT repository.
[silc.git] / lib / silcutil / silcschedule.c
diff --git a/lib/silcutil/silcschedule.c b/lib/silcutil/silcschedule.c
deleted file mode 100644 (file)
index 5550181..0000000
+++ /dev/null
@@ -1,1581 +0,0 @@
-/*
-
-  silcschedule.c
-
-  Author: Pekka Riikonen <priikone@silcnet.org>
-
-  Copyright (C) 1998 - 2007 Pekka Riikonen
-
-  This program is free software; you can redistribute it and/or modify
-  it under the terms of the GNU General Public License as published by
-  the Free Software Foundation; version 2 of the License.
-
-  This program is distributed in the hope that it will be useful,
-  but WITHOUT ANY WARRANTY; without even the implied warranty of
-  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-  GNU General Public License for more details.
-
-*/
-/* $Id$ */
-
-#include "silc.h"
-
-/************************** Types and definitions ***************************/
-
-/* Connected event context */
-typedef struct SilcScheduleEventConnectionStruct {
-  SilcSchedule schedule;
-  SilcTaskEventCallback callback;
-  void *context;
-  struct SilcScheduleEventConnectionStruct *next;
-} *SilcScheduleEventConnection;
-
-/* Platform specific implementation */
-extern const SilcScheduleOps schedule_ops;
-
-static void silc_schedule_task_remove(SilcSchedule schedule, SilcTask task);
-static void silc_schedule_dispatch_fd(SilcSchedule schedule);
-static void silc_schedule_dispatch_timeout(SilcSchedule schedule,
-                                          SilcBool dispatch_all);
-SILC_TASK_CALLBACK(silc_schedule_event_del_timeout);
-
-/************************ Static utility functions **************************/
-
-/* Fd task hash table destructor */
-
-static void silc_schedule_fd_destructor(void *key, void *context,
-                                       void *user_context)
-{
-  silc_free(context);
-}
-
-/* Executes file descriptor tasks. Invalid tasks are removed here. */
-
-static void silc_schedule_dispatch_fd(SilcSchedule schedule)
-{
-  SilcTaskFd task;
-  SilcTask t;
-
-  /* The dispatch list includes only valid tasks, and tasks that have
-     something to dispatch.  Dispatching is atomic; no matter if another
-     thread invalidates a task when we unlock, we dispatch to completion. */
-  SILC_SCHEDULE_UNLOCK(schedule);
-  silc_list_start(schedule->fd_dispatch);
-  while ((task = silc_list_get(schedule->fd_dispatch))) {
-    t = (SilcTask)task;
-
-    /* Is the task ready for reading */
-    if (task->revents & SILC_TASK_READ)
-      t->callback(schedule, schedule->app_context, SILC_TASK_READ,
-                 task->fd, t->context);
-
-    /* Is the task ready for writing */
-    if (t->valid && task->revents & SILC_TASK_WRITE)
-      t->callback(schedule, schedule->app_context, SILC_TASK_WRITE,
-                 task->fd, t->context);
-  }
-  SILC_SCHEDULE_LOCK(schedule);
-
-  /* Remove invalidated tasks */
-  silc_list_start(schedule->fd_dispatch);
-  while ((task = silc_list_get(schedule->fd_dispatch)))
-    if (silc_unlikely(!task->header.valid))
-      silc_schedule_task_remove(schedule, (SilcTask)task);
-}
-
-/* Executes all tasks whose timeout has expired. The task is removed from
-   the task queue after the callback function has returned. Also, invalid
-   tasks are removed here. */
-
-static void silc_schedule_dispatch_timeout(SilcSchedule schedule,
-                                          SilcBool dispatch_all)
-{
-  SilcTask t;
-  SilcTaskTimeout task;
-  struct timeval curtime;
-  int count = 0;
-
-  SILC_LOG_DEBUG(("Running timeout tasks"));
-
-  silc_gettimeofday(&curtime);
-
-  /* First task in the task queue has always the earliest timeout. */
-  silc_list_start(schedule->timeout_queue);
-  task = silc_list_get(schedule->timeout_queue);
-  if (silc_unlikely(!task))
-    return;
-  do {
-    t = (SilcTask)task;
-
-    /* Remove invalid task */
-    if (silc_unlikely(!t->valid)) {
-      silc_schedule_task_remove(schedule, t);
-      continue;
-    }
-
-    /* Execute the task if the timeout has expired */
-    if (silc_compare_timeval(&task->timeout, &curtime) > 0 && !dispatch_all)
-      break;
-
-    t->valid = FALSE;
-    SILC_SCHEDULE_UNLOCK(schedule);
-    t->callback(schedule, schedule->app_context, SILC_TASK_EXPIRE, 0,
-               t->context);
-    SILC_SCHEDULE_LOCK(schedule);
-
-    /* Remove the expired task */
-    silc_schedule_task_remove(schedule, t);
-
-    /* Balance when we have lots of small timeouts */
-    if (silc_unlikely((++count) > 40))
-      break;
-  } while (silc_likely((task = silc_list_get(schedule->timeout_queue))));
-}
-
-/* Calculates next timeout. This is the timeout value when at earliest some
-   of the timeout tasks expire. If this is in the past, they will be
-   dispatched now. */
-
-static void silc_schedule_select_timeout(SilcSchedule schedule)
-{
-  SilcTask t;
-  SilcTaskTimeout task;
-  struct timeval curtime;
-  SilcBool dispatch = TRUE;
-
-  /* Get the current time */
-  silc_gettimeofday(&curtime);
-  schedule->has_timeout = FALSE;
-
-  /* First task in the task queue has always the earliest timeout. */
-  silc_list_start(schedule->timeout_queue);
-  task = silc_list_get(schedule->timeout_queue);
-  if (silc_unlikely(!task))
-    return;
-  do {
-    t = (SilcTask)task;
-
-    /* Remove invalid task */
-    if (silc_unlikely(!t->valid)) {
-      silc_schedule_task_remove(schedule, t);
-      continue;
-    }
-
-    /* If the timeout is in past, we will run the task and all other
-       timeout tasks from the past. */
-    if (silc_compare_timeval(&task->timeout, &curtime) <= 0 && dispatch) {
-      silc_schedule_dispatch_timeout(schedule, FALSE);
-      if (silc_unlikely(!schedule->valid))
-       return;
-
-      /* Start selecting new timeout again after dispatch */
-      silc_list_start(schedule->timeout_queue);
-      dispatch = FALSE;
-      continue;
-    }
-
-    /* Calculate the next timeout */
-    curtime.tv_sec = task->timeout.tv_sec - curtime.tv_sec;
-    curtime.tv_usec = task->timeout.tv_usec - curtime.tv_usec;
-    if (curtime.tv_sec < 0)
-      curtime.tv_sec = 0;
-
-    /* We wouldn't want to go under zero, check for it. */
-    if (curtime.tv_usec < 0) {
-      curtime.tv_sec -= 1;
-      if (curtime.tv_sec < 0)
-       curtime.tv_sec = 0;
-      curtime.tv_usec += 1000000L;
-    }
-    break;
-  } while ((task = silc_list_get(schedule->timeout_queue)));
-
-  /* Save the timeout */
-  if (task) {
-    schedule->timeout = curtime;
-    schedule->has_timeout = TRUE;
-    SILC_LOG_DEBUG(("timeout: sec=%d, usec=%d", schedule->timeout.tv_sec,
-                   schedule->timeout.tv_usec));
-  }
-}
-
-/* Removes task from the scheduler.  This must be called with scheduler
-   locked. */
-
-static void silc_schedule_task_remove(SilcSchedule schedule, SilcTask task)
-{
-  SilcSchedule parent;
-
-  if (silc_unlikely(task == SILC_ALL_TASKS)) {
-    SilcTask task;
-    SilcEventTask etask;
-    SilcHashTableList htl;
-    void *fd;
-
-    /* Delete from fd queue */
-    silc_hash_table_list(schedule->fd_queue, &htl);
-    while (silc_hash_table_get(&htl, &fd, (void *)&task))
-      silc_hash_table_del(schedule->fd_queue, fd);
-    silc_hash_table_list_reset(&htl);
-
-    /* Delete from timeout queue */
-    silc_list_start(schedule->timeout_queue);
-    while ((task = silc_list_get(schedule->timeout_queue))) {
-      silc_list_del(schedule->timeout_queue, task);
-      silc_free(task);
-    }
-
-    /* Delete even tasks */
-    parent = silc_schedule_get_parent(schedule);
-    silc_hash_table_list(parent->events, &htl);
-    while (silc_hash_table_get(&htl, NULL, (void *)&etask)) {
-      silc_hash_table_del_by_context(parent->events, etask->event, etask);
-      silc_free(etask->event);
-      silc_free(etask);
-    }
-    silc_hash_table_list_reset(&htl);
-    return;
-  }
-
-  switch (task->type) {
-  case SILC_TASK_FD:
-    {
-      /* Delete from fd queue */
-      SilcTaskFd ftask = (SilcTaskFd)task;
-      silc_hash_table_del(schedule->fd_queue, SILC_32_TO_PTR(ftask->fd));
-    }
-    break;
-
-  case SILC_TASK_TIMEOUT:
-    {
-      /* Delete from timeout queue */
-      silc_list_del(schedule->timeout_queue, task);
-
-      /* Put to free list */
-      silc_list_add(schedule->free_tasks, task);
-    }
-    break;
-
-  case SILC_TASK_EVENT:
-    {
-      SilcEventTask etask = (SilcEventTask)task;
-      SilcScheduleEventConnection conn;
-
-      parent = silc_schedule_get_parent(schedule);
-
-      /* Delete event */
-      silc_hash_table_del_by_context(parent->events, etask->event, etask);
-
-      /* Remove all connections */
-      silc_list_start(etask->connections);
-      while ((conn = silc_list_get(etask->connections)))
-       silc_free(conn);
-
-      silc_free(etask->event);
-      silc_free(etask);
-    }
-    break;
-
-  default:
-    break;
-  }
-}
-
-/* Timeout freelist garbage collection */
-
-SILC_TASK_CALLBACK(silc_schedule_timeout_gc)
-{
-  SilcTaskTimeout t;
-  int c;
-
-  if (!schedule->valid)
-    return;
-
-  SILC_LOG_DEBUG(("Timeout freelist garbage collection"));
-
-  SILC_SCHEDULE_LOCK(schedule);
-
-  if (silc_list_count(schedule->free_tasks) <= 10) {
-    SILC_SCHEDULE_UNLOCK(schedule);
-    silc_schedule_task_add_timeout(schedule, silc_schedule_timeout_gc,
-                                  schedule, 3600, 0);
-    return;
-  }
-  if (silc_list_count(schedule->timeout_queue) >
-      silc_list_count(schedule->free_tasks)) {
-    SILC_SCHEDULE_UNLOCK(schedule);
-    silc_schedule_task_add_timeout(schedule, silc_schedule_timeout_gc,
-                                  schedule, 3600, 0);
-    return;
-  }
-
-  c = silc_list_count(schedule->free_tasks) / 2;
-  if (c > silc_list_count(schedule->timeout_queue))
-    c = (silc_list_count(schedule->free_tasks) -
-        silc_list_count(schedule->timeout_queue));
-  if (silc_list_count(schedule->free_tasks) - c < 10)
-    c -= (10 - (silc_list_count(schedule->free_tasks) - c));
-
-  SILC_LOG_DEBUG(("Freeing %d unused tasks, leaving %d", c,
-                 silc_list_count(schedule->free_tasks) - c));
-
-  silc_list_start(schedule->free_tasks);
-  while ((t = silc_list_get(schedule->free_tasks)) && c-- > 0) {
-    silc_list_del(schedule->free_tasks, t);
-    silc_free(t);
-  }
-  silc_list_start(schedule->free_tasks);
-
-  SILC_SCHEDULE_UNLOCK(schedule);
-
-  silc_schedule_task_add_timeout(schedule, silc_schedule_timeout_gc,
-                                schedule, 3600, 0);
-}
-
-#ifdef SILC_DIST_INPLACE
-/* Print schedule statistics to stdout */
-
-void silc_schedule_stats(SilcSchedule schedule)
-{
-  SilcTaskFd ftask;
-  fprintf(stdout, "Schedule %p statistics:\n\n", schedule);
-  fprintf(stdout, "Num FD tasks         : %d (%lu bytes allocated)\n",
-         silc_hash_table_count(schedule->fd_queue),
-         sizeof(*ftask) * silc_hash_table_count(schedule->fd_queue));
-  fprintf(stdout, "Num Timeout tasks    : %d (%lu bytes allocated)\n",
-         silc_list_count(schedule->timeout_queue),
-         sizeof(struct SilcTaskTimeoutStruct) *
-         silc_list_count(schedule->timeout_queue));
-  fprintf(stdout, "Num Timeout freelist : %d (%lu bytes allocated)\n",
-         silc_list_count(schedule->free_tasks),
-         sizeof(struct SilcTaskTimeoutStruct) *
-         silc_list_count(schedule->free_tasks));
-}
-#endif /* SILC_DIST_INPLACE */
-
-/****************************** Public API **********************************/
-
-/* Initializes the scheduler. This returns the scheduler context that
-   is given as arugment usually to all silc_schedule_* functions.
-   The `max_tasks' indicates the number of maximum tasks that the
-   scheduler can handle. The `app_context' is application specific
-   context that is delivered to task callbacks. */
-
-SilcSchedule silc_schedule_init(int max_tasks, void *app_context,
-                               SilcStack stack, SilcSchedule parent)
-{
-  SilcSchedule schedule;
-
-  /* Initialize Tls, in case it hasn't been done yet */
-  silc_thread_tls_init();
-
-  stack = silc_stack_alloc(0, stack);
-  if (!stack)
-    return NULL;
-
-  /* Allocate scheduler from the stack */
-  schedule = silc_scalloc(stack, 1, sizeof(*schedule));
-  if (!schedule)
-    return NULL;
-
-  SILC_LOG_DEBUG(("Initializing scheduler %p", schedule));
-
-  /* Allocate Fd task hash table dynamically */
-  schedule->fd_queue =
-    silc_hash_table_alloc(NULL, 0, silc_hash_uint, NULL, NULL, NULL,
-                         silc_schedule_fd_destructor, NULL, TRUE);
-  if (!schedule->fd_queue) {
-    silc_stack_free(stack);
-    return NULL;
-  }
-
-  silc_list_init(schedule->timeout_queue, struct SilcTaskStruct, next);
-  silc_list_init(schedule->free_tasks, struct SilcTaskStruct, next);
-
-  /* Get the parent */
-  if (parent && parent->parent)
-    parent = parent->parent;
-
-  schedule->stack = stack;
-  schedule->app_context = app_context;
-  schedule->valid = TRUE;
-  schedule->max_tasks = max_tasks;
-  schedule->parent = parent;
-
-  /* Allocate scheduler lock */
-  silc_mutex_alloc(&schedule->lock);
-
-  /* Initialize the platform specific scheduler. */
-  schedule->internal = schedule_ops.init(schedule, app_context);
-  if (!schedule->internal) {
-    silc_hash_table_free(schedule->fd_queue);
-    silc_mutex_free(schedule->lock);
-    silc_stack_free(stack);
-    return NULL;
-  }
-
-  /* Timeout freelist garbage collection */
-  silc_schedule_task_add_timeout(schedule, silc_schedule_timeout_gc,
-                                schedule, 3600, 0);
-
-  return schedule;
-}
-
-/* Uninitializes the schedule. This is called when the program is ready
-   to end. This removes all tasks and task queues. Returns FALSE if the
-   scheduler could not be uninitialized. This happens when the scheduler
-   is still valid and silc_schedule_stop has not been called. */
-
-SilcBool silc_schedule_uninit(SilcSchedule schedule)
-{
-  SilcTask task;
-
-  SILC_VERIFY(schedule);
-
-  SILC_LOG_DEBUG(("Uninitializing scheduler %p", schedule));
-
-  if (schedule->valid == TRUE)
-    return FALSE;
-
-  /* Dispatch all timeouts before going away */
-  SILC_SCHEDULE_LOCK(schedule);
-  silc_schedule_dispatch_timeout(schedule, TRUE);
-  SILC_SCHEDULE_UNLOCK(schedule);
-
-  /* Deliver signals before going away */
-  if (schedule->signal_tasks) {
-    schedule_ops.signals_call(schedule, schedule->internal);
-    schedule->signal_tasks = FALSE;
-  }
-
-  /* Unregister all tasks */
-  silc_schedule_task_del(schedule, SILC_ALL_TASKS);
-  silc_schedule_task_remove(schedule, SILC_ALL_TASKS);
-
-  /* Delete timeout task freelist */
-  silc_list_start(schedule->free_tasks);
-  while ((task = silc_list_get(schedule->free_tasks)))
-    silc_free(task);
-
-  /* Unregister all task queues */
-  silc_hash_table_free(schedule->fd_queue);
-
-  /* Uninit the platform specific scheduler. */
-  schedule_ops.uninit(schedule, schedule->internal);
-
-  silc_mutex_free(schedule->lock);
-  silc_stack_free(schedule->stack);
-
-  return TRUE;
-}
-
-/* Stops the schedule even if it is not supposed to be stopped yet.
-   After calling this, one should call silc_schedule_uninit (after the
-   silc_schedule has returned). */
-
-void silc_schedule_stop(SilcSchedule schedule)
-{
-  SILC_LOG_DEBUG(("Stopping scheduler"));
-  SILC_VERIFY(schedule);
-  SILC_SCHEDULE_LOCK(schedule);
-  schedule->valid = FALSE;
-  SILC_SCHEDULE_UNLOCK(schedule);
-}
-
-/* Runs the scheduler once and then returns.   Must be called locked. */
-
-static SilcBool silc_schedule_iterate(SilcSchedule schedule, int timeout_usecs)
-{
-  struct timeval timeout;
-  int ret;
-
-  do {
-    SILC_LOG_DEBUG(("In scheduler loop"));
-
-    /* Deliver signals if any has been set to be called */
-    if (silc_unlikely(schedule->signal_tasks)) {
-      SILC_SCHEDULE_UNLOCK(schedule);
-      schedule_ops.signals_call(schedule, schedule->internal);
-      schedule->signal_tasks = FALSE;
-      SILC_SCHEDULE_LOCK(schedule);
-    }
-
-    /* Check if scheduler is valid */
-    if (silc_unlikely(schedule->valid == FALSE)) {
-      SILC_LOG_DEBUG(("Scheduler not valid anymore, exiting"));
-      return FALSE;
-    }
-
-    /* Calculate next timeout for silc_select().  This is the timeout value
-       when at earliest some of the timeout tasks expire.  This may dispatch
-       already expired timeouts. */
-    silc_schedule_select_timeout(schedule);
-
-    /* Check if scheduler is valid */
-    if (silc_unlikely(schedule->valid == FALSE)) {
-      SILC_LOG_DEBUG(("Scheduler not valid anymore, exiting"));
-      return FALSE;
-    }
-
-    if (timeout_usecs >= 0) {
-      timeout.tv_sec = 0;
-      timeout.tv_usec = timeout_usecs;
-      schedule->timeout = timeout;
-      schedule->has_timeout = TRUE;
-    }
-
-    /* This is the main silc_select(). The program blocks here until some
-       of the selected file descriptors change status or the selected
-       timeout expires. */
-    SILC_LOG_DEBUG(("Select"));
-    ret = schedule_ops.schedule(schedule, schedule->internal);
-
-    if (silc_likely(ret == 0)) {
-      /* Timeout */
-      SILC_LOG_DEBUG(("Running timeout tasks"));
-      if (silc_likely(silc_list_count(schedule->timeout_queue)))
-       silc_schedule_dispatch_timeout(schedule, FALSE);
-      continue;
-
-    } else if (silc_likely(ret > 0)) {
-      /* There is some data available now */
-      SILC_LOG_DEBUG(("Running fd tasks"));
-      silc_schedule_dispatch_fd(schedule);
-
-      /* If timeout was very short, dispatch also timeout tasks */
-      if (schedule->has_timeout && schedule->timeout.tv_sec == 0 &&
-         schedule->timeout.tv_usec < 50000)
-       silc_schedule_dispatch_timeout(schedule, FALSE);
-      continue;
-
-    } else {
-      /* Error or special case handling */
-      if (errno == EINTR)
-       continue;
-      if (ret == -2)
-       break;
-
-      SILC_LOG_ERROR(("Error in select()/poll(): %s", strerror(errno)));
-      continue;
-    }
-  } while (timeout_usecs == -1);
-
-  return TRUE;
-}
-
-/* Runs the scheduler once and then returns. */
-
-SilcBool silc_schedule_one(SilcSchedule schedule, int timeout_usecs)
-{
-  SilcBool ret;
-  SILC_SCHEDULE_LOCK(schedule);
-  ret = silc_schedule_iterate(schedule, timeout_usecs);
-  SILC_SCHEDULE_UNLOCK(schedule);
-  return ret;
-}
-
-/* Runs the scheduler and blocks here.  When this returns the scheduler
-   has ended. */
-
-#ifndef SILC_SYMBIAN
-void silc_schedule(SilcSchedule schedule)
-{
-  SILC_LOG_DEBUG(("Running scheduler"));
-
-  /* Start the scheduler loop */
-  SILC_SCHEDULE_LOCK(schedule);
-  silc_schedule_iterate(schedule, -1);
-  SILC_SCHEDULE_UNLOCK(schedule);
-}
-#endif /* !SILC_SYMBIAN */
-
-/* Wakes up the scheduler. This is used only in multi-threaded
-   environments where threads may add new tasks or remove old tasks
-   from task queues. This is called to wake up the scheduler in the
-   main thread so that it detects the changes in the task queues.
-   If threads support is not compiled in this function has no effect.
-   Implementation of this function is platform specific. */
-
-void silc_schedule_wakeup(SilcSchedule schedule)
-{
-#ifdef SILC_THREADS
-  SILC_LOG_DEBUG(("Wakeup scheduler"));
-  SILC_SCHEDULE_LOCK(schedule);
-  schedule_ops.wakeup(schedule, schedule->internal);
-  SILC_SCHEDULE_UNLOCK(schedule);
-#endif
-}
-
-/* Returns parent scheduler */
-
-SilcSchedule silc_schedule_get_parent(SilcSchedule schedule)
-{
-  return schedule->parent ? schedule->parent : schedule;
-}
-
-/* Returns the application specific context that was saved into the
-   scheduler in silc_schedule_init function.  The context is also
-   returned to application in task callback functions, but this function
-   may be used to get it as well if needed. */
-
-void *silc_schedule_get_context(SilcSchedule schedule)
-{
-  return schedule->app_context;
-}
-
-/* Return the stack of the scheduler */
-
-SilcStack silc_schedule_get_stack(SilcSchedule schedule)
-{
-  return schedule->stack;
-}
-
-/* Set notify callback */
-
-void silc_schedule_set_notify(SilcSchedule schedule,
-                             SilcTaskNotifyCb notify, void *context)
-{
-  schedule->notify = notify;
-  schedule->notify_context = context;
-}
-
-/* Set global scheduler */
-
-void silc_schedule_set_global(SilcSchedule schedule)
-{
-  SilcTls tls = silc_thread_get_tls();
-
-  if (!tls) {
-    /* Try to initialize Tls */
-    tls = silc_thread_tls_init();
-    SILC_VERIFY(tls);
-    if (!tls)
-      return;
-  }
-
-  SILC_LOG_DEBUG(("Setting global scheduler %p", schedule));
-
-  tls->schedule = schedule;
-}
-
-/* Return global scheduler */
-
-SilcSchedule silc_schedule_get_global(void)
-{
-  SilcTls tls = silc_thread_get_tls();
-
-  if (!tls)
-    return NULL;
-
-  SILC_LOG_DEBUG(("Return global scheduler %p", tls->schedule));
-
-  return tls->schedule;
-}
-
-/* Add new task to the scheduler */
-
-SilcTask silc_schedule_task_add(SilcSchedule schedule, SilcUInt32 fd,
-                               SilcTaskCallback callback, void *context,
-                               long seconds, long useconds,
-                               SilcTaskType type)
-{
-  SilcTask task = NULL;
-
-  if (!schedule) {
-    schedule = silc_schedule_get_global();
-    SILC_VERIFY(schedule);
-    if (!schedule) {
-      silc_set_errno(SILC_ERR_INVALID_ARGUMENT);
-      return NULL;
-    }
-  }
-
-  if (silc_unlikely(!schedule->valid)) {
-    silc_set_errno(SILC_ERR_NOT_VALID);
-    return NULL;
-  }
-
-  SILC_SCHEDULE_LOCK(schedule);
-
-  if (silc_likely(type == SILC_TASK_TIMEOUT)) {
-    SilcTaskTimeout tmp, prev, ttask;
-    SilcList list;
-
-    silc_list_start(schedule->free_tasks);
-    ttask = silc_list_get(schedule->free_tasks);
-    if (silc_unlikely(!ttask)) {
-      ttask = silc_calloc(1, sizeof(*ttask));
-      if (silc_unlikely(!ttask))
-       goto out;
-    } else
-      silc_list_del(schedule->free_tasks, ttask);
-
-    ttask->header.type = 1;
-    ttask->header.callback = callback;
-    ttask->header.context = context;
-    ttask->header.valid = TRUE;
-
-    /* Add timeout */
-    silc_gettimeofday(&ttask->timeout);
-    if ((seconds + useconds) > 0) {
-      ttask->timeout.tv_sec += seconds + (useconds / 1000000L);
-      ttask->timeout.tv_usec += (useconds % 1000000L);
-      if (ttask->timeout.tv_usec >= 1000000L) {
-       ttask->timeout.tv_sec += 1;
-       ttask->timeout.tv_usec -= 1000000L;
-      }
-    }
-
-    SILC_LOG_DEBUG(("New timeout task %p: sec=%d, usec=%d", ttask,
-                   seconds, useconds));
-
-    /* Add task to correct spot so that the first task in the list has
-       the earliest timeout. */
-    list = schedule->timeout_queue;
-    silc_list_start(list);
-    prev = NULL;
-    while ((tmp = silc_list_get(list)) != SILC_LIST_END) {
-      /* If we have shorter timeout, we have found our spot */
-      if (silc_compare_timeval(&ttask->timeout, &tmp->timeout) < 0) {
-       silc_list_insert(schedule->timeout_queue, prev, ttask);
-       break;
-      }
-      prev = tmp;
-    }
-    if (!tmp)
-      silc_list_add(schedule->timeout_queue, ttask);
-
-    task = (SilcTask)ttask;
-
-    /* Call notify callback */
-    if (schedule->notify)
-      schedule->notify(schedule, TRUE, task, FALSE, 0, 0, seconds, useconds,
-                      schedule->notify_context);
-
-  } else if (silc_likely(type == SILC_TASK_FD)) {
-    SilcTaskFd ftask;
-
-    /* Check if fd is already added */
-    if (silc_unlikely(silc_hash_table_find(schedule->fd_queue,
-                                          SILC_32_TO_PTR(fd),
-                                          NULL, (void *)&task))) {
-      if (task->valid)
-        goto out;
-
-      /* Remove invalid task.  We must have unique fd key to hash table. */
-      silc_schedule_task_remove(schedule, task);
-    }
-
-    /* Check max tasks */
-    if (silc_unlikely(schedule->max_tasks > 0 &&
-                     silc_hash_table_count(schedule->fd_queue) >=
-                     schedule->max_tasks)) {
-      SILC_LOG_WARNING(("Scheduler task limit reached: cannot add new task"));
-      task = NULL;
-      silc_set_errno(SILC_ERR_LIMIT);
-      goto out;
-    }
-
-    ftask = silc_calloc(1, sizeof(*ftask));
-    if (silc_unlikely(!ftask)) {
-      task = NULL;
-      goto out;
-    }
-
-    SILC_LOG_DEBUG(("New fd task %p fd=%d", ftask, fd));
-
-    ftask->header.type = 0;
-    ftask->header.callback = callback;
-    ftask->header.context = context;
-    ftask->header.valid = TRUE;
-    ftask->events = SILC_TASK_READ;
-    ftask->fd = fd;
-
-    /* Add task and schedule it */
-    if (!silc_hash_table_add(schedule->fd_queue, SILC_32_TO_PTR(fd), ftask)) {
-      silc_free(ftask);
-      task = NULL;
-      goto out;
-    }
-    if (!schedule_ops.schedule_fd(schedule, schedule->internal,
-                                 ftask, ftask->events)) {
-      silc_hash_table_del(schedule->fd_queue, SILC_32_TO_PTR(fd));
-      task = NULL;
-      goto out;
-    }
-
-    task = (SilcTask)ftask;
-
-    /* Call notify callback */
-    if (schedule->notify)
-      schedule->notify(schedule, TRUE, task, TRUE, ftask->fd,
-                      SILC_TASK_READ, 0, 0, schedule->notify_context);
-
-  } else if (silc_unlikely(type == SILC_TASK_SIGNAL)) {
-    SILC_SCHEDULE_UNLOCK(schedule);
-    schedule_ops.signal_register(schedule, schedule->internal, fd,
-                                callback, context);
-    return NULL;
-  }
-
- out:
-  SILC_SCHEDULE_UNLOCK(schedule);
-
-#ifdef SILC_SYMBIAN
-  /* On symbian we wakeup scheduler immediately after adding timeout task
-     in case the task is added outside the scheduler loop (in some active
-     object). */
-  if (task && task->type == 1)
-    silc_schedule_wakeup(schedule);
-#endif /* SILC_SYMBIAN */
-
-  return task;
-}
-
-/* Invalidates task */
-
-SilcBool silc_schedule_task_del(SilcSchedule schedule, SilcTask task)
-{
-  SilcSchedule parent;
-
-  if (!schedule) {
-    schedule = silc_schedule_get_global();
-    SILC_VERIFY(schedule);
-    if (!schedule) {
-      silc_set_errno(SILC_ERR_INVALID_ARGUMENT);
-      return FALSE;
-    }
-  }
-
-  if (silc_unlikely(task == SILC_ALL_TASKS)) {
-    SilcHashTableList htl;
-
-    SILC_LOG_DEBUG(("Unregister all tasks"));
-
-    SILC_SCHEDULE_LOCK(schedule);
-
-    /* Delete from fd queue */
-    silc_hash_table_list(schedule->fd_queue, &htl);
-    while (silc_hash_table_get(&htl, NULL, (void *)&task)) {
-      task->valid = FALSE;
-
-      /* Call notify callback */
-      if (schedule->notify)
-       schedule->notify(schedule, FALSE, task, TRUE,
-                        ((SilcTaskFd)task)->fd, 0, 0, 0,
-                        schedule->notify_context);
-    }
-    silc_hash_table_list_reset(&htl);
-
-    /* Delete from timeout queue */
-    silc_list_start(schedule->timeout_queue);
-    while ((task = (SilcTask)silc_list_get(schedule->timeout_queue))) {
-      task->valid = FALSE;
-
-      /* Call notify callback */
-      if (schedule->notify)
-       schedule->notify(schedule, FALSE, task, FALSE, 0, 0, 0, 0,
-                        schedule->notify_context);
-    }
-
-    /* Delete even tasks */
-    parent = silc_schedule_get_parent(schedule);
-    silc_hash_table_list(parent->events, &htl);
-    while (silc_hash_table_get(&htl, NULL, (void *)&task))
-      task->valid = FALSE;
-    silc_hash_table_list_reset(&htl);
-
-    SILC_SCHEDULE_UNLOCK(schedule);
-    return TRUE;
-  }
-
-  SILC_LOG_DEBUG(("Unregistering task %p, type %d", task, task->type));
-  SILC_SCHEDULE_LOCK(schedule);
-  task->valid = FALSE;
-
-  /* Call notify callback */
-  if (schedule->notify && task->type != SILC_TASK_EVENT)
-    schedule->notify(schedule, FALSE, task, task->type == SILC_TASK_FD,
-                    0, 0, 0, 0, schedule->notify_context);
-  SILC_SCHEDULE_UNLOCK(schedule);
-
-  if (task->type == SILC_TASK_EVENT) {
-    /* Schedule removal of deleted event task */
-    parent = silc_schedule_get_parent(schedule);
-    silc_schedule_task_add_timeout(parent, silc_schedule_event_del_timeout,
-                                  task, 0, 1);
-  }
-
-  return TRUE;
-}
-
-/* Invalidate task by fd */
-
-SilcBool silc_schedule_task_del_by_fd(SilcSchedule schedule, SilcUInt32 fd)
-{
-  SilcTask task = NULL;
-  SilcBool ret = FALSE;
-
-  SILC_LOG_DEBUG(("Unregister task by fd %d", fd));
-
-  if (!schedule) {
-    schedule = silc_schedule_get_global();
-    SILC_VERIFY(schedule);
-    if (!schedule) {
-      silc_set_errno(SILC_ERR_INVALID_ARGUMENT);
-      return FALSE;
-    }
-  }
-
-  SILC_SCHEDULE_LOCK(schedule);
-
-  /* fd is unique, so there is only one task with this fd in the table */
-  if (silc_likely(silc_hash_table_find(schedule->fd_queue,
-                                      SILC_32_TO_PTR(fd), NULL,
-                                      (void *)&task))) {
-    SILC_LOG_DEBUG(("Deleting task %p", task));
-    task->valid = FALSE;
-
-    /* Call notify callback */
-    if (schedule->notify)
-      schedule->notify(schedule, FALSE, task, TRUE, fd, 0, 0, 0,
-                      schedule->notify_context);
-    ret = TRUE;
-  }
-
-  SILC_SCHEDULE_UNLOCK(schedule);
-
-  /* If it is signal, remove it */
-  if (silc_unlikely(!task)) {
-    schedule_ops.signal_unregister(schedule, schedule->internal, fd);
-    ret = TRUE;
-  }
-
-  if (ret == FALSE)
-    silc_set_errno(SILC_ERR_NOT_FOUND);
-
-  return ret;
-}
-
-/* Invalidate task by task callback. */
-
-SilcBool silc_schedule_task_del_by_callback(SilcSchedule schedule,
-                                           SilcTaskCallback callback)
-{
-  SilcTask task;
-  SilcHashTableList htl;
-  SilcList list;
-  SilcBool ret = FALSE;
-
-  SILC_LOG_DEBUG(("Unregister task by callback"));
-
-  if (!schedule) {
-    schedule = silc_schedule_get_global();
-    SILC_VERIFY(schedule);
-    if (!schedule) {
-      silc_set_errno(SILC_ERR_INVALID_ARGUMENT);
-      return FALSE;
-    }
-  }
-
-  SILC_SCHEDULE_LOCK(schedule);
-
-  /* Delete from fd queue */
-  silc_hash_table_list(schedule->fd_queue, &htl);
-  while (silc_hash_table_get(&htl, NULL, (void *)&task)) {
-    if (task->callback == callback) {
-      task->valid = FALSE;
-
-      /* Call notify callback */
-      if (schedule->notify)
-       schedule->notify(schedule, FALSE, task, TRUE,
-                        ((SilcTaskFd)task)->fd, 0, 0, 0,
-                        schedule->notify_context);
-      ret = TRUE;
-    }
-  }
-  silc_hash_table_list_reset(&htl);
-
-  /* Delete from timeout queue */
-  list = schedule->timeout_queue;
-  silc_list_start(list);
-  while ((task = (SilcTask)silc_list_get(list))) {
-    if (task->callback == callback) {
-      task->valid = FALSE;
-
-      /* Call notify callback */
-      if (schedule->notify)
-       schedule->notify(schedule, FALSE, task, FALSE, 0, 0, 0, 0,
-                        schedule->notify_context);
-      ret = TRUE;
-    }
-  }
-
-  SILC_SCHEDULE_UNLOCK(schedule);
-
-  if (ret == FALSE)
-    silc_set_errno(SILC_ERR_NOT_FOUND);
-
-  return ret;
-}
-
-/* Invalidate task by context. */
-
-SilcBool silc_schedule_task_del_by_context(SilcSchedule schedule,
-                                          void *context)
-{
-  SilcTask task;
-  SilcHashTableList htl;
-  SilcList list;
-  SilcBool ret = FALSE;
-
-  SILC_LOG_DEBUG(("Unregister task by context"));
-
-  if (!schedule) {
-    schedule = silc_schedule_get_global();
-    SILC_VERIFY(schedule);
-    if (!schedule) {
-      silc_set_errno(SILC_ERR_INVALID_ARGUMENT);
-      return FALSE;
-    }
-  }
-
-  SILC_SCHEDULE_LOCK(schedule);
-
-  /* Delete from fd queue */
-  silc_hash_table_list(schedule->fd_queue, &htl);
-  while (silc_hash_table_get(&htl, NULL, (void *)&task)) {
-    if (task->context == context) {
-      task->valid = FALSE;
-
-      /* Call notify callback */
-      if (schedule->notify)
-       schedule->notify(schedule, FALSE, task, TRUE,
-                        ((SilcTaskFd)task)->fd, 0, 0, 0,
-                        schedule->notify_context);
-      ret = TRUE;
-    }
-  }
-  silc_hash_table_list_reset(&htl);
-
-  /* Delete from timeout queue */
-  list = schedule->timeout_queue;
-  silc_list_start(list);
-  while ((task = (SilcTask)silc_list_get(list))) {
-    if (task->context == context) {
-      task->valid = FALSE;
-
-      /* Call notify callback */
-      if (schedule->notify)
-       schedule->notify(schedule, FALSE, task, FALSE, 0, 0, 0, 0,
-                        schedule->notify_context);
-      ret = TRUE;
-    }
-  }
-
-  SILC_SCHEDULE_UNLOCK(schedule);
-
-  if (ret == FALSE)
-    silc_set_errno(SILC_ERR_NOT_FOUND);
-
-  return ret;
-}
-
-/* Invalidate task by all */
-
-SilcBool silc_schedule_task_del_by_all(SilcSchedule schedule, int fd,
-                                      SilcTaskCallback callback,
-                                      void *context)
-{
-  SilcTask task;
-  SilcList list;
-  SilcBool ret = FALSE;
-
-  SILC_LOG_DEBUG(("Unregister task by fd, callback and context"));
-
-  /* For fd task, callback and context is irrelevant as fd is unique */
-  if (fd)
-    return silc_schedule_task_del_by_fd(schedule, fd);
-
-  if (!schedule) {
-    schedule = silc_schedule_get_global();
-    SILC_VERIFY(schedule);
-    if (!schedule) {
-      silc_set_errno(SILC_ERR_INVALID_ARGUMENT);
-      return FALSE;
-    }
-  }
-
-  SILC_SCHEDULE_LOCK(schedule);
-
-  /* Delete from timeout queue */
-  list = schedule->timeout_queue;
-  silc_list_start(list);
-  while ((task = (SilcTask)silc_list_get(list))) {
-    if (task->callback == callback && task->context == context) {
-      task->valid = FALSE;
-
-      /* Call notify callback */
-      if (schedule->notify)
-       schedule->notify(schedule, FALSE, task, FALSE, 0, 0, 0, 0,
-                        schedule->notify_context);
-      ret = TRUE;
-    }
-  }
-
-  SILC_SCHEDULE_UNLOCK(schedule);
-
-  if (ret == FALSE)
-    silc_set_errno(SILC_ERR_NOT_FOUND);
-
-  return TRUE;
-}
-
-/* Sets a file descriptor to be listened by scheduler. One can call this
-   directly if wanted. This can be called multiple times for one file
-   descriptor to set different iomasks. */
-
-SilcBool silc_schedule_set_listen_fd(SilcSchedule schedule, SilcUInt32 fd,
-                                    SilcTaskEvent mask, SilcBool send_events)
-{
-  SilcTaskFd task;
-
-  if (!schedule) {
-    schedule = silc_schedule_get_global();
-    SILC_VERIFY(schedule);
-    if (!schedule) {
-      silc_set_errno(SILC_ERR_INVALID_ARGUMENT);
-      return FALSE;
-    }
-  }
-
-  if (silc_unlikely(!schedule->valid)) {
-    silc_set_errno(SILC_ERR_NOT_VALID);
-    return FALSE;
-  }
-
-  SILC_SCHEDULE_LOCK(schedule);
-
-  if (silc_hash_table_find(schedule->fd_queue, SILC_32_TO_PTR(fd),
-                          NULL, (void *)&task)) {
-    if (!schedule_ops.schedule_fd(schedule, schedule->internal, task, mask)) {
-      SILC_SCHEDULE_UNLOCK(schedule);
-      return FALSE;
-    }
-    task->events = mask;
-    if (silc_unlikely(send_events) && mask) {
-      task->revents = mask;
-      silc_schedule_dispatch_fd(schedule);
-    }
-
-    /* Call notify callback */
-    if (schedule->notify)
-      schedule->notify(schedule, TRUE, (SilcTask)task,
-                      TRUE, task->fd, mask, 0, 0,
-                      schedule->notify_context);
-  }
-
-  SILC_SCHEDULE_UNLOCK(schedule);
-
-  return TRUE;
-}
-
-/* Returns the file descriptor's current requested event mask. */
-
-SilcTaskEvent silc_schedule_get_fd_events(SilcSchedule schedule,
-                                         SilcUInt32 fd)
-{
-  SilcTaskFd task;
-  SilcTaskEvent event = 0;
-
-  if (!schedule) {
-    schedule = silc_schedule_get_global();
-    SILC_VERIFY(schedule);
-    if (!schedule) {
-      silc_set_errno(SILC_ERR_INVALID_ARGUMENT);
-      return 0;
-    }
-  }
-
-  if (silc_unlikely(!schedule->valid)) {
-    silc_set_errno(SILC_ERR_NOT_VALID);
-    return 0;
-  }
-
-  SILC_SCHEDULE_LOCK(schedule);
-  if (silc_hash_table_find(schedule->fd_queue, SILC_32_TO_PTR(fd),
-                          NULL, (void *)&task))
-    event = task->events;
-  SILC_SCHEDULE_UNLOCK(schedule);
-
-  return event;
-}
-
-/* Removes a file descriptor from listen list. */
-
-void silc_schedule_unset_listen_fd(SilcSchedule schedule, SilcUInt32 fd)
-{
-  silc_schedule_set_listen_fd(schedule, fd, 0, FALSE);
-}
-
-/*************************** Asynchronous Events ****************************/
-
-/* Add event */
-
-SilcTask silc_schedule_task_add_event(SilcSchedule schedule,
-                                     const char *event, ...)
-{
-  SilcEventTask task;
-  SilcSchedule parent;
-
-  if (!schedule) {
-    schedule = silc_schedule_get_global();
-    SILC_VERIFY(schedule);
-    if (!schedule) {
-      silc_set_errno(SILC_ERR_INVALID_ARGUMENT);
-      return NULL;
-    }
-  }
-
-  /* Get parent scheduler */
-  parent = silc_schedule_get_parent(schedule);
-
-  SILC_LOG_DEBUG(("Adding event '%s' to scheduler %p", event, parent));
-
-  SILC_SCHEDULE_LOCK(parent);
-
-  /* Create events hash table if not already done */
-  if (!parent->events) {
-    parent->events = silc_hash_table_alloc(NULL, 3,
-                                          silc_hash_string, NULL,
-                                          silc_hash_string_compare, NULL,
-                                          NULL, NULL, FALSE);
-    if (!parent->events) {
-      SILC_SCHEDULE_UNLOCK(parent);
-      return NULL;
-    }
-  }
-
-  /* Check if this event is added already */
-  if (silc_hash_table_find(parent->events, (void *)event, NULL, NULL)) {
-    SILC_SCHEDULE_UNLOCK(parent);
-    return NULL;
-  }
-
-  /* Add new event */
-  task = silc_calloc(1, sizeof(*task));
-  if (!task) {
-    SILC_SCHEDULE_UNLOCK(parent);
-    return NULL;
-  }
-
-  task->header.type = SILC_TASK_EVENT;
-  task->header.valid = TRUE;
-  task->event = silc_strdup(event);
-  if (!task->event) {
-    SILC_SCHEDULE_UNLOCK(parent);
-    silc_free(task);
-    return NULL;
-  }
-  silc_list_init(task->connections, struct SilcScheduleEventConnectionStruct,
-                next);
-
-  if (!silc_hash_table_add(parent->events, task->event, task)) {
-    SILC_SCHEDULE_UNLOCK(parent);
-    silc_free(task->event);
-    silc_free(task);
-    return NULL;
-  }
-
-  SILC_SCHEDULE_UNLOCK(parent);
-
-  return (SilcTask)task;
-}
-
-/* Connect to event task */
-
-SilcBool silc_schedule_event_connect(SilcSchedule schedule,
-                                    const char *event, SilcTask task,
-                                    SilcTaskEventCallback callback,
-                                    void *context)
-{
-  SilcSchedule parent;
-  SilcScheduleEventConnection conn;
-  SilcEventTask etask;
-
-  if (!schedule) {
-    schedule = silc_schedule_get_global();
-    SILC_VERIFY(schedule);
-    if (!schedule) {
-      silc_set_errno(SILC_ERR_INVALID_ARGUMENT);
-      return FALSE;
-    }
-  }
-
-  if (!event && !task) {
-    silc_set_errno(SILC_ERR_INVALID_ARGUMENT);
-    return FALSE;
-  }
-
-  if (task && task->type != SILC_TASK_EVENT) {
-    silc_set_errno(SILC_ERR_INVALID_ARGUMENT);
-    return FALSE;
-  }
-
-  /* Get parent scheduler */
-  parent = silc_schedule_get_parent(schedule);
-
-  SILC_SCHEDULE_LOCK(parent);
-
-  if (!task) {
-    /* Get the event task */
-    if (!silc_hash_table_find(parent->events, (void *)event, NULL,
-                             (void *)&task)) {
-      SILC_SCHEDULE_UNLOCK(parent);
-      return FALSE;
-    }
-  }
-  etask = (SilcEventTask)task;
-
-  /* See if task is deleted */
-  if (task->valid == FALSE) {
-    SILC_SCHEDULE_UNLOCK(parent);
-    silc_set_errno(SILC_ERR_NOT_VALID);
-    return FALSE;
-  }
-
-  SILC_LOG_DEBUG(("Connect callback %p with context %p to event '%s'",
-                 callback, context, etask->event));
-
-  /* See if already connected */
-  silc_list_start(etask->connections);
-  while ((conn = silc_list_get(etask->connections))) {
-    if (conn->callback == callback && conn->context == context) {
-      SILC_SCHEDULE_UNLOCK(parent);
-      silc_set_errno(SILC_ERR_ALREADY_EXISTS);
-      return FALSE;
-    }
-  }
-
-  conn = silc_calloc(1, sizeof(*conn));
-  if (!conn) {
-    SILC_SCHEDULE_UNLOCK(parent);
-    return FALSE;
-  }
-
-  /* Connect to the event */
-  conn->schedule = schedule;
-  conn->callback = callback;
-  conn->context = context;
-  silc_list_add(etask->connections, conn);
-
-  SILC_SCHEDULE_UNLOCK(parent);
-
-  return TRUE;
-}
-
-/* Disconnect from event */
-
-SilcBool silc_schedule_event_disconnect(SilcSchedule schedule,
-                                       const char *event, SilcTask task,
-                                       SilcTaskEventCallback callback,
-                                       void *context)
-{
-  SilcSchedule parent;
-  SilcScheduleEventConnection conn;
-  SilcEventTask etask;
-
-  if (!schedule) {
-    schedule = silc_schedule_get_global();
-    SILC_VERIFY(schedule);
-    if (!schedule) {
-      silc_set_errno(SILC_ERR_INVALID_ARGUMENT);
-      return FALSE;
-    }
-  }
-
-  if (!event && !task) {
-    silc_set_errno(SILC_ERR_INVALID_ARGUMENT);
-    return FALSE;
-  }
-
-  if (task && task->type != SILC_TASK_EVENT) {
-    silc_set_errno(SILC_ERR_INVALID_ARGUMENT);
-    return FALSE;
-  }
-
-  /* Get parent scheduler */
-  parent = silc_schedule_get_parent(schedule);
-
-  SILC_SCHEDULE_LOCK(parent);
-
-  if (!task) {
-    /* Get the event task */
-    if (!silc_hash_table_find(parent->events, (void *)event, NULL,
-                             (void *)&task)) {
-      SILC_SCHEDULE_UNLOCK(parent);
-      return FALSE;
-    }
-  }
-  etask = (SilcEventTask)task;
-
-  /* See if task is deleted */
-  if (task->valid == FALSE) {
-    SILC_SCHEDULE_UNLOCK(parent);
-    silc_set_errno(SILC_ERR_NOT_VALID);
-    return FALSE;
-  }
-
-  SILC_LOG_DEBUG(("Disconnect callback %p with context %p from event '%s'",
-                 callback, context, etask->event));
-
-  /* Disconnect */
-  silc_list_start(etask->connections);
-  while ((conn = silc_list_get(etask->connections))) {
-    if (conn->callback == callback && conn->context == context) {
-      silc_list_del(etask->connections, conn);
-      silc_free(conn);
-      SILC_SCHEDULE_UNLOCK(parent);
-      return TRUE;
-    }
-  }
-
-  SILC_SCHEDULE_UNLOCK(parent);
-  silc_set_errno(SILC_ERR_NOT_FOUND);
-  return FALSE;
-}
-
-/* Signal event */
-
-SilcBool silc_schedule_event_signal(SilcSchedule schedule, const char *event,
-                                   SilcTask task, ...)
-{
-  SilcSchedule parent;
-  SilcScheduleEventConnection conn;
-  SilcEventTask etask;
-  SilcBool stop;
-  va_list ap, cp;
-
-  if (silc_unlikely(!schedule)) {
-    schedule = silc_schedule_get_global();
-    SILC_VERIFY(schedule);
-    if (!schedule) {
-      silc_set_errno(SILC_ERR_INVALID_ARGUMENT);
-      return FALSE;
-    }
-  }
-
-  if (silc_unlikely(!event && !task)) {
-    silc_set_errno(SILC_ERR_INVALID_ARGUMENT);
-    return FALSE;
-  }
-
-  if (silc_unlikely(task && task->type != SILC_TASK_EVENT)) {
-    silc_set_errno(SILC_ERR_INVALID_ARGUMENT);
-    return FALSE;
-  }
-
-  /* Get parent scheduler */
-  parent = silc_schedule_get_parent(schedule);
-
-  SILC_SCHEDULE_LOCK(parent);
-
-  if (!task) {
-    /* Get the event task */
-    if (!silc_hash_table_find(parent->events, (void *)event, NULL,
-                             (void *)&task)) {
-      SILC_SCHEDULE_UNLOCK(parent);
-      return FALSE;
-    }
-  }
-  etask = (SilcEventTask)task;
-
-  /* See if task is deleted */
-  if (task->valid == FALSE) {
-    SILC_SCHEDULE_UNLOCK(parent);
-    silc_set_errno(SILC_ERR_NOT_VALID);
-    return FALSE;
-  }
-
-  SILC_LOG_DEBUG(("Signal event '%s'", etask->event));
-
-  va_start(ap, task);
-
-  /* Deliver the signal */
-  silc_list_start(etask->connections);
-  while ((conn = silc_list_get(etask->connections))) {
-    SILC_SCHEDULE_UNLOCK(parent);
-
-    silc_va_copy(cp, ap);
-    stop = conn->callback(conn->schedule, conn->schedule->app_context,
-                         task, conn->context, cp);
-    va_end(cp);
-
-    SILC_SCHEDULE_LOCK(parent);
-
-    /* Stop signal if wanted or if the task was deleted */
-    if (!stop || !task->valid)
-      break;
-  }
-
-  va_end(ap);
-
-  SILC_SCHEDULE_UNLOCK(parent);
-
-  return TRUE;
-}
-
-/* Delete event */
-
-SilcBool silc_schedule_task_del_event(SilcSchedule schedule, const char *event)
-{
-  SilcSchedule parent;
-  SilcTask task;
-
-  if (!schedule) {
-    schedule = silc_schedule_get_global();
-    SILC_VERIFY(schedule);
-    if (!schedule) {
-      silc_set_errno(SILC_ERR_INVALID_ARGUMENT);
-      return FALSE;
-    }
-  }
-
-  if (!event) {
-    silc_set_errno(SILC_ERR_INVALID_ARGUMENT);
-    return FALSE;
-  }
-
-  /* Get parent scheduler */
-  parent = silc_schedule_get_parent(schedule);
-
-  SILC_SCHEDULE_LOCK(parent);
-
-  /* Get the event task */
-  if (!silc_hash_table_find(parent->events, (void *)event, NULL,
-                           (void *)&task)) {
-    SILC_SCHEDULE_UNLOCK(parent);
-    return FALSE;
-  }
-
-  /* See if already deleted */
-  if (task->valid == FALSE)
-    return TRUE;
-
-  SILC_LOG_DEBUG(("Delete event '%s'", ((SilcEventTask)task)->event));
-
-  SILC_SCHEDULE_UNLOCK(parent);
-
-  silc_schedule_task_del(parent, task);
-
-  return TRUE;
-}
-
-/* Timeout to remove deleted event task */
-
-SILC_TASK_CALLBACK(silc_schedule_event_del_timeout)
-{
-  SILC_SCHEDULE_LOCK(schedule);
-  silc_schedule_task_remove(schedule, context);
-  SILC_SCHEDULE_UNLOCK(schedule);
-}