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)) {
119 internal->wakeup_task =
120 silc_schedule_task_add(schedule, internal->wakeup_pipe[0],
121 silc_schedule_wakeup_cb, internal,
123 SILC_TASK_PRI_NORMAL);
124 if (!internal->wakeup_task) {
125 close(internal->wakeup_pipe[0]);
126 close(internal->wakeup_pipe[1]);
132 return (void *)internal;
135 /* Uninitializes the platform specific scheduler context. */
137 void silc_schedule_internal_uninit(void *context)
139 SilcUnixScheduler internal = (SilcUnixScheduler)context;
145 close(internal->wakeup_pipe[0]);
146 close(internal->wakeup_pipe[1]);
152 /* Wakes up the scheduler */
154 void silc_schedule_internal_wakeup(void *context)
157 SilcUnixScheduler internal = (SilcUnixScheduler)context;
162 write(internal->wakeup_pipe[1], "!", 1);
166 void silc_schedule_internal_signal_register(void *context,
168 SilcTaskCallback callback,
169 void *callback_context)
171 SilcUnixScheduler internal = (SilcUnixScheduler)context;
174 sigprocmask(SIG_BLOCK, &internal->signals, &internal->signals_blocked);
176 for (i = 0; i < SIGNAL_COUNT; i++) {
177 if (!internal->signal_call[i].signal) {
178 internal->signal_call[i].signal = signal;
179 internal->signal_call[i].callback = callback;
180 internal->signal_call[i].context = callback_context;
181 internal->signal_call[i].call = FALSE;
186 sigprocmask(SIG_SETMASK, &internal->signals_blocked, NULL);
187 sigaddset(&internal->signals, signal);
190 void silc_schedule_internal_signal_unregister(void *context,
192 SilcTaskCallback callback,
193 void *callback_context)
195 SilcUnixScheduler internal = (SilcUnixScheduler)context;
198 sigprocmask(SIG_BLOCK, &internal->signals, &internal->signals_blocked);
200 for (i = 0; i < SIGNAL_COUNT; i++) {
201 if (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].signal = 0;
205 internal->signal_call[i].callback = NULL;
206 internal->signal_call[i].context = NULL;
207 internal->signal_call[i].call = FALSE;
211 sigprocmask(SIG_SETMASK, &internal->signals_blocked, NULL);
212 sigdelset(&internal->signals, signal);
215 /* Mark signal to be called later. */
217 void silc_schedule_internal_signal_call(void *context, SilcUInt32 signal)
219 SilcUnixScheduler internal = (SilcUnixScheduler)context;
222 sigprocmask(SIG_BLOCK, &internal->signals, &internal->signals_blocked);
224 for (i = 0; i < SIGNAL_COUNT; i++) {
225 if (internal->signal_call[i].signal == signal)
226 internal->signal_call[i].call = TRUE;
229 sigprocmask(SIG_SETMASK, &internal->signals_blocked, NULL);
232 /* Call all signals */
234 void silc_schedule_internal_signals_call(void *context,
235 SilcSchedule schedule)
237 SilcUnixScheduler internal = (SilcUnixScheduler)context;
240 sigprocmask(SIG_BLOCK, &internal->signals, &internal->signals_blocked);
242 for (i = 0; i < SIGNAL_COUNT; i++) {
243 if (internal->signal_call[i].call &&
244 internal->signal_call[i].callback) {
245 internal->signal_call[i].callback(schedule, SILC_TASK_INTERRUPT,
246 internal->signal_call[i].signal,
247 internal->signal_call[i].context);
248 internal->signal_call[i].call = FALSE;
252 sigprocmask(SIG_SETMASK, &internal->signals_blocked, NULL);
255 /* Block registered signals in scheduler. */
257 void silc_schedule_internal_signals_block(void *context)
259 SilcUnixScheduler internal = (SilcUnixScheduler)context;
260 sigprocmask(SIG_BLOCK, &internal->signals, &internal->signals_blocked);
263 /* Unblock registered signals in schedule. */
265 void silc_schedule_internal_signals_unblock(void *context)
267 SilcUnixScheduler internal = (SilcUnixScheduler)context;
268 sigprocmask(SIG_SETMASK, &internal->signals_blocked, NULL);