Improved signals support in scheduler.
authorPekka Riikonen <priikone@silcnet.org>
Wed, 20 Mar 2002 10:09:14 +0000 (10:09 +0000)
committerPekka Riikonen <priikone@silcnet.org>
Wed, 20 Mar 2002 10:09:14 +0000 (10:09 +0000)
CHANGES
apps/silcd/silcd.c
lib/silcutil/os2/silcos2schedule.c
lib/silcutil/silcschedule.c
lib/silcutil/silcschedule.h
lib/silcutil/unix/silcunixschedule.c
lib/silcutil/win32/silcwin32schedule.c

diff --git a/CHANGES b/CHANGES
index 6e419f7f7ca0b63532d288c5ab4866b8d9072fdc..a5b0b35b318b75a8b08360ccb4b6e3fc3f6a6016 100644 (file)
--- a/CHANGES
+++ b/CHANGES
@@ -1,3 +1,13 @@
+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
index 616f50c43597a08070cda9af8e6a60a394705579..e5f45e3b850be4a7dc235729e55f287ee620409d 100644 (file)
@@ -127,14 +127,20 @@ static void silc_server_checkpid(SilcServer silcd)
   }
 }
 
-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. */
@@ -251,15 +257,13 @@ int main(int argc, char **argv)
   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)
index 54cfa3747665857de20adefc6afaa05bb7d7e752..53904de47fc0290389d153e3b0a40a895b7b2f64 100644 (file)
@@ -114,8 +114,11 @@ void silc_schedule_internal_wakeup(void *context)
 }
 
 /* Register signal */
+
 void silc_schedule_internal_signal_register(void *context,
-                                           SilcUInt32 signal)
+                                            SilcUInt32 signal,
+                                            SilcTaskCallback callback,
+                                            void *callback_context)
 {
 
 }
@@ -123,7 +126,24 @@ void silc_schedule_internal_signal_register(void *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)
 {
 
 }
index cb4a9693c5f23d829b6fc72a07fba25905a90dde..b7627350758bbada7b1b7fd05ff01422d85e850d 100644 (file)
@@ -45,11 +45,22 @@ void silc_schedule_internal_wakeup(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);
 
 /* Block registered signals in scheduler. */
 void silc_schedule_internal_signals_block(void *context);
@@ -190,6 +201,11 @@ struct SilcTaskQueueStruct {
   
        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;
@@ -203,6 +219,7 @@ struct SilcScheduleStruct {
   void *internal;
   SILC_MUTEX_DEFINE(lock);
   bool is_locked;
+  bool signal_tasks;
 };
 
 /* Initializes the scheduler. This returns the scheduler context that
@@ -238,9 +255,6 @@ SilcSchedule silc_schedule_init(int max_tasks)
 
   /* Initialize the platform specific scheduler. */
   schedule->internal = silc_schedule_internal_init(schedule);
-#ifdef SILC_UNIX
-  silc_schedule_signal_register(schedule, SIGALRM);
-#endif
 
   return schedule;
 }
@@ -573,6 +587,12 @@ bool silc_schedule_one(SilcSchedule schedule, int timeout_usecs)
 
   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. */
@@ -876,16 +896,29 @@ void silc_schedule_unset_listen_fd(SilcSchedule schedule, SilcUInt32 fd)
 
 /* 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 */
index 4b23067dd4cf566d7950448aafae8ddde8008304..953dbe7301d56fcbe06a104a750b4221dcc9e863 100644 (file)
@@ -165,6 +165,7 @@ typedef enum {
   SILC_TASK_READ      = 0x0001,                 /* Reading */
   SILC_TASK_WRITE     = 0x0002,                 /* Writing */
   SILC_TASK_EXPIRE    = 0x0004,                 /* Timeout */
+  SILC_TASK_INTERRUPT = 0x0004,                 /* Signal */
 } SilcTaskEvent;
 /***/
 
@@ -574,25 +575,60 @@ void silc_schedule_unset_listen_fd(SilcSchedule schedule, SilcUInt32 fd);
  * 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
  *
@@ -601,6 +637,26 @@ void silc_schedule_signal_register(SilcSchedule schedule, SilcUInt32 signal);
  *    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
index bf12f7b21ac387a0f3c4383016fead9b060f15d6..ae2ce91210c5020102df09700c2d052f842fcafc 100644 (file)
@@ -65,12 +65,22 @@ int silc_select(SilcScheduleFd fds, SilcUInt32 fds_count,
   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
@@ -154,19 +164,79 @@ void silc_schedule_internal_wakeup(void *context)
 }
 
 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)
index 66b732ab3882f6bb6118517a79223d7086cfef37..e6aa6c9d04023df98dd58579359f8e755d11acbb 100644 (file)
@@ -255,7 +255,9 @@ void silc_schedule_internal_wakeup(void *context)
 /* Register signal */
 
 void silc_schedule_internal_signal_register(void *context,
-                                           SilcUInt32 signal)
+                                            SilcUInt32 signal,
+                                            SilcTaskCallback callback,
+                                            void *callback_context)
 {
 
 }
@@ -263,7 +265,24 @@ void silc_schedule_internal_signal_register(void *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)
 {
 
 }