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. */
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)
105 SilcUnixScheduler internal;
107 internal = silc_calloc(1, sizeof(*internal));
111 sigemptyset(&internal->signals);
114 if (pipe(internal->wakeup_pipe)) {
115 SILC_LOG_ERROR(("pipe() fails: %s", strerror(errno)));
120 internal->wakeup_task =
121 silc_schedule_task_add(schedule, internal->wakeup_pipe[0],
122 silc_schedule_wakeup_cb, internal,
124 SILC_TASK_PRI_NORMAL);
125 if (!internal->wakeup_task) {
126 SILC_LOG_ERROR(("Could not add a wakeup task, threads won't work"));
127 close(internal->wakeup_pipe[0]);
128 close(internal->wakeup_pipe[1]);
134 return (void *)internal;
137 /* Uninitializes the platform specific scheduler context. */
139 void silc_schedule_internal_uninit(void *context)
141 SilcUnixScheduler internal = (SilcUnixScheduler)context;
147 close(internal->wakeup_pipe[0]);
148 close(internal->wakeup_pipe[1]);
154 /* Wakes up the scheduler */
156 void silc_schedule_internal_wakeup(void *context)
159 SilcUnixScheduler internal = (SilcUnixScheduler)context;
164 write(internal->wakeup_pipe[1], "!", 1);
168 void silc_schedule_internal_signal_register(void *context,
170 SilcTaskCallback callback,
171 void *callback_context)
173 SilcUnixScheduler internal = (SilcUnixScheduler)context;
179 sigprocmask(SIG_BLOCK, &internal->signals, &internal->signals_blocked);
181 for (i = 0; i < SIGNAL_COUNT; i++) {
182 if (!internal->signal_call[i].signal) {
183 internal->signal_call[i].signal = signal;
184 internal->signal_call[i].callback = callback;
185 internal->signal_call[i].context = callback_context;
186 internal->signal_call[i].call = FALSE;
191 sigprocmask(SIG_SETMASK, &internal->signals_blocked, NULL);
192 sigaddset(&internal->signals, signal);
195 void silc_schedule_internal_signal_unregister(void *context,
197 SilcTaskCallback callback,
198 void *callback_context)
200 SilcUnixScheduler internal = (SilcUnixScheduler)context;
206 sigprocmask(SIG_BLOCK, &internal->signals, &internal->signals_blocked);
208 for (i = 0; i < SIGNAL_COUNT; i++) {
209 if (internal->signal_call[i].signal == signal &&
210 internal->signal_call[i].callback == callback &&
211 internal->signal_call[i].context == callback_context) {
212 internal->signal_call[i].signal = 0;
213 internal->signal_call[i].callback = NULL;
214 internal->signal_call[i].context = NULL;
215 internal->signal_call[i].call = FALSE;
219 sigprocmask(SIG_SETMASK, &internal->signals_blocked, NULL);
220 sigdelset(&internal->signals, signal);
223 /* Mark signal to be called later. */
225 void silc_schedule_internal_signal_call(void *context, SilcUInt32 signal)
227 SilcUnixScheduler internal = (SilcUnixScheduler)context;
233 sigprocmask(SIG_BLOCK, &internal->signals, &internal->signals_blocked);
235 for (i = 0; i < SIGNAL_COUNT; i++) {
236 if (internal->signal_call[i].signal == signal)
237 internal->signal_call[i].call = TRUE;
240 sigprocmask(SIG_SETMASK, &internal->signals_blocked, NULL);
243 /* Call all signals */
245 void silc_schedule_internal_signals_call(void *context,
246 SilcSchedule schedule)
248 SilcUnixScheduler internal = (SilcUnixScheduler)context;
254 sigprocmask(SIG_BLOCK, &internal->signals, &internal->signals_blocked);
256 for (i = 0; i < SIGNAL_COUNT; i++) {
257 if (internal->signal_call[i].call &&
258 internal->signal_call[i].callback) {
259 internal->signal_call[i].callback(schedule, SILC_TASK_INTERRUPT,
260 internal->signal_call[i].signal,
261 internal->signal_call[i].context);
262 internal->signal_call[i].call = FALSE;
266 sigprocmask(SIG_SETMASK, &internal->signals_blocked, NULL);
269 /* Block registered signals in scheduler. */
271 void silc_schedule_internal_signals_block(void *context)
273 SilcUnixScheduler internal = (SilcUnixScheduler)context;
278 sigprocmask(SIG_BLOCK, &internal->signals, &internal->signals_blocked);
281 /* Unblock registered signals in schedule. */
283 void silc_schedule_internal_signals_unblock(void *context)
285 SilcUnixScheduler internal = (SilcUnixScheduler)context;
290 sigprocmask(SIG_SETMASK, &internal->signals_blocked, NULL);