Added asynchronous event tasks to SILC Scheduler. Added
[crypto.git] / lib / silcutil / silcschedule_i.h
index 7e2b6026cf14bf95a228cdd2a127b64b4ea78b86..a88df592c8fb7bad88b4f183e16b50dc7a2d3cc8 100644 (file)
@@ -4,13 +4,12 @@
 
   Author: Pekka Riikonen <priikone@silcnet.org>
 
-  Copyright (C) 2001 Pekka Riikonen
+  Copyright (C) 2001 - 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; either version 2 of the License, or
-  (at your option) any later version.
-  
+  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
 #ifndef SILCSCHEDULE_I_H
 #define SILCSCHEDULE_I_H
 
-#include "silcincludes.h"
+#ifndef SILCSCHEDULE_H
+#error "Do not include this header directly"
+#endif
+
+#include "silchashtable.h"
+#include "silclist.h"
+
+/* Task types */
+typedef enum {
+  /* File descriptor task that performs some event over file descriptors.
+     These tasks are for example network connections. */
+  SILC_TASK_FD           = 0,
+
+  /* Timeout tasks are tasks that are executed after the specified
+     time has elapsed. After the task is executed the task is removed
+     automatically from the scheduler. It is safe to re-register the
+     task in task callback. It is also safe to unregister a task in
+     the task callback. */
+  SILC_TASK_TIMEOUT      = 1,
+
+  /* Platform specific process signal task.  On Unix systems this is one of
+     the signals described in signal(7).  On other platforms this may not
+     be available at all.  Only one callback per signal may be added. */
+  SILC_TASK_SIGNAL       = 2,
+
+  /* Asynchronous event task. */
+  SILC_TASK_EVENT        = 3,
+} SilcTaskType;
+
+/* Task header */
+struct SilcTaskStruct {
+  struct SilcTaskStruct *next;
+  SilcTaskCallback callback;
+  void *context;
+  unsigned int type    : 2;    /* SilcTaskType */
+  unsigned int valid   : 1;    /* Set if task is valid */
+};
+
+/* Timeout task */
+typedef struct SilcTaskTimeoutStruct {
+  struct SilcTaskStruct header;
+  struct timeval timeout;
+} *SilcTaskTimeout;
+
+/* Fd task */
+typedef struct SilcTaskFdStruct {
+  struct SilcTaskStruct header;
+  unsigned int scheduled  : 1;
+  unsigned int events     : 14;
+  unsigned int revents    : 14;
+  SilcUInt32 fd;
+} *SilcTaskFd;
+
+/* Event task */
+typedef struct SilcEventTaskStruct {
+  struct SilcTaskStruct header;
+  char *event;
+  SilcList connections;
+} *SilcEventTask;
+
+/* Scheduler context */
+struct SilcScheduleStruct {
+  SilcSchedule parent;            /* Parent scheduler */
+  void *internal;
+  void *app_context;              /* Application specific context */
+  SilcTaskNotifyCb notify;        /* Notify callback */
+  void *notify_context;                   /* Notify context */
+  SilcStack stack;                /* Stack */
+  SilcHashTable events;                   /* Event tasks */
+  SilcHashTable fd_queue;         /* FD task queue */
+  SilcList fd_dispatch;                   /* Dispatched FDs */
+  SilcList timeout_queue;         /* Timeout queue */
+  SilcList free_tasks;            /* Timeout task freelist */
+  SilcMutex lock;                 /* Scheduler lock */
+  struct timeval timeout;         /* Current timeout */
+  unsigned int max_tasks     : 29; /* Max FD tasks */
+  unsigned int has_timeout   : 1;  /* Set if timeout is set */
+  unsigned int valid         : 1;  /* Set if scheduler is valid */
+  unsigned int signal_tasks  : 1;  /* Set if to dispatch signals */
+};
+
+/* Locks. These also blocks signals that we care about and thus guarantee
+   that while we are in scheduler no signals can happen.  This way we can
+   synchronise signals with SILC Scheduler. */
+#define SILC_SCHEDULE_LOCK(schedule)                           \
+do {                                                           \
+  silc_mutex_lock(schedule->lock);                             \
+  schedule_ops.signals_block(schedule, schedule->internal);    \
+} while (0)
+#define SILC_SCHEDULE_UNLOCK(schedule)                         \
+do {                                                           \
+  schedule_ops.signals_unblock(schedule, schedule->internal);  \
+  silc_mutex_unlock(schedule->lock);                           \
+} while (0)
 
-/* Schedule FD structure. Includes the file descriptors that the scheduler
-   will listen. This is given as argument to the silc_select function. */
+/* Platform specific scheduler operations */
 typedef struct {
-  SilcUInt32 fd;                       /* The file descriptor (or handle on WIN32) */
-  SilcUInt16 events;           /* Mask of task events, if events is 0 then
-                                  the fd must be omitted. */
-  SilcUInt16 revents;          /* Returned events mask */
-} *SilcScheduleFd;
+  /* Initializes the platform specific scheduler.  This for example initializes
+     the wakeup mechanism of the scheduler.  In multi-threaded environment
+     the scheduler needs to be wakenup when tasks are added or removed from
+     the task queues.  Returns context to the platform specific scheduler.
+     If this returns NULL the scheduler initialization will fail.  Do not
+     add FD tasks inside function.  Timeout tasks can be added. */
+  void *(*init)(SilcSchedule schedule, void *app_context);
 
-#endif
+  /* Uninitializes the platform specific scheduler context. */
+  void (*uninit)(SilcSchedule schedule, void *context);
+
+  /* System specific waiter. This must fill the schedule->fd_dispatch queue
+     with valid tasks that has something to dispatch, when this returns. */
+  int (*schedule)(SilcSchedule schedule, void *context);
+
+  /* Schedule `task' with events `event_mask'. Zero `event_mask'
+     unschedules the task. */
+  SilcBool (*schedule_fd)(SilcSchedule schedule, void *context,
+                         SilcTaskFd task, SilcTaskEvent event_mask);
+
+  /* Wakes up the scheduler. This is platform specific routine */
+  void (*wakeup)(SilcSchedule schedule, void *context);
+
+  /* Register signal */
+  void (*signal_register)(SilcSchedule schedule, void *context,
+                         SilcUInt32 signal, SilcTaskCallback callback,
+                         void *callback_context);
+
+  /* Unregister signal */
+  void (*signal_unregister)(SilcSchedule schedule, void *context,
+                           SilcUInt32 signal);
+
+  /* Call all signals */
+  void (*signals_call)(SilcSchedule schedule, void *context);
+
+  /* Block registered signals in scheduler. */
+  void (*signals_block)(SilcSchedule schedule, void *context);
+
+  /* Unblock registered signals in schedule. */
+  void (*signals_unblock)(SilcSchedule schedule, void *context);
+} SilcScheduleOps;
+
+/* The generic function to add any type of task to the scheduler.  This
+   used to be exported as is to application, but now they should use the
+   macro wrappers defined in silcschedule.h.  For Fd task the timeout must
+   be zero, for timeout task the timeout must not be zero, for signal task
+   the fd argument is the signal. */
+SilcTask silc_schedule_task_add(SilcSchedule schedule, SilcUInt32 fd,
+                               SilcTaskCallback callback, void *context,
+                               long seconds, long useconds,
+                               SilcTaskType type);
+
+#ifdef SILC_DIST_INPLACE
+/* Print scheduler statistics to stdout. */
+void silc_schedule_stats(SilcSchedule schedule);
+#endif /* SILC_DIST_INPLACE */
+
+#endif /* SILCSCHEDULE_I_H */