5 Author: Pekka Riikonen <priikone@silcnet.org>
7 Copyright (C) 1998 - 2001 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; either version 2 of the License, or
12 (at your option) any later version.
14 This program is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 GNU General Public License for more details.
22 #include "silcincludes.h"
23 #include "silcschedule_i.h"
25 /* Calls normal select() system call. */
27 int silc_select(SilcScheduleFd fds, SilcUInt32 fds_count,
28 struct timeval *timeout)
31 int ret, i, max_fd = 0;
36 for (i = 0; i < fds_count; i++) {
40 if (fds[i].fd > max_fd)
43 if (fds[i].events & SILC_TASK_READ)
44 FD_SET(fds[i].fd, &in);
45 if (fds[i].events & SILC_TASK_WRITE)
46 FD_SET(fds[i].fd, &out);
51 ret = select(max_fd + 1, &in, &out, NULL, timeout);
55 for (i = 0; i < fds_count; i++) {
59 if (FD_ISSET(fds[i].fd, &in))
60 fds[i].revents |= SILC_TASK_READ;
61 if (FD_ISSET(fds[i].fd, &out))
62 fds[i].revents |= SILC_TASK_WRITE;
68 #define SIGNAL_COUNT 32
72 SilcTaskCallback callback;
77 /* Internal context. */
83 sigset_t signals_blocked;
84 SilcUnixSignal signal_call[SIGNAL_COUNT];
89 SILC_TASK_CALLBACK(silc_schedule_wakeup_cb)
91 SilcUnixScheduler internal = (SilcUnixScheduler)context;
94 read(internal->wakeup_pipe[0], &c, 1);
97 #endif /* SILC_THREADS */
99 /* Initializes the platform specific scheduler. This for example initializes
100 the wakeup mechanism of the scheduler. In multi-threaded environment
101 the scheduler needs to be wakenup when tasks are added or removed from
102 the task queues. Returns context to the platform specific scheduler. */
104 void *silc_schedule_internal_init(SilcSchedule schedule,
107 SilcUnixScheduler internal;
109 internal = silc_calloc(1, sizeof(*internal));
113 sigemptyset(&internal->signals);
116 if (pipe(internal->wakeup_pipe)) {
117 SILC_LOG_ERROR(("pipe() fails: %s", strerror(errno)));
122 internal->wakeup_task =
123 silc_schedule_task_add(schedule, internal->wakeup_pipe[0],
124 silc_schedule_wakeup_cb, internal,
126 SILC_TASK_PRI_NORMAL);
127 if (!internal->wakeup_task) {
128 SILC_LOG_ERROR(("Could not add a wakeup task, threads won't work"));
129 close(internal->wakeup_pipe[0]);
130 close(internal->wakeup_pipe[1]);
136 internal->app_context = app_context;
138 return (void *)internal;
141 /* Uninitializes the platform specific scheduler context. */
143 void silc_schedule_internal_uninit(void *context)
145 SilcUnixScheduler internal = (SilcUnixScheduler)context;
151 close(internal->wakeup_pipe[0]);
152 close(internal->wakeup_pipe[1]);
158 /* Wakes up the scheduler */
160 void silc_schedule_internal_wakeup(void *context)
163 SilcUnixScheduler internal = (SilcUnixScheduler)context;
168 write(internal->wakeup_pipe[1], "!", 1);
172 void silc_schedule_internal_signal_register(void *context,
174 SilcTaskCallback callback,
175 void *callback_context)
177 SilcUnixScheduler internal = (SilcUnixScheduler)context;
183 sigprocmask(SIG_BLOCK, &internal->signals, &internal->signals_blocked);
185 for (i = 0; i < SIGNAL_COUNT; i++) {
186 if (!internal->signal_call[i].signal) {
187 internal->signal_call[i].signal = signal;
188 internal->signal_call[i].callback = callback;
189 internal->signal_call[i].context = callback_context;
190 internal->signal_call[i].call = FALSE;
195 sigprocmask(SIG_SETMASK, &internal->signals_blocked, NULL);
196 sigaddset(&internal->signals, signal);
199 void silc_schedule_internal_signal_unregister(void *context,
201 SilcTaskCallback callback,
202 void *callback_context)
204 SilcUnixScheduler internal = (SilcUnixScheduler)context;
210 sigprocmask(SIG_BLOCK, &internal->signals, &internal->signals_blocked);
212 for (i = 0; i < SIGNAL_COUNT; i++) {
213 if (internal->signal_call[i].signal == signal &&
214 internal->signal_call[i].callback == callback &&
215 internal->signal_call[i].context == callback_context) {
216 internal->signal_call[i].signal = 0;
217 internal->signal_call[i].callback = NULL;
218 internal->signal_call[i].context = NULL;
219 internal->signal_call[i].call = FALSE;
223 sigprocmask(SIG_SETMASK, &internal->signals_blocked, NULL);
224 sigdelset(&internal->signals, signal);
227 /* Mark signal to be called later. */
229 void silc_schedule_internal_signal_call(void *context, SilcUInt32 signal)
231 SilcUnixScheduler internal = (SilcUnixScheduler)context;
237 sigprocmask(SIG_BLOCK, &internal->signals, &internal->signals_blocked);
239 for (i = 0; i < SIGNAL_COUNT; i++) {
240 if (internal->signal_call[i].signal == signal)
241 internal->signal_call[i].call = TRUE;
244 sigprocmask(SIG_SETMASK, &internal->signals_blocked, NULL);
247 /* Call all signals */
249 void silc_schedule_internal_signals_call(void *context,
250 SilcSchedule schedule)
252 SilcUnixScheduler internal = (SilcUnixScheduler)context;
258 sigprocmask(SIG_BLOCK, &internal->signals, &internal->signals_blocked);
260 for (i = 0; i < SIGNAL_COUNT; i++) {
261 if (internal->signal_call[i].call &&
262 internal->signal_call[i].callback) {
263 internal->signal_call[i].callback(schedule, internal->app_context,
265 internal->signal_call[i].signal,
266 internal->signal_call[i].context);
267 internal->signal_call[i].call = FALSE;
271 sigprocmask(SIG_SETMASK, &internal->signals_blocked, NULL);
274 /* Block registered signals in scheduler. */
276 void silc_schedule_internal_signals_block(void *context)
278 SilcUnixScheduler internal = (SilcUnixScheduler)context;
283 sigprocmask(SIG_BLOCK, &internal->signals, &internal->signals_blocked);
286 /* Unblock registered signals in schedule. */
288 void silc_schedule_internal_signals_unblock(void *context)
290 SilcUnixScheduler internal = (SilcUnixScheduler)context;
295 sigprocmask(SIG_SETMASK, &internal->signals_blocked, NULL);