+#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)