+
+void silc_schedule_internal_signal_register(SilcSchedule schedule,
+ void *context,
+ SilcUInt32 signal,
+ SilcTaskCallback callback,
+ void *callback_context)
+{
+ SilcUnixScheduler internal = (SilcUnixScheduler)context;
+ int i;
+
+ if (!internal)
+ return;
+
+ SILC_LOG_DEBUG(("Registering signal %d", signal));
+
+ silc_schedule_internal_signals_block(schedule, context);
+
+ for (i = 0; i < SIGNAL_COUNT; i++) {
+ if (!internal->signal_call[i].signal) {
+ internal->signal_call[i].signal = signal;
+ internal->signal_call[i].callback = callback;
+ internal->signal_call[i].context = callback_context;
+ internal->signal_call[i].call = FALSE;
+ break;
+ }
+ }
+
+ silc_schedule_internal_signals_unblock(schedule, context);
+ sigaddset(&internal->signals, signal);
+}
+
+void silc_schedule_internal_signal_unregister(SilcSchedule schedule,
+ void *context,
+ SilcUInt32 signal,
+ SilcTaskCallback callback,
+ void *callback_context)
+{
+ SilcUnixScheduler internal = (SilcUnixScheduler)context;
+ int i;
+
+ if (!internal)
+ return;
+
+ SILC_LOG_DEBUG(("Unregistering signal %d", signal));
+
+ silc_schedule_internal_signals_block(schedule, context);
+
+ for (i = 0; i < SIGNAL_COUNT; i++) {
+ if (internal->signal_call[i].signal == signal &&
+ internal->signal_call[i].callback == callback &&
+ internal->signal_call[i].context == callback_context) {
+ internal->signal_call[i].signal = 0;
+ internal->signal_call[i].callback = NULL;
+ internal->signal_call[i].context = NULL;
+ internal->signal_call[i].call = FALSE;
+ }
+ }
+
+ silc_schedule_internal_signals_unblock(schedule, context);
+ sigdelset(&internal->signals, signal);
+}
+
+/* Mark signal to be called later. */
+
+void silc_schedule_internal_signal_call(SilcSchedule schedule,
+ void *context, SilcUInt32 signal)
+{
+ SilcUnixScheduler internal = (SilcUnixScheduler)context;
+ int i;
+
+ if (!internal)
+ return;
+
+ silc_schedule_internal_signals_block(schedule, context);
+
+ for (i = 0; i < SIGNAL_COUNT; i++) {
+ if (internal->signal_call[i].signal == signal) {
+ internal->signal_call[i].call = TRUE;
+ SILC_LOG_DEBUG(("Scheduling signal %d to be called",
+ internal->signal_call[i].signal));
+ }
+ }
+
+ silc_schedule_internal_signals_unblock(schedule, context);
+}
+
+/* Call all signals */
+
+void silc_schedule_internal_signals_call(SilcSchedule schedule, void *context)
+{
+ SilcUnixScheduler internal = (SilcUnixScheduler)context;
+ int i;
+
+ SILC_LOG_DEBUG(("Start"));
+
+ if (!internal)
+ return;
+
+ silc_schedule_internal_signals_block(schedule, context);
+
+ for (i = 0; i < SIGNAL_COUNT; i++) {
+ if (internal->signal_call[i].call &&
+ internal->signal_call[i].callback) {
+ SILC_LOG_DEBUG(("Calling signal %d callback",
+ internal->signal_call[i].signal));
+ internal->signal_call[i].callback(schedule, internal->app_context,
+ SILC_TASK_INTERRUPT,
+ internal->signal_call[i].signal,
+ internal->signal_call[i].context);
+ internal->signal_call[i].call = FALSE;
+ }
+ }
+
+ silc_schedule_internal_signals_unblock(schedule, context);
+}
+
+/* Block registered signals in scheduler. */
+
+void silc_schedule_internal_signals_block(SilcSchedule schedule, void *context)
+{
+ SilcUnixScheduler internal = (SilcUnixScheduler)context;
+
+ if (!internal)
+ return;
+
+ sigprocmask(SIG_BLOCK, &internal->signals, &internal->signals_blocked);
+}
+
+/* Unblock registered signals in schedule. */
+
+void silc_schedule_internal_signals_unblock(SilcSchedule schedule,
+ void *context)
+{
+ SilcUnixScheduler internal = (SilcUnixScheduler)context;
+
+ if (!internal)
+ return;
+
+ sigprocmask(SIG_SETMASK, &internal->signals_blocked, NULL);
+}
+
+const SilcScheduleOps schedule_ops =
+{
+ silc_schedule_internal_init,
+ silc_schedule_internal_uninit,
+#if defined(HAVE_POLL) && defined(HAVE_SETRLIMIT) && defined(RLIMIT_NOFILE)
+ silc_poll,
+#else
+ silc_select,
+#endif /* HAVE_POLL && HAVE_SETRLIMIT && RLIMIT_NOFILE */
+ silc_schedule_internal_wakeup,
+ silc_schedule_internal_signal_register,
+ silc_schedule_internal_signal_unregister,
+ silc_schedule_internal_signal_call,
+ silc_schedule_internal_signals_call,
+ silc_schedule_internal_signals_block,
+ silc_schedule_internal_signals_unblock,
+};