5 Author: Pekka Riikonen <priikone@silcnet.org>
7 Copyright (C) 1998 - 2004 Pekka Riikonen
9 This program is free software; you can redistribute it and/or modify
10 it under the terms of the GNU General Public License as published by
11 the Free Software Foundation; version 2 of the License.
13 This program is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
21 #include "silcincludes.h"
22 #include "silcschedule_i.h"
24 /* Calls normal select() system call. */
26 int silc_select(SilcScheduleFd fds, SilcUInt32 fds_count,
27 struct timeval *timeout)
30 int ret, i, max_fd = 0;
35 for (i = 0; i < fds_count; i++) {
40 if (fds[i].fd >= FD_SETSIZE)
42 #endif /* FD_SETSIZE */
44 if (fds[i].fd > max_fd)
47 if (fds[i].events & SILC_TASK_READ)
48 FD_SET(fds[i].fd, &in);
49 if (fds[i].events & SILC_TASK_WRITE)
50 FD_SET(fds[i].fd, &out);
55 ret = select(max_fd + 1, &in, &out, NULL, timeout);
59 for (i = 0; i < fds_count; i++) {
64 if (fds[i].fd >= FD_SETSIZE)
66 #endif /* FD_SETSIZE */
68 if (FD_ISSET(fds[i].fd, &in))
69 fds[i].revents |= SILC_TASK_READ;
70 if (FD_ISSET(fds[i].fd, &out))
71 fds[i].revents |= SILC_TASK_WRITE;
77 #define SIGNAL_COUNT 32
81 SilcTaskCallback callback;
86 /* Internal context. */
92 sigset_t signals_blocked;
93 SilcUnixSignal signal_call[SIGNAL_COUNT];
98 SILC_TASK_CALLBACK(silc_schedule_wakeup_cb)
100 SilcUnixScheduler internal = (SilcUnixScheduler)context;
103 read(internal->wakeup_pipe[0], &c, 1);
106 #endif /* SILC_THREADS */
108 /* Initializes the platform specific scheduler. This for example initializes
109 the wakeup mechanism of the scheduler. In multi-threaded environment
110 the scheduler needs to be wakenup when tasks are added or removed from
111 the task queues. Returns context to the platform specific scheduler. */
113 void *silc_schedule_internal_init(SilcSchedule schedule,
116 SilcUnixScheduler internal;
118 internal = silc_calloc(1, sizeof(*internal));
122 sigemptyset(&internal->signals);
125 if (pipe(internal->wakeup_pipe)) {
126 SILC_LOG_ERROR(("pipe() fails: %s", strerror(errno)));
131 internal->wakeup_task =
132 silc_schedule_task_add(schedule, internal->wakeup_pipe[0],
133 silc_schedule_wakeup_cb, internal,
135 SILC_TASK_PRI_NORMAL);
136 if (!internal->wakeup_task) {
137 SILC_LOG_ERROR(("Could not add a wakeup task, threads won't work"));
138 close(internal->wakeup_pipe[0]);
139 close(internal->wakeup_pipe[1]);
145 internal->app_context = app_context;
147 return (void *)internal;
150 void silc_schedule_internal_signals_block(void *context);
151 void silc_schedule_internal_signals_unblock(void *context);
153 /* Uninitializes the platform specific scheduler context. */
155 void silc_schedule_internal_uninit(void *context)
157 SilcUnixScheduler internal = (SilcUnixScheduler)context;
163 close(internal->wakeup_pipe[0]);
164 close(internal->wakeup_pipe[1]);
170 /* Wakes up the scheduler */
172 void silc_schedule_internal_wakeup(void *context)
175 SilcUnixScheduler internal = (SilcUnixScheduler)context;
180 write(internal->wakeup_pipe[1], "!", 1);
184 void silc_schedule_internal_signal_register(void *context,
186 SilcTaskCallback callback,
187 void *callback_context)
189 SilcUnixScheduler internal = (SilcUnixScheduler)context;
195 SILC_LOG_DEBUG(("Registering signal %d", signal));
197 silc_schedule_internal_signals_block(context);
199 for (i = 0; i < SIGNAL_COUNT; i++) {
200 if (!internal->signal_call[i].signal) {
201 internal->signal_call[i].signal = signal;
202 internal->signal_call[i].callback = callback;
203 internal->signal_call[i].context = callback_context;
204 internal->signal_call[i].call = FALSE;
209 silc_schedule_internal_signals_unblock(context);
210 sigaddset(&internal->signals, signal);
213 void silc_schedule_internal_signal_unregister(void *context,
215 SilcTaskCallback callback,
216 void *callback_context)
218 SilcUnixScheduler internal = (SilcUnixScheduler)context;
224 SILC_LOG_DEBUG(("Unregistering signal %d", signal));
226 silc_schedule_internal_signals_block(context);
228 for (i = 0; i < SIGNAL_COUNT; i++) {
229 if (internal->signal_call[i].signal == signal &&
230 internal->signal_call[i].callback == callback &&
231 internal->signal_call[i].context == callback_context) {
232 internal->signal_call[i].signal = 0;
233 internal->signal_call[i].callback = NULL;
234 internal->signal_call[i].context = NULL;
235 internal->signal_call[i].call = FALSE;
239 silc_schedule_internal_signals_unblock(context);
240 sigdelset(&internal->signals, signal);
243 /* Mark signal to be called later. */
245 void silc_schedule_internal_signal_call(void *context, SilcUInt32 signal)
247 SilcUnixScheduler internal = (SilcUnixScheduler)context;
253 silc_schedule_internal_signals_block(context);
255 for (i = 0; i < SIGNAL_COUNT; i++) {
256 if (internal->signal_call[i].signal == signal) {
257 internal->signal_call[i].call = TRUE;
258 SILC_LOG_DEBUG(("Scheduling signal %d to be called",
259 internal->signal_call[i].signal));
263 silc_schedule_internal_signals_unblock(context);
266 /* Call all signals */
268 void silc_schedule_internal_signals_call(void *context,
269 SilcSchedule schedule)
271 SilcUnixScheduler internal = (SilcUnixScheduler)context;
274 SILC_LOG_DEBUG(("Start"));
279 silc_schedule_internal_signals_block(context);
281 for (i = 0; i < SIGNAL_COUNT; i++) {
282 if (internal->signal_call[i].call &&
283 internal->signal_call[i].callback) {
284 SILC_LOG_DEBUG(("Calling signal %d callback",
285 internal->signal_call[i].signal));
286 internal->signal_call[i].callback(schedule, internal->app_context,
288 internal->signal_call[i].signal,
289 internal->signal_call[i].context);
290 internal->signal_call[i].call = FALSE;
294 silc_schedule_internal_signals_unblock(context);
297 /* Block registered signals in scheduler. */
299 void silc_schedule_internal_signals_block(void *context)
301 SilcUnixScheduler internal = (SilcUnixScheduler)context;
306 sigprocmask(SIG_BLOCK, &internal->signals, &internal->signals_blocked);
309 /* Unblock registered signals in schedule. */
311 void silc_schedule_internal_signals_unblock(void *context)
313 SilcUnixScheduler internal = (SilcUnixScheduler)context;
318 sigprocmask(SIG_SETMASK, &internal->signals_blocked, NULL);