Added signals suppor to shceduler.
authorPekka Riikonen <priikone@silcnet.org>
Sun, 17 Mar 2002 09:23:05 +0000 (09:23 +0000)
committerPekka Riikonen <priikone@silcnet.org>
Sun, 17 Mar 2002 09:23:05 +0000 (09:23 +0000)
CHANGES
TODO-1.0
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 3a53dc287d1e4050f5ae486e60e33e6d01457396..d5e56ae7a9dbcf090243b8077338935c3dd2e633 100644 (file)
--- a/CHANGES
+++ b/CHANGES
@@ -1,3 +1,25 @@
+Sun Mar 17 10:24:50 EET 2002  Pekka Riikonen <priikone@silcnet.org>
+
+       * Added preliminary support for signals in scheduler.  The
+         signals we care about are now blocked always when the scheduler
+         is locked.  This way we can synchronise the use of signal with
+         scheduler.  It is guaranteed that when signal occurs the scheduler
+         is not locked, and thus new tasks can be safely added to the
+         scheduler.
+
+         Renamed silc_schedule_wakeup_init and silc_schedule_wakeup_uninit
+         to silc_schedule_internal_init and silc_schedule_internal_uninit.
+         Added new platform specific routines
+         silc_schedule_internal_signals_[un]block and 
+         silc_schedule_internal_signal_[un]register.
+
+         Added new functions to SILC Schedule API:
+         silc_schedule_signal_[un]register.  Each signal that application
+         is going to use should be registered to the scheduler.
+
+         Affected files are lib/silcutil/silcschedule.[ch],
+         lib/silcutil/*/silc*schedule.c.
+
 Sat Mar 16 22:39:23 EET 2002  Pekka Riikonen <priikone@silcnet.org>
 
        * Check for unauthenticated client and server in the
index 814075631fe9c44b62620f0889d420fd9b26068a..d16cd747fddac25dafc1ab280857bcda3f0835ed 100644 (file)
--- a/TODO-1.0
+++ b/TODO-1.0
@@ -145,6 +145,10 @@ least could be done.
  o SILC RNG does not implement random seed files, and they should be
    implemented.
 
+ o Add SILC scheduler's internal routines into a table of implementation
+   function pointers, that the generic code then takes as extern from
+   implementation.  These are the silc_schedule_internal_* routines.
+
  o Cipher optimizations (asm, that this) at least for i386 would be nice.
 
  o Add builtin SOCKS and HTTP Proxy support, well the SOCKS at least.
index 21af435ba25be1a0e11cbf9962a732c3234048de..616f50c43597a08070cda9af8e6a60a394705579 100644 (file)
@@ -257,6 +257,9 @@ int main(int argc, char **argv)
   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);
 
   /* Before running the server, fork to background. */
   if (!foreground)
index fc775056577b133eca4846e795f3e950f444c2b8..54cfa3747665857de20adefc6afaa05bb7d7e752 100644 (file)
@@ -81,14 +81,12 @@ SILC_TASK_CALLBACK(silc_schedule_wakeup_cb)
 
 #endif /* SILC_THREADS */
 
-/* Initializes the wakeup of the scheduler. In multi-threaded environment
+/* Initializes the platform specific scheduler.  This for example initializes
+   the wakeup mechanism of the scheduler.  In multi-threaded environment
    the scheduler needs to be wakenup when tasks are added or removed from
-   the task queues. This will initialize the wakeup for the scheduler.
-   Any tasks that needs to be registered must be registered to the `queue'.
-   It is quaranteed that the scheduler will automatically free any
-   registered tasks in this queue. This is system specific routine. */
+   the task queues.  Returns context to the platform specific scheduler. */
 
-void *silc_schedule_wakeup_init(SilcSchedule schedule)
+void *silc_schedule_internal_init(SilcSchedule schedule)
 {
 #ifdef SILC_THREADS
   return NULL;
@@ -97,9 +95,9 @@ void *silc_schedule_wakeup_init(SilcSchedule schedule)
   return NULL;
 }
 
-/* Uninitializes the system specific wakeup. */
+/* Uninitializes the platform specific scheduler context. */
 
-void silc_schedule_wakeup_uninit(void *context)
+void silc_schedule_internal_uninit(void *context)
 {
 #ifdef SILC_THREADS
 
@@ -108,9 +106,38 @@ void silc_schedule_wakeup_uninit(void *context)
 
 /* Wakes up the scheduler */
 
-void silc_schedule_wakeup_internal(void *context)
+void silc_schedule_internal_wakeup(void *context)
 {
 #ifdef SILC_THREADS
 
 #endif
 }
+
+/* Register signal */
+void silc_schedule_internal_signal_register(void *context,
+                                           SilcUInt32 signal)
+{
+
+}
+
+/* Unregister signal */
+
+void silc_schedule_internal_signal_unregister(void *context,
+                                             SilcUInt32 signal)
+{
+
+}
+
+/* Block registered signals in scheduler. */
+
+void silc_schedule_internal_signals_block(void *context)
+{
+
+}
+
+/* Unblock registered signals in schedule. */
+
+void silc_schedule_internal_signals_unblock(void *context)
+{
+
+}
index 0305893e27679a9a706d09820d9c616cdeed8b14..240ddeb28e3e208f8e56405e9edf1bd9d8932bdd 100644 (file)
 /* Forward declarations */
 typedef struct SilcTaskQueueStruct *SilcTaskQueue;
 
-/* System specific routines. Implemented under unix/ and win32/. */
+/* System specific routines. Implemented under unix/, win32/ and such. */
 
 /* System specific select(). Returns same values as normal select(). */
 int silc_select(SilcScheduleFd fds, SilcUInt32 fds_count, 
                struct timeval *timeout);
 
-/* Initializes the wakeup of the scheduler. In multi-threaded environment
+/* Initializes the platform specific scheduler.  This for example initializes
+   the wakeup mechanism of the scheduler.  In multi-threaded environment
    the scheduler needs to be wakenup when tasks are added or removed from
-   the task queues. This will initialize the wakeup for the scheduler.
-   Any tasks that needs to be registered must be registered to the `queue'.
-   It is guaranteed that the scheduler will automatically free any
-   registered tasks in this queue. This is system specific routine. */
-void *silc_schedule_wakeup_init(SilcSchedule schedule);
+   the task queues.  Returns context to the platform specific scheduler. */
+void *silc_schedule_internal_init(SilcSchedule schedule);
 
-/* Uninitializes the system specific wakeup. */
-void silc_schedule_wakeup_uninit(void *context);
+/* Uninitializes the platform specific scheduler context. */
+void silc_schedule_internal_uninit(void *context);
 
 /* Wakes up the scheduler. This is platform specific routine */
-void silc_schedule_wakeup_internal(void *context);
+void silc_schedule_internal_wakeup(void *context);
 
+/* Register signal */
+void silc_schedule_internal_signal_register(void *context,
+                                           SilcUInt32 signal);
+
+/* Unregister signal */
+void silc_schedule_internal_signal_unregister(void *context,
+                                             SilcUInt32 signal);
+
+/* Block registered signals in scheduler. */
+void silc_schedule_internal_signals_block(void *context);
+
+/* Unblock registered signals in schedule. */
+void silc_schedule_internal_signals_unblock(void *context);
 
 /* Internal task management routines. */
 
@@ -65,14 +76,24 @@ static void silc_task_del_by_callback(SilcTaskQueue queue,
 static void silc_task_del_by_fd(SilcTaskQueue queue, SilcUInt32 fd);
 
 /* Returns the task queue by task type */
-#define SILC_SCHEDULE_GET_QUEUE(type)                                  \
-  (type == SILC_TASK_FD ? schedule->fd_queue :                         \
-   type == SILC_TASK_TIMEOUT ? schedule->timeout_queue :               \
+#define SILC_SCHEDULE_GET_QUEUE(type)                          \
+  (type == SILC_TASK_FD ? schedule->fd_queue :                 \
+   type == SILC_TASK_TIMEOUT ? schedule->timeout_queue :       \
    schedule->generic_queue)
 
-/* Locks */
-#define SILC_SCHEDULE_LOCK(schedule) silc_mutex_lock(schedule->lock)
-#define SILC_SCHEDULE_UNLOCK(schedule) silc_mutex_unlock(schedule->lock)
+/* Locks. These also blocks signals that we care about and thus guarantee
+   that while we are in scheduler no signals can happen.  This way we can
+   synchronise signals with SILC Scheduler. */
+#define SILC_SCHEDULE_LOCK(schedule)                           \
+do {                                                           \
+  silc_schedule_internal_signals_block(schedule->internal);    \
+  silc_mutex_lock(schedule->lock);                             \
+} while (0)
+#define SILC_SCHEDULE_UNLOCK(schedule)                         \
+do {                                                           \
+  silc_mutex_unlock(schedule->lock);                           \
+  silc_schedule_internal_signals_unblock(schedule->internal);  \
+} while (0)
 
 /* SILC Task object. Represents one task in the scheduler. */
 struct SilcTaskStruct {
@@ -161,11 +182,9 @@ struct SilcTaskQueueStruct {
        File descriptor sets for select(). These are automatically managed
        by the scheduler and should not be touched otherwise.
 
-   void *wakeup
+   void *internal
 
-       System specific wakeup context. On multi-threaded environments the
-       scheduler needs to be wakenup (in the thread) when tasks are added
-       or removed. This is initialized by silc_schedule_wakeup_init.
+       System specific scheduler context.
 
    SILC_MUTEX_DEFINE(lock)
   
@@ -181,7 +200,7 @@ struct SilcScheduleStruct {
   SilcUInt32 last_fd;
   struct timeval *timeout;
   bool valid;
-  void *wakeup;
+  void *internal;
   SILC_MUTEX_DEFINE(lock);
   bool is_locked;
 };
@@ -217,8 +236,9 @@ SilcSchedule silc_schedule_init(int max_tasks)
   /* Allocate scheduler lock */
   silc_mutex_alloc(&schedule->lock);
 
-  /* Initialize the wakeup, for multi-threads support */
-  schedule->wakeup = silc_schedule_wakeup_init(schedule);
+  /* Initialize the platform specific scheduler. */
+  schedule->internal = silc_schedule_internal_init(schedule);
+  silc_schedule_signal_register(schedule, SIGALRM);
 
   return schedule;
 }
@@ -247,8 +267,8 @@ bool silc_schedule_uninit(SilcSchedule schedule)
 
   silc_free(schedule->fd_list);
 
-  /* Uninit the wakeup */
-  silc_schedule_wakeup_uninit(schedule->wakeup);
+  /* Uninit the platform specific scheduler. */
+  silc_schedule_internal_uninit(schedule->internal);
 
   silc_mutex_free(schedule->lock);
 
@@ -276,7 +296,9 @@ bool silc_schedule_reinit(SilcSchedule schedule, int max_tasks)
 void silc_schedule_stop(SilcSchedule schedule)
 {
   SILC_LOG_DEBUG(("Stopping scheduler"));
+  SILC_SCHEDULE_LOCK(schedule);
   schedule->valid = FALSE;
+  SILC_SCHEDULE_UNLOCK(schedule);
 }
 
 /* Executes nontimeout tasks. It then checks whether any of ther fd tasks
@@ -619,7 +641,7 @@ void silc_schedule_wakeup(SilcSchedule schedule)
 #ifdef SILC_THREADS
   SILC_LOG_DEBUG(("Wakeup scheduler"));
   SILC_SCHEDULE_LOCK(schedule);
-  silc_schedule_wakeup_internal(schedule->wakeup);
+  silc_schedule_internal_wakeup(schedule->internal);
   SILC_SCHEDULE_UNLOCK(schedule);
 #endif
 }
@@ -850,6 +872,20 @@ void silc_schedule_unset_listen_fd(SilcSchedule schedule, SilcUInt32 fd)
   SILC_SCHEDULE_UNLOCK(schedule);
 }
 
+/* Register a new signal */
+
+void silc_schedule_signal_register(SilcSchedule schedule, SilcUInt32 signal)
+{
+  silc_schedule_internal_signal_register(schedule->internal, signal);
+}
+
+/* Unregister a new signal */
+
+void silc_schedule_signal_unregister(SilcSchedule schedule, SilcUInt32 signal)
+{
+  silc_schedule_internal_signal_unregister(schedule->internal, signal);
+}
+
 /* Allocates a newtask task queue into the scheduler */
 
 static void silc_task_queue_alloc(SilcTaskQueue *queue)
index e7479f4f4b0be61f9e29fb833d6c48504876e7b1..1de2ec4c8e8deef4ecc8ed0f39e6a5ed5c6debdf 100644 (file)
@@ -569,4 +569,38 @@ void silc_schedule_set_listen_fd(SilcSchedule schedule, SilcUInt32 fd,
  ***/
 void silc_schedule_unset_listen_fd(SilcSchedule schedule, SilcUInt32 fd);
 
+/****f* silcutil/SilcScheduleAPI/silc_schedule_signal_register
+ *
+ * SYNOPSIS
+ *
+ *    void silc_schedule_signal_register(SilcSchedule schedule, 
+ *                                       SilcUInt32 signal);
+ *
+ * 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.
+ *
+ ***/
+void silc_schedule_signal_register(SilcSchedule schedule, SilcUInt32 signal);
+
+/****f* silcutil/SilcScheduleAPI/silc_schedule_signal_unregister
+ *
+ * SYNOPSIS
+ *
+ *    void silc_schedule_signal_unregister(SilcSchedule schedule, 
+ *                                       SilcUInt32 signal);
+ *
+ * DESCRIPTION
+ *
+ *    Unregister a signal indicated by `signal' from the scheduler.  On
+ *    platform that does not support signals calling this function has no
+ *    effect.
+ *
+ ***/
+void silc_schedule_signal_unregister(SilcSchedule schedule, SilcUInt32 signal);
+
 #endif
index 98a1d8a4fc32527d728d1ce98e15142f020f6013..bf12f7b21ac387a0f3c4383016fead9b060f15d6 100644 (file)
@@ -65,86 +65,120 @@ int silc_select(SilcScheduleFd fds, SilcUInt32 fds_count,
   return ret;
 }
 
-#ifdef SILC_THREADS
-
-/* Internal wakeup context. */
+/* Internal context. */
 typedef struct {
   int wakeup_pipe[2];
   SilcTask wakeup_task;
-} *SilcUnixWakeup;
+  sigset_t signals;
+  sigset_t signals_blocked;
+} *SilcUnixScheduler;
+
+#ifdef SILC_THREADS
 
 SILC_TASK_CALLBACK(silc_schedule_wakeup_cb)
 {
-  SilcUnixWakeup wakeup = (SilcUnixWakeup)context;
+  SilcUnixScheduler internal = (SilcUnixScheduler)context;
   unsigned char c;
 
-  read(wakeup->wakeup_pipe[0], &c, 1);
+  read(internal->wakeup_pipe[0], &c, 1);
 }
 
 #endif /* SILC_THREADS */
 
-/* Initializes the wakeup of the scheduler. In multi-threaded environment
+/* Initializes the platform specific scheduler.  This for example initializes
+   the wakeup mechanism of the scheduler.  In multi-threaded environment
    the scheduler needs to be wakenup when tasks are added or removed from
-   the task queues. This will initialize the wakeup for the scheduler.
-   Any tasks that needs to be registered must be registered to the `queue'.
-   It is quaranteed that the scheduler will automatically free any
-   registered tasks in this queue. This is system specific routine. */
+   the task queues.  Returns context to the platform specific scheduler. */
 
-void *silc_schedule_wakeup_init(SilcSchedule schedule)
+void *silc_schedule_internal_init(SilcSchedule schedule)
 {
-#ifdef SILC_THREADS
-  SilcUnixWakeup wakeup;
+  SilcUnixScheduler internal;
+
+  internal = silc_calloc(1, sizeof(*internal));
+  if (!internal)
+    return NULL;
 
-  wakeup = silc_calloc(1, sizeof(*wakeup));
+  sigemptyset(&internal->signals);
 
-  if (pipe(wakeup->wakeup_pipe)) {
-    silc_free(wakeup);
+#ifdef SILC_THREADS
+  if (pipe(internal->wakeup_pipe)) {
+    silc_free(internal);
     return NULL;
   }
 
-  wakeup->wakeup_task = 
-    silc_schedule_task_add(schedule, wakeup->wakeup_pipe[0],
-                          silc_schedule_wakeup_cb, wakeup,
+  internal->wakeup_task = 
+    silc_schedule_task_add(schedule, internal->wakeup_pipe[0],
+                          silc_schedule_wakeup_cb, internal,
                           0, 0, SILC_TASK_FD, 
                           SILC_TASK_PRI_NORMAL);
-  if (!wakeup->wakeup_task) {
-    close(wakeup->wakeup_pipe[0]);
-    close(wakeup->wakeup_pipe[1]);
-    silc_free(wakeup);
+  if (!internal->wakeup_task) {
+    close(internal->wakeup_pipe[0]);
+    close(internal->wakeup_pipe[1]);
+    silc_free(internal);
     return NULL;
   }
-
-  return (void *)wakeup;
 #endif
-  return NULL;
+
+  return (void *)internal;
 }
 
-/* Uninitializes the system specific wakeup. */
+/* Uninitializes the platform specific scheduler context. */
 
-void silc_schedule_wakeup_uninit(void *context)
+void silc_schedule_internal_uninit(void *context)
 {
-#ifdef SILC_THREADS
-  SilcUnixWakeup wakeup = (SilcUnixWakeup)context;
+  SilcUnixScheduler internal = (SilcUnixScheduler)context;
 
-  if (!wakeup)
+  if (!internal)
     return;
 
-  close(wakeup->wakeup_pipe[0]);
-  close(wakeup->wakeup_pipe[1]);
-  silc_free(wakeup);
+#ifdef SILC_THREADS
+  close(internal->wakeup_pipe[0]);
+  close(internal->wakeup_pipe[1]);
 #endif
+
+  silc_free(internal);
 }
 
 /* Wakes up the scheduler */
 
-void silc_schedule_wakeup_internal(void *context)
+void silc_schedule_internal_wakeup(void *context)
 {
 #ifdef SILC_THREADS
-  SilcUnixWakeup wakeup = (SilcUnixWakeup)context;
+  SilcUnixScheduler internal = (SilcUnixScheduler)context;
 
-  if (!wakeup)
+  if (!internal)
     return;
 
-  write(wakeup->wakeup_pipe[1], "!", 1);
+  write(internal->wakeup_pipe[1], "!", 1);
 #endif
 }
+
+void silc_schedule_internal_signal_register(void *context,
+                                           SilcUInt32 signal)
+{
+  SilcUnixScheduler internal = (SilcUnixScheduler)context;
+  sigaddset(&internal->signals, signal);
+}
+
+void silc_schedule_internal_signal_unregister(void *context,
+                                             SilcUInt32 signal)
+{
+  SilcUnixScheduler internal = (SilcUnixScheduler)context;
+  sigdelset(&internal->signals, signal);
+}
+
+/* Block registered signals in scheduler. */
+
+void silc_schedule_internal_signals_block(void *context)
+{
+  SilcUnixScheduler internal = (SilcUnixScheduler)context;
+  sigprocmask(SIG_BLOCK, &internal->signals, &internal->signals_blocked);
+}
+
+/* Unblock registered signals in schedule. */
+
+void silc_schedule_internal_signals_unblock(void *context)
+{
+  SilcUnixScheduler internal = (SilcUnixScheduler)context;
+  sigprocmask(SIG_SETMASK, &internal->signals_blocked, NULL);
+}
index f3bf02cc0f894d5ef98083bcd8baf7e8483917b2..66b732ab3882f6bb6118517a79223d7086cfef37 100644 (file)
@@ -188,14 +188,12 @@ SILC_TASK_CALLBACK(silc_schedule_wakeup_cb)
 
 #endif /* SILC_THREADS */
 
-/* Initializes the wakeup of the scheduler. In multi-threaded environment
+/* Initializes the platform specific scheduler.  This for example initializes
+   the wakeup mechanism of the scheduler.  In multi-threaded environment
    the scheduler needs to be wakenup when tasks are added or removed from
-   the task queues. This will initialize the wakeup for the scheduler.
-   Any tasks that needs to be registered must be registered to the `queue'.
-   It is guaranteed that the scheduler will automatically free any
-   registered tasks in this queue. This is system specific routine. */
+   the task queues.  Returns context to the platform specific scheduler. */
 
-void *silc_schedule_wakeup_init(SilcSchedule schedule)
+void *silc_schedule_internal_init(SilcSchedule schedule)
 {
 #ifdef SILC_THREADS
   SilcWin32Wakeup wakeup;
@@ -225,9 +223,9 @@ void *silc_schedule_wakeup_init(SilcSchedule schedule)
 #endif
 }
 
-/* Uninitializes the system specific wakeup. */
+/* Uninitializes the platform specific scheduler context. */
 
-void silc_schedule_wakeup_uninit(void *context)
+void silc_schedule_internal_uninit(void *context)
 {
 #ifdef SILC_THREADS
   SilcWin32Wakeup wakeup = (SilcWin32Wakeup)context;
@@ -242,7 +240,7 @@ void silc_schedule_wakeup_uninit(void *context)
 
 /* Wakes up the scheduler */
 
-void silc_schedule_wakeup_internal(void *context)
+void silc_schedule_internal_wakeup(void *context)
 {
 #ifdef SILC_THREADS
   SilcWin32Wakeup wakeup = (SilcWin32Wakeup)context;
@@ -253,3 +251,33 @@ void silc_schedule_wakeup_internal(void *context)
   ReleaseSemaphore(wakeup->wakeup_sema, 1, NULL);
 #endif
 }
+
+/* Register signal */
+
+void silc_schedule_internal_signal_register(void *context,
+                                           SilcUInt32 signal)
+{
+
+}
+
+/* Unregister signal */
+
+void silc_schedule_internal_signal_unregister(void *context,
+                                             SilcUInt32 signal)
+{
+
+}
+
+/* Block registered signals in scheduler. */
+
+void silc_schedule_internal_signals_block(void *context)
+{
+
+}
+
+/* Unblock registered signals in schedule. */
+
+void silc_schedule_internal_signals_unblock(void *context)
+{
+
+}