From f50fab3886a56151079728daa678fed3b882b433 Mon Sep 17 00:00:00 2001 From: Pekka Riikonen Date: Sun, 17 Mar 2002 09:23:05 +0000 Subject: [PATCH] Added signals suppor to shceduler. --- CHANGES | 22 +++++ TODO-1.0 | 4 + apps/silcd/silcd.c | 3 + lib/silcutil/os2/silcos2schedule.c | 45 ++++++++-- lib/silcutil/silcschedule.c | 88 +++++++++++++------ lib/silcutil/silcschedule.h | 34 ++++++++ lib/silcutil/unix/silcunixschedule.c | 112 ++++++++++++++++--------- lib/silcutil/win32/silcwin32schedule.c | 46 ++++++++-- 8 files changed, 271 insertions(+), 83 deletions(-) diff --git a/CHANGES b/CHANGES index 3a53dc28..d5e56ae7 100644 --- a/CHANGES +++ b/CHANGES @@ -1,3 +1,25 @@ +Sun Mar 17 10:24:50 EET 2002 Pekka Riikonen + + * 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 * Check for unauthenticated client and server in the diff --git a/TODO-1.0 b/TODO-1.0 index 81407563..d16cd747 100644 --- 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. diff --git a/apps/silcd/silcd.c b/apps/silcd/silcd.c index 21af435b..616f50c4 100644 --- a/apps/silcd/silcd.c +++ b/apps/silcd/silcd.c @@ -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) diff --git a/lib/silcutil/os2/silcos2schedule.c b/lib/silcutil/os2/silcos2schedule.c index fc775056..54cfa374 100644 --- a/lib/silcutil/os2/silcos2schedule.c +++ b/lib/silcutil/os2/silcos2schedule.c @@ -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) +{ + +} diff --git a/lib/silcutil/silcschedule.c b/lib/silcutil/silcschedule.c index 0305893e..240ddeb2 100644 --- a/lib/silcutil/silcschedule.c +++ b/lib/silcutil/silcschedule.c @@ -25,26 +25,37 @@ /* 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) diff --git a/lib/silcutil/silcschedule.h b/lib/silcutil/silcschedule.h index e7479f4f..1de2ec4c 100644 --- a/lib/silcutil/silcschedule.h +++ b/lib/silcutil/silcschedule.h @@ -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 diff --git a/lib/silcutil/unix/silcunixschedule.c b/lib/silcutil/unix/silcunixschedule.c index 98a1d8a4..bf12f7b2 100644 --- a/lib/silcutil/unix/silcunixschedule.c +++ b/lib/silcutil/unix/silcunixschedule.c @@ -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); +} diff --git a/lib/silcutil/win32/silcwin32schedule.c b/lib/silcutil/win32/silcwin32schedule.c index f3bf02cc..66b732ab 100644 --- a/lib/silcutil/win32/silcwin32schedule.c +++ b/lib/silcutil/win32/silcwin32schedule.c @@ -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) +{ + +} -- 2.24.0