1 /*
2 
3   silcschedule_i.h.
4 
5   Author: Pekka Riikonen <priikone@silcnet.org>
6 
7   Copyright (C) 2001 - 2007 Pekka Riikonen
8 
9   The contents of this file are subject to one of the Licenses specified
10   in the COPYING file;  You may not use this file except in compliance
11   with the License.
12 
13   The software distributed under the License is distributed on an "AS IS"
14   basis, in the hope that it will be useful, but WITHOUT WARRANTY OF ANY
15   KIND, either expressed or implied.  See the COPYING file for more
16   information.
17 
18 */
19 
20 #ifndef SILCSCHEDULE_I_H
21 #define SILCSCHEDULE_I_H
22 
23 #ifndef SILCSCHEDULE_H
24 #error "Do not include this header directly"
25 #endif
26 
27 #include "silchashtable.h"
28 #include "silclist.h"
29 
30 /* Task types */
31 typedef enum {
32   /* File descriptor task that performs some event over file descriptors.
33      These tasks are for example network connections. */
34   SILC_TASK_FD           = 0,
35 
36   /* Timeout tasks are tasks that are executed after the specified
37      time has elapsed. After the task is executed the task is removed
38      automatically from the scheduler. It is safe to re-register the
39      task in task callback. It is also safe to unregister a task in
40      the task callback. */
41   SILC_TASK_TIMEOUT,
42 
43   /* Platform specific process signal task.  On Unix systems this is one of
44      the signals described in signal(7).  On other platforms this may not
45      be available at all.  Only one callback per signal may be added. */
46   SILC_TASK_SIGNAL
47 } SilcTaskType;
48 
49 /* Task header */
50 struct SilcTaskStruct {
51   struct SilcTaskStruct *next;
52   SilcTaskCallback callback;
53   void *context;
54   unsigned int type    : 1;	/* 0 = fd, 1 = timeout */
55   unsigned int valid   : 1;	/* Set if task is valid */
56 };
57 
58 /* Timeout task */
59 typedef struct SilcTaskTimeoutStruct {
60   struct SilcTaskStruct header;
61   struct timeval timeout;
62 } *SilcTaskTimeout;
63 
64 /* Fd task */
65 typedef struct SilcTaskFdStruct {
66   struct SilcTaskStruct header;
67   unsigned int scheduled  : 1;
68   unsigned int events     : 14;
69   unsigned int revents    : 15;
70   SilcUInt32 fd;
71 } *SilcTaskFd;
72 
73 /* Scheduler context */
74 struct SilcScheduleStruct {
75   void *internal;
76   void *app_context;		   /* Application specific context */
77   SilcTaskNotifyCb notify;	   /* Notify callback */
78   void *notify_context;		   /* Notify context */
79   SilcHashTable fd_queue;	   /* FD task queue */
80   SilcList fd_dispatch;		   /* Dispatched FDs */
81   SilcList timeout_queue;	   /* Timeout queue */
82   SilcList free_tasks;		   /* Timeout task freelist */
83   SilcMutex lock;		   /* Scheduler lock */
84   struct timeval timeout;	   /* Current timeout */
85   unsigned int max_tasks     : 29; /* Max FD tasks */
86   unsigned int has_timeout   : 1;  /* Set if timeout is set */
87   unsigned int valid         : 1;  /* Set if scheduler is valid */
88   unsigned int signal_tasks  : 1;  /* Set if to dispatch signals */
89 };
90 
91 /* Locks. These also blocks signals that we care about and thus guarantee
92    that while we are in scheduler no signals can happen.  This way we can
93    synchronise signals with SILC Scheduler. */
94 #define SILC_SCHEDULE_LOCK(schedule)				\
95 do {								\
96   silc_mutex_lock(schedule->lock);				\
97   schedule_ops.signals_block(schedule, schedule->internal);	\
98 } while (0)
99 #define SILC_SCHEDULE_UNLOCK(schedule)				\
100 do {								\
101   schedule_ops.signals_unblock(schedule, schedule->internal);	\
102   silc_mutex_unlock(schedule->lock);				\
103 } while (0)
104 
105 /* Platform specific scheduler operations */
106 typedef struct {
107   /* Initializes the platform specific scheduler.  This for example initializes
108      the wakeup mechanism of the scheduler.  In multi-threaded environment
109      the scheduler needs to be wakenup when tasks are added or removed from
110      the task queues.  Returns context to the platform specific scheduler.
111      If this returns NULL the scheduler initialization will fail.  Do not
112      add FD tasks inside function.  Timeout tasks can be added. */
113   void *(*init)(SilcSchedule schedule, void *app_context);
114 
115   /* Uninitializes the platform specific scheduler context. */
116   void (*uninit)(SilcSchedule schedule, void *context);
117 
118   /* System specific waiter. This must fill the schedule->fd_dispatch queue
119      with valid tasks that has something to dispatch, when this returns. */
120   int (*schedule)(SilcSchedule schedule, void *context);
121 
122   /* Schedule `task' with events `event_mask'. Zero `event_mask'
123      unschedules the task. */
124   SilcBool (*schedule_fd)(SilcSchedule schedule, void *context,
125 			  SilcTaskFd task, SilcTaskEvent event_mask);
126 
127   /* Wakes up the scheduler. This is platform specific routine */
128   void (*wakeup)(SilcSchedule schedule, void *context);
129 
130   /* Register signal */
131   void (*signal_register)(SilcSchedule schedule, void *context,
132 			  SilcUInt32 signal, SilcTaskCallback callback,
133 			  void *callback_context);
134 
135   /* Unregister signal */
136   void (*signal_unregister)(SilcSchedule schedule, void *context,
137 			    SilcUInt32 signal);
138 
139   /* Call all signals */
140   void (*signals_call)(SilcSchedule schedule, void *context);
141 
142   /* Block registered signals in scheduler. */
143   void (*signals_block)(SilcSchedule schedule, void *context);
144 
145   /* Unblock registered signals in schedule. */
146   void (*signals_unblock)(SilcSchedule schedule, void *context);
147 } SilcScheduleOps;
148 
149 /* The generic function to add any type of task to the scheduler.  This
150    used to be exported as is to application, but now they should use the
151    macro wrappers defined in silcschedule.h.  For Fd task the timeout must
152    be zero, for timeout task the timeout must not be zero, for signal task
153    the fd argument is the signal. */
154 SilcTask silc_schedule_task_add(SilcSchedule schedule, SilcUInt32 fd,
155 				SilcTaskCallback callback, void *context,
156 				long seconds, long useconds,
157 				SilcTaskType type);
158 
159 
160 #endif /* SILCSCHEDULE_I_H */
161