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 for (i = 0; i < SIGNAL_COUNT; i++) {
175 if (!internal->signal_call[i].signal) {
176 internal->signal_call[i].signal = signal;
177 internal->signal_call[i].callback = callback;
178 internal->signal_call[i].context = callback_context;
179 internal->signal_call[i].call = FALSE;
183 sigaddset(&internal->signals, signal);
186 void silc_schedule_internal_signal_unregister(void *context,
188 SilcTaskCallback callback,
189 void *callback_context)
191 SilcUnixScheduler internal = (SilcUnixScheduler)context;
194 for (i = 0; i < SIGNAL_COUNT; i++) {
195 if (internal->signal_call[i].signal == signal &&
196 internal->signal_call[i].callback == callback &&
197 internal->signal_call[i].context == callback_context) {
198 internal->signal_call[i].signal = 0;
199 internal->signal_call[i].callback = NULL;
200 internal->signal_call[i].context = NULL;
201 internal->signal_call[i].call = FALSE;
205 sigdelset(&internal->signals, signal);
208 /* Mark signal to be called later. */
210 void silc_schedule_internal_signal_call(void *context, SilcUInt32 signal)
212 SilcUnixScheduler internal = (SilcUnixScheduler)context;
215 for (i = 0; i < SIGNAL_COUNT; i++) {
216 if (internal->signal_call[i].signal == signal)
217 internal->signal_call[i].call = TRUE;
221 /* Call all signals */
223 void silc_schedule_internal_signals_call(void *context,
224 SilcSchedule schedule)
226 SilcUnixScheduler internal = (SilcUnixScheduler)context;
229 for (i = 0; i < SIGNAL_COUNT; i++) {
230 if (internal->signal_call[i].call &&
231 internal->signal_call[i].callback) {
232 internal->signal_call[i].callback(schedule, SILC_TASK_INTERRUPT,
233 internal->signal_call[i].signal,
234 internal->signal_call[i].context);
235 internal->signal_call[i].call = FALSE;
240 /* Block registered signals in scheduler. */
242 void silc_schedule_internal_signals_block(void *context)
244 SilcUnixScheduler internal = (SilcUnixScheduler)context;
245 sigprocmask(SIG_BLOCK, &internal->signals, &internal->signals_blocked);
248 /* Unblock registered signals in schedule. */
250 void silc_schedule_internal_signals_unblock(void *context)
252 SilcUnixScheduler internal = (SilcUnixScheduler)context;
253 sigprocmask(SIG_SETMASK, &internal->signals_blocked, NULL);