+
+/* Signal handler */
+
+static void silc_schedule_internal_sighandler(int signal)
+{
+ int i;
+ SilcUnixSignal *signal_call = silc_global_get_var("srtsignals", TRUE);
+
+ if (!signal_call)
+ return;
+
+ SILC_LOG_DEBUG(("Start"));
+
+ for (i = 0; i < SIGNAL_COUNT; i++) {
+ if (signal_call[i].sig == signal) {
+ signal_call[i].call = TRUE;
+ signal_call[i].schedule->signal_tasks = TRUE;
+ SILC_LOG_DEBUG(("Scheduling signal %d to be called",
+ signal_call[i].sig));
+ break;
+ }
+ }
+}
+
+void silc_schedule_internal_signal_register(SilcSchedule schedule,
+ void *context,
+ SilcUInt32 sig,
+ SilcTaskCallback callback,
+ void *callback_context)
+{
+ SilcUnixScheduler internal = (SilcUnixScheduler)context;
+ SilcUnixSignal *signal_call = silc_global_get_var("srtsignals", TRUE);
+ int i;
+
+ if (!internal || !signal_call)
+ return;
+
+ SILC_LOG_DEBUG(("Registering signal %d", sig));
+
+ silc_schedule_internal_signals_block(schedule, context);
+
+ for (i = 0; i < SIGNAL_COUNT; i++) {
+ if (!signal_call[i].sig) {
+ signal_call[i].sig = sig;
+ signal_call[i].callback = callback;
+ signal_call[i].context = callback_context;
+ signal_call[i].schedule = schedule;
+ signal_call[i].call = FALSE;
+ signal(sig, silc_schedule_internal_sighandler);
+ break;
+ }
+ }
+
+ silc_schedule_internal_signals_unblock(schedule, context);
+ sigaddset(&internal->signals, sig);
+}
+
+void silc_schedule_internal_signal_unregister(SilcSchedule schedule,
+ void *context,
+ SilcUInt32 sig)
+{
+ SilcUnixScheduler internal = (SilcUnixScheduler)context;
+ SilcUnixSignal *signal_call = silc_global_get_var("srtsignals", TRUE);
+ int i;
+
+ if (!internal || !signal_call)
+ return;
+
+ SILC_LOG_DEBUG(("Unregistering signal %d", sig));
+
+ silc_schedule_internal_signals_block(schedule, context);
+
+ for (i = 0; i < SIGNAL_COUNT; i++) {
+ if (signal_call[i].sig == sig) {
+ signal_call[i].sig = 0;
+ signal_call[i].callback = NULL;
+ signal_call[i].context = NULL;
+ signal_call[i].schedule = NULL;
+ signal_call[i].call = FALSE;
+ signal(sig, SIG_DFL);
+ }
+ }
+
+ silc_schedule_internal_signals_unblock(schedule, context);
+ sigdelset(&internal->signals, sig);
+}
+
+/* Call all signals */
+
+void silc_schedule_internal_signals_call(SilcSchedule schedule, void *context)
+{
+ SilcUnixScheduler internal = (SilcUnixScheduler)context;
+ SilcUnixSignal *signal_call = silc_global_get_var("srtsignals", TRUE);
+ int i;
+
+ SILC_LOG_DEBUG(("Start"));
+
+ if (!internal || !signal_call)
+ return;
+
+ silc_schedule_internal_signals_block(schedule, context);
+
+ for (i = 0; i < SIGNAL_COUNT; i++) {
+ if (signal_call[i].call &&
+ signal_call[i].callback) {
+ SILC_LOG_DEBUG(("Calling signal %d callback",
+ signal_call[i].sig));
+ silc_schedule_internal_signals_unblock(schedule, context);
+ signal_call[i].callback(schedule, internal->app_context,
+ SILC_TASK_INTERRUPT,
+ signal_call[i].sig,
+ signal_call[i].context);
+ signal_call[i].call = FALSE;
+ silc_schedule_internal_signals_block(schedule, context);
+ }
+ }
+
+ 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_EPOLL_WAIT)
+ silc_epoll,
+#elif defined(HAVE_POLL) && defined(HAVE_SETRLIMIT) && defined(RLIMIT_NOFILE)
+ silc_poll,
+#else
+ silc_select,
+#endif /* HAVE_POLL && HAVE_SETRLIMIT && RLIMIT_NOFILE */
+ silc_schedule_internal_schedule_fd,
+ silc_schedule_internal_wakeup,
+ silc_schedule_internal_signal_register,
+ silc_schedule_internal_signal_unregister,
+ silc_schedule_internal_signals_call,
+ silc_schedule_internal_signals_block,
+ silc_schedule_internal_signals_unblock,
+};