+Wed Mar 20 11:06:57 CET 2002 Pekka Riikonen <priikone@silcnet.org>
+
+ * Improved the signal support in SILC Schedule. Added new
+ function silc_schedule_signal_call which is used by application
+ to mark a signal to be called. It is now safe to perform
+ any kind of tasks in signal callbacks since it is guaranteed
+ that the application specified signal callback is called
+ after the signal is over. Affected files are
+ lib/silcutil/silcschedule.[ch], lib/silcutil/*/silc*schedule.c.
+
Tue Mar 19 20:42:41 EET 2002 Pekka Riikonen <priikone@silcnet.org>
* Added `name' field to SilcChannelPrivateKey to represent
}
}
-static void got_hup(int z)
+static void signal_handler(int sig)
+{
+ /* Mark the signal to be caller after this signal is over. */
+ silc_schedule_signal_call(silcd->schedule, sig);
+}
+
+SILC_TASK_CALLBACK(got_hup)
{
/* First, reset all log files (they might have been deleted) */
silc_log_reset_all();
silc_log_flush_all();
}
-static void stop_server(int z)
+SILC_TASK_CALLBACK(stop_server)
{
/* Stop scheduler, the program will stop eventually after noticing
that the scheduler is down. */
sa.sa_flags = 0;
sigemptyset(&sa.sa_mask);
sigaction(SIGPIPE, &sa, NULL);
- sa.sa_handler = got_hup;
+ sa.sa_handler = signal_handler;
sigaction(SIGHUP, &sa, NULL);
- sa.sa_handler = stop_server;
sigaction(SIGTERM, &sa, NULL);
- sa.sa_handler = stop_server;
sigaction(SIGINT, &sa, NULL);
- silc_schedule_signal_register(silcd->schedule, SIGHUP);
- silc_schedule_signal_register(silcd->schedule, SIGTERM);
- silc_schedule_signal_register(silcd->schedule, SIGINT);
+ silc_schedule_signal_register(silcd->schedule, SIGHUP, got_hup, NULL);
+ silc_schedule_signal_register(silcd->schedule, SIGTERM, stop_server, NULL);
+ silc_schedule_signal_register(silcd->schedule, SIGINT, stop_server, NULL);
/* Before running the server, fork to background. */
if (!foreground)
}
/* Register signal */
+
void silc_schedule_internal_signal_register(void *context,
- SilcUInt32 signal)
+ SilcUInt32 signal,
+ SilcTaskCallback callback,
+ void *callback_context)
{
}
/* Unregister signal */
void silc_schedule_internal_signal_unregister(void *context,
- SilcUInt32 signal)
+ SilcUInt32 signal,
+ SilcTaskCallback callback,
+ void *callback_context)
+{
+
+}
+
+/* Mark signal to be called later. */
+
+void silc_schedule_internal_signal_call(void *context, SilcUInt32 signal)
+{
+
+}
+
+/* Call all signals */
+
+void silc_schedule_internal_signals_call(void *context,
+ SilcSchedule schedule)
{
}
/* Register signal */
void silc_schedule_internal_signal_register(void *context,
- SilcUInt32 signal);
+ SilcUInt32 signal,
+ SilcTaskCallback callback,
+ void *callback_context);
/* Unregister signal */
void silc_schedule_internal_signal_unregister(void *context,
- SilcUInt32 signal);
+ SilcUInt32 signal,
+ SilcTaskCallback callback,
+ void *callback_context);
+
+/* Mark signal to be called later. */
+void silc_schedule_internal_signal_call(void *context, SilcUInt32 signal);
+
+/* Call all signals */
+void silc_schedule_internal_signals_call(void *context,
+ SilcSchedule schedule);
/* Block registered signals in scheduler. */
void silc_schedule_internal_signals_block(void *context);
Scheduler lock.
+ bool signal_tasks
+
+ TRUE when tasks has been registered from signals. Next round in
+ scheduler will call the callbacks when this is TRUE.
+
*/
struct SilcScheduleStruct {
SilcTaskQueue fd_queue;
void *internal;
SILC_MUTEX_DEFINE(lock);
bool is_locked;
+ bool signal_tasks;
};
/* Initializes the scheduler. This returns the scheduler context that
/* Initialize the platform specific scheduler. */
schedule->internal = silc_schedule_internal_init(schedule);
-#ifdef SILC_UNIX
- silc_schedule_signal_register(schedule, SIGALRM);
-#endif
return schedule;
}
SILC_SCHEDULE_UNLOCK(schedule);
+ /* Deliver signals if any has been set to be called */
+ if (schedule->signal_tasks) {
+ silc_schedule_internal_signals_call(schedule->internal, schedule);
+ schedule->signal_tasks = FALSE;
+ }
+
/* This is the main select(). The program blocks here until some
of the selected file descriptors change status or the selected
timeout expires. */
/* Register a new signal */
-void silc_schedule_signal_register(SilcSchedule schedule, SilcUInt32 signal)
+void silc_schedule_signal_register(SilcSchedule schedule, SilcUInt32 signal,
+ SilcTaskCallback callback, void *context)
{
- silc_schedule_internal_signal_register(schedule->internal, signal);
+ silc_schedule_internal_signal_register(schedule->internal, signal,
+ callback, context);
}
/* Unregister a new signal */
-void silc_schedule_signal_unregister(SilcSchedule schedule, SilcUInt32 signal)
+void silc_schedule_signal_unregister(SilcSchedule schedule, SilcUInt32 signal,
+ SilcTaskCallback callback, void *context)
+{
+ silc_schedule_internal_signal_unregister(schedule->internal, signal,
+ callback, context);
+}
+
+/* Call signal indicated by `signal'. */
+
+void silc_schedule_signal_call(SilcSchedule schedule, SilcUInt32 signal)
{
- silc_schedule_internal_signal_unregister(schedule->internal, signal);
+ /* Mark that signals needs to be delivered later. */
+ silc_schedule_internal_signal_call(schedule->internal, signal);
+ schedule->signal_tasks = TRUE;
}
/* Allocates a newtask task queue into the scheduler */
SILC_TASK_READ = 0x0001, /* Reading */
SILC_TASK_WRITE = 0x0002, /* Writing */
SILC_TASK_EXPIRE = 0x0004, /* Timeout */
+ SILC_TASK_INTERRUPT = 0x0004, /* Signal */
} SilcTaskEvent;
/***/
* SYNOPSIS
*
* void silc_schedule_signal_register(SilcSchedule schedule,
- * SilcUInt32 signal);
+ * SilcUInt32 signal,
+ * SilcTaskCallback callback,
+ * void *context);
*
* DESCRIPTION
*
* Register signal indicated by `signal' to the scheduler. Application
* should register all signals it is going to use to the scheduler.
- * To unregister a signal call silc_schedule_signal_unregister. On
- * platform that does not support signals calling this function has not
- * effect.
+ * The `callback' with `context' will be called after the application
+ * has called silc_schedule_signal_call function in the real signal
+ * callback. Application is responsible of calling that, and the
+ * signal system will not work without calling silc_schedule_signal_call
+ * function. The specified `signal' value will be also delivered to
+ * the `callback' as the fd-argument. The event type in the callback
+ * will be SILC_TASK_INTERRUPT. It is safe to use any SILC routines,
+ * in the `callback' since it is actually called after the signal really
+ * happened.
+ *
+ * On platform that does not support signals calling this function has
+ * not effect.
+ *
+ * EXAMPLE
+ *
+ * Typical signal usage case on Unix systems:
+ *
+ * struct sigaction sa;
+ * sa.sa_handler = signal_handler;
+ * sigaction(SIGHUP, &sa, NULL);
+ * sigaction(SIGINT, &sa, NULL);
+ * silc_schedule_signal_register(schedule, SIGHUP, hup_signal, context);
+ * silc_schedule_signal_register(schedule, SIGINT, int_signal, context);
+ *
+ * static void signal_handler(int sig)
+ * {
+ * silc_schedule_signal_call(schedule, sig);
+ * }
+ *
+ * The `signal_handler' can be used as generic signal callback in the
+ * application that merely calls silc_schedule_signal_call, which then
+ * eventually will deliver for example the `hup_signal' callback. The
+ * same `signal_handler' can be used with all signals.
*
***/
-void silc_schedule_signal_register(SilcSchedule schedule, SilcUInt32 signal);
+void silc_schedule_signal_register(SilcSchedule schedule, SilcUInt32 signal,
+ SilcTaskCallback callback, void *context);
/****f* silcutil/SilcScheduleAPI/silc_schedule_signal_unregister
*
* SYNOPSIS
*
* void silc_schedule_signal_unregister(SilcSchedule schedule,
- * SilcUInt32 signal);
+ * SilcUInt32 signal,
+ * SilcTaskCallback callback,
+ * void *context);
*
* DESCRIPTION
*
* effect.
*
***/
-void silc_schedule_signal_unregister(SilcSchedule schedule, SilcUInt32 signal);
+void silc_schedule_signal_unregister(SilcSchedule schedule, SilcUInt32 signal,
+ SilcTaskCallback callback, void *context);
+
+/****f* silcutil/SilcScheduleAPI/silc_schedule_signal_call
+ *
+ * SYNOPSIS
+ *
+ * void silc_schedule_signal_call(SilcSchedule schedule,
+ * SilcUInt32 signal);
+ *
+ * DESCRIPTION
+ *
+ * Mark the `signal' to be called later. Every signal that has been
+ * registered by silc_schedule_signal_register is delivered by calling
+ * this function. When signal really occurs, the application is
+ * responsible of calling this function int the signal handler. After
+ * signal is over the scheduler will then safely deliver the callback
+ * that was given to silc_schedule_signal_register function.
+ *
+ ***/
+void silc_schedule_signal_call(SilcSchedule schedule, SilcUInt32 signal);
#endif
return ret;
}
+#define SIGNAL_COUNT 32
+
+typedef struct {
+ SilcUInt32 signal;
+ SilcTaskCallback callback;
+ void *context;
+ bool call;
+} SilcUnixSignal;
+
/* Internal context. */
typedef struct {
int wakeup_pipe[2];
SilcTask wakeup_task;
sigset_t signals;
sigset_t signals_blocked;
+ SilcUnixSignal signal_call[SIGNAL_COUNT];
} *SilcUnixScheduler;
#ifdef SILC_THREADS
}
void silc_schedule_internal_signal_register(void *context,
- SilcUInt32 signal)
+ SilcUInt32 signal,
+ SilcTaskCallback callback,
+ void *callback_context)
{
SilcUnixScheduler internal = (SilcUnixScheduler)context;
+ int i;
+
+ 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;
+ }
+ }
+
sigaddset(&internal->signals, signal);
}
void silc_schedule_internal_signal_unregister(void *context,
- SilcUInt32 signal)
+ SilcUInt32 signal,
+ SilcTaskCallback callback,
+ void *callback_context)
{
SilcUnixScheduler internal = (SilcUnixScheduler)context;
+ int i;
+
+ 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;
+ }
+ }
+
sigdelset(&internal->signals, signal);
}
+/* Mark signal to be called later. */
+
+void silc_schedule_internal_signal_call(void *context, SilcUInt32 signal)
+{
+ SilcUnixScheduler internal = (SilcUnixScheduler)context;
+ int i;
+
+ for (i = 0; i < SIGNAL_COUNT; i++) {
+ if (internal->signal_call[i].signal == signal)
+ internal->signal_call[i].call = TRUE;
+ }
+}
+
+/* Call all signals */
+
+void silc_schedule_internal_signals_call(void *context,
+ SilcSchedule schedule)
+{
+ SilcUnixScheduler internal = (SilcUnixScheduler)context;
+ int i;
+
+ for (i = 0; i < SIGNAL_COUNT; i++) {
+ if (internal->signal_call[i].call &&
+ internal->signal_call[i].callback) {
+ internal->signal_call[i].callback(schedule, SILC_TASK_INTERRUPT,
+ internal->signal_call[i].signal,
+ internal->signal_call[i].context);
+ internal->signal_call[i].call = FALSE;
+ }
+ }
+}
+
/* Block registered signals in scheduler. */
void silc_schedule_internal_signals_block(void *context)
/* Register signal */
void silc_schedule_internal_signal_register(void *context,
- SilcUInt32 signal)
+ SilcUInt32 signal,
+ SilcTaskCallback callback,
+ void *callback_context)
{
}
/* Unregister signal */
void silc_schedule_internal_signal_unregister(void *context,
- SilcUInt32 signal)
+ SilcUInt32 signal,
+ SilcTaskCallback callback,
+ void *callback_context)
+{
+
+}
+
+/* Mark signal to be called later. */
+
+void silc_schedule_internal_signal_call(void *context, SilcUInt32 signal)
+{
+
+}
+
+/* Call all signals */
+
+void silc_schedule_internal_signals_call(void *context,
+ SilcSchedule schedule)
{
}