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 /* Uninitializes the platform specific scheduler context. */
142 void silc_schedule_internal_uninit(void *context)
144 SilcUnixScheduler internal = (SilcUnixScheduler)context;
150 close(internal->wakeup_pipe[0]);
151 close(internal->wakeup_pipe[1]);
157 /* Wakes up the scheduler */
159 void silc_schedule_internal_wakeup(void *context)
162 SilcUnixScheduler internal = (SilcUnixScheduler)context;
167 write(internal->wakeup_pipe[1], "!", 1);
171 void silc_schedule_internal_signal_register(void *context,
173 SilcTaskCallback callback,
174 void *callback_context)
176 SilcUnixScheduler internal = (SilcUnixScheduler)context;
182 SILC_LOG_DEBUG(("Registering signal %d", signal));
184 silc_schedule_internal_signals_block(context);
186 for (i = 0; i < SIGNAL_COUNT; i++) {
187 if (!internal->signal_call[i].signal) {
188 internal->signal_call[i].signal = signal;
189 internal->signal_call[i].callback = callback;
190 internal->signal_call[i].context = callback_context;
191 internal->signal_call[i].call = FALSE;
196 silc_schedule_internal_signals_unblock(context);
197 sigaddset(&internal->signals, signal);
200 void silc_schedule_internal_signal_unregister(void *context,
202 SilcTaskCallback callback,
203 void *callback_context)
205 SilcUnixScheduler internal = (SilcUnixScheduler)context;
211 SILC_LOG_DEBUG(("Unregistering signal %d", signal));
213 silc_schedule_internal_signals_block(context);
215 for (i = 0; i < SIGNAL_COUNT; i++) {
216 if (internal->signal_call[i].signal == signal &&
217 internal->signal_call[i].callback == callback &&
218 internal->signal_call[i].context == callback_context) {
219 internal->signal_call[i].signal = 0;
220 internal->signal_call[i].callback = NULL;
221 internal->signal_call[i].context = NULL;
222 internal->signal_call[i].call = FALSE;
226 silc_schedule_internal_signals_unblock(context);
227 sigdelset(&internal->signals, signal);
230 /* Mark signal to be called later. */
232 void silc_schedule_internal_signal_call(void *context, SilcUInt32 signal)
234 SilcUnixScheduler internal = (SilcUnixScheduler)context;
240 silc_schedule_internal_signals_block(context);
242 for (i = 0; i < SIGNAL_COUNT; i++) {
243 if (internal->signal_call[i].signal == signal) {
244 internal->signal_call[i].call = TRUE;
245 SILC_LOG_DEBUG(("Scheduling signal %d to be called",
246 internal->signal_call[i].signal));
250 silc_schedule_internal_signals_unblock(context);
253 /* Call all signals */
255 void silc_schedule_internal_signals_call(void *context,
256 SilcSchedule schedule)
258 SilcUnixScheduler internal = (SilcUnixScheduler)context;
261 SILC_LOG_DEBUG(("Start"));
266 silc_schedule_internal_signals_block(context);
268 for (i = 0; i < SIGNAL_COUNT; i++) {
269 if (internal->signal_call[i].call &&
270 internal->signal_call[i].callback) {
271 SILC_LOG_DEBUG(("Calling signal %d callback",
272 internal->signal_call[i].signal));
273 internal->signal_call[i].callback(schedule, internal->app_context,
275 internal->signal_call[i].signal,
276 internal->signal_call[i].context);
277 internal->signal_call[i].call = FALSE;
281 silc_schedule_internal_signals_unblock(context);
284 /* Block registered signals in scheduler. */
286 void silc_schedule_internal_signals_block(void *context)
288 SilcUnixScheduler internal = (SilcUnixScheduler)context;
293 sigprocmask(SIG_BLOCK, &internal->signals, &internal->signals_blocked);
296 /* Unblock registered signals in schedule. */
298 void silc_schedule_internal_signals_unblock(void *context)
300 SilcUnixScheduler internal = (SilcUnixScheduler)context;
305 sigprocmask(SIG_SETMASK, &internal->signals_blocked, NULL);