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++) {
39 if (fds[i].fd > max_fd)
42 if (fds[i].events & SILC_TASK_READ)
43 FD_SET(fds[i].fd, &in);
44 if (fds[i].events & SILC_TASK_WRITE)
45 FD_SET(fds[i].fd, &out);
50 ret = select(max_fd + 1, &in, &out, NULL, timeout);
54 for (i = 0; i < fds_count; i++) {
58 if (FD_ISSET(fds[i].fd, &in))
59 fds[i].revents |= SILC_TASK_READ;
60 if (FD_ISSET(fds[i].fd, &out))
61 fds[i].revents |= SILC_TASK_WRITE;
67 #define SIGNAL_COUNT 32
71 SilcTaskCallback callback;
76 /* Internal context. */
82 sigset_t signals_blocked;
83 SilcUnixSignal signal_call[SIGNAL_COUNT];
88 SILC_TASK_CALLBACK(silc_schedule_wakeup_cb)
90 SilcUnixScheduler internal = (SilcUnixScheduler)context;
93 read(internal->wakeup_pipe[0], &c, 1);
96 #endif /* SILC_THREADS */
98 /* Initializes the platform specific scheduler. This for example initializes
99 the wakeup mechanism of the scheduler. In multi-threaded environment
100 the scheduler needs to be wakenup when tasks are added or removed from
101 the task queues. Returns context to the platform specific scheduler. */
103 void *silc_schedule_internal_init(SilcSchedule schedule,
106 SilcUnixScheduler internal;
108 internal = silc_calloc(1, sizeof(*internal));
112 sigemptyset(&internal->signals);
115 if (pipe(internal->wakeup_pipe)) {
116 SILC_LOG_ERROR(("pipe() fails: %s", strerror(errno)));
121 internal->wakeup_task =
122 silc_schedule_task_add(schedule, internal->wakeup_pipe[0],
123 silc_schedule_wakeup_cb, internal,
125 SILC_TASK_PRI_NORMAL);
126 if (!internal->wakeup_task) {
127 SILC_LOG_ERROR(("Could not add a wakeup task, threads won't work"));
128 close(internal->wakeup_pipe[0]);
129 close(internal->wakeup_pipe[1]);
135 internal->app_context = app_context;
137 return (void *)internal;
140 void silc_schedule_internal_signals_block(void *context);
141 void silc_schedule_internal_signals_unblock(void *context);
143 /* Uninitializes the platform specific scheduler context. */
145 void silc_schedule_internal_uninit(void *context)
147 SilcUnixScheduler internal = (SilcUnixScheduler)context;
153 close(internal->wakeup_pipe[0]);
154 close(internal->wakeup_pipe[1]);
160 /* Wakes up the scheduler */
162 void silc_schedule_internal_wakeup(void *context)
165 SilcUnixScheduler internal = (SilcUnixScheduler)context;
170 write(internal->wakeup_pipe[1], "!", 1);
174 void silc_schedule_internal_signal_register(void *context,
176 SilcTaskCallback callback,
177 void *callback_context)
179 SilcUnixScheduler internal = (SilcUnixScheduler)context;
185 SILC_LOG_DEBUG(("Registering signal %d", signal));
187 silc_schedule_internal_signals_block(context);
189 for (i = 0; i < SIGNAL_COUNT; i++) {
190 if (!internal->signal_call[i].signal) {
191 internal->signal_call[i].signal = signal;
192 internal->signal_call[i].callback = callback;
193 internal->signal_call[i].context = callback_context;
194 internal->signal_call[i].call = FALSE;
199 silc_schedule_internal_signals_unblock(context);
200 sigaddset(&internal->signals, signal);
203 void silc_schedule_internal_signal_unregister(void *context,
205 SilcTaskCallback callback,
206 void *callback_context)
208 SilcUnixScheduler internal = (SilcUnixScheduler)context;
214 SILC_LOG_DEBUG(("Unregistering signal %d", signal));
216 silc_schedule_internal_signals_block(context);
218 for (i = 0; i < SIGNAL_COUNT; i++) {
219 if (internal->signal_call[i].signal == signal &&
220 internal->signal_call[i].callback == callback &&
221 internal->signal_call[i].context == callback_context) {
222 internal->signal_call[i].signal = 0;
223 internal->signal_call[i].callback = NULL;
224 internal->signal_call[i].context = NULL;
225 internal->signal_call[i].call = FALSE;
229 silc_schedule_internal_signals_unblock(context);
230 sigdelset(&internal->signals, signal);
233 /* Mark signal to be called later. */
235 void silc_schedule_internal_signal_call(void *context, SilcUInt32 signal)
237 SilcUnixScheduler internal = (SilcUnixScheduler)context;
243 silc_schedule_internal_signals_block(context);
245 for (i = 0; i < SIGNAL_COUNT; i++) {
246 if (internal->signal_call[i].signal == signal) {
247 internal->signal_call[i].call = TRUE;
248 SILC_LOG_DEBUG(("Scheduling signal %d to be called",
249 internal->signal_call[i].signal));
253 silc_schedule_internal_signals_unblock(context);
256 /* Call all signals */
258 void silc_schedule_internal_signals_call(void *context,
259 SilcSchedule schedule)
261 SilcUnixScheduler internal = (SilcUnixScheduler)context;
264 SILC_LOG_DEBUG(("Start"));
269 silc_schedule_internal_signals_block(context);
271 for (i = 0; i < SIGNAL_COUNT; i++) {
272 if (internal->signal_call[i].call &&
273 internal->signal_call[i].callback) {
274 SILC_LOG_DEBUG(("Calling signal %d callback",
275 internal->signal_call[i].signal));
276 internal->signal_call[i].callback(schedule, internal->app_context,
278 internal->signal_call[i].signal,
279 internal->signal_call[i].context);
280 internal->signal_call[i].call = FALSE;
284 silc_schedule_internal_signals_unblock(context);
287 /* Block registered signals in scheduler. */
289 void silc_schedule_internal_signals_block(void *context)
291 SilcUnixScheduler internal = (SilcUnixScheduler)context;
296 sigprocmask(SIG_BLOCK, &internal->signals, &internal->signals_blocked);
299 /* Unblock registered signals in schedule. */
301 void silc_schedule_internal_signals_unblock(void *context)
303 SilcUnixScheduler internal = (SilcUnixScheduler)context;
308 sigprocmask(SIG_SETMASK, &internal->signals_blocked, NULL);