From 4c6c24cc5513d0725b6a4afd2ce30acbedd65ab2 Mon Sep 17 00:00:00 2001 From: Pekka Riikonen Date: Sun, 22 Oct 2006 10:37:07 +0000 Subject: [PATCH] Removed signal registering and unregistering and added silc_schedule_task_add_signal to add signals as task. The signals are also automatically called back to caller instead of requiring caller to handle the calling manually. --- lib/silcutil/silcschedule.c | 43 ++---- lib/silcutil/silcschedule.h | 183 ++++++------------------- lib/silcutil/silcschedule_i.h | 16 ++- lib/silcutil/unix/silcunixschedule.c | 115 +++++++--------- lib/silcutil/win32/silcwin32schedule.c | 15 +- 5 files changed, 122 insertions(+), 250 deletions(-) diff --git a/lib/silcutil/silcschedule.c b/lib/silcutil/silcschedule.c index 495ff366..de7db5e0 100644 --- a/lib/silcutil/silcschedule.c +++ b/lib/silcutil/silcschedule.c @@ -554,7 +554,8 @@ SilcTask silc_schedule_task_add(SilcSchedule schedule, SilcUInt32 fd, silc_list_add(schedule->timeout_queue, ttask); task = (SilcTask)ttask; - } else { + + } else if (type == SILC_TASK_FD) { /* Check if fd is already added */ if (silc_hash_table_find(schedule->fd_queue, SILC_32_TO_PTR(fd), NULL, (void **)&task)) @@ -584,8 +585,15 @@ SilcTask silc_schedule_task_add(SilcSchedule schedule, SilcUInt32 fd, silc_hash_table_add(schedule->fd_queue, SILC_32_TO_PTR(fd), ftask); task = (SilcTask)ftask; + + } else if (type == SILC_TASK_SIGNAL) { + SILC_SCHEDULE_UNLOCK(schedule); + schedule_ops.signal_register(schedule, schedule->internal, (int)fd, + callback, context); + return NULL; } + out: SILC_SCHEDULE_UNLOCK(schedule); return task; @@ -629,7 +637,7 @@ void silc_schedule_task_del(SilcSchedule schedule, SilcTask task) void silc_schedule_task_del_by_fd(SilcSchedule schedule, SilcUInt32 fd) { - SilcTask task; + SilcTask task = NULL; SILC_LOG_DEBUG(("Unregister task by fd %d", fd)); @@ -641,6 +649,10 @@ void silc_schedule_task_del_by_fd(SilcSchedule schedule, SilcUInt32 fd) task->valid = FALSE; SILC_SCHEDULE_UNLOCK(schedule); + + /* If it is signal, remove it */ + if (!task) + schedule_ops.signal_unregister(schedule, schedule->internal, fd); } /* Invalidate task by task callback. */ @@ -762,30 +774,3 @@ void silc_schedule_unset_listen_fd(SilcSchedule schedule, SilcUInt32 fd) { silc_schedule_set_listen_fd(schedule, fd, 0, FALSE); } - -/* Register a new signal */ - -void silc_schedule_signal_register(SilcSchedule schedule, SilcUInt32 signal, - SilcTaskCallback callback, void *context) -{ - schedule_ops.signal_register(schedule, schedule->internal, signal, - callback, context); -} - -/* Unregister a new signal */ - -void silc_schedule_signal_unregister(SilcSchedule schedule, SilcUInt32 signal, - SilcTaskCallback callback, void *context) -{ - schedule_ops.signal_unregister(schedule, schedule->internal, signal, - callback, context); -} - -/* Call signal indicated by `signal'. */ - -void silc_schedule_signal_call(SilcSchedule schedule, SilcUInt32 signal) -{ - /* Mark that signals needs to be delivered later. */ - schedule_ops.signal_call(schedule, schedule->internal, signal); - schedule->signal_tasks = TRUE; -} diff --git a/lib/silcutil/silcschedule.h b/lib/silcutil/silcschedule.h index dffa7142..85bbf339 100644 --- a/lib/silcutil/silcschedule.h +++ b/lib/silcutil/silcschedule.h @@ -120,6 +120,11 @@ typedef enum { task in task callback. It is also safe to unregister a task in the task callback. */ SILC_TASK_TIMEOUT, + + /* Platform specific process signal task. On Unix systems this is one of + the signals described in signal(7). On other platforms this may not + be available at all. Only one callback per signal may be added. */ + SILC_TASK_SIGNAL } SilcTaskType; /***/ @@ -343,53 +348,6 @@ void silc_schedule_wakeup(SilcSchedule schedule); ***/ void *silc_schedule_get_context(SilcSchedule schedule); -/****f* silcutil/SilcScheduleAPI/silc_schedule_task_add - * - * SYNOPSIS - * - * SilcTask silc_schedule_task_add(SilcSchedule schedule, SilcUInt32 fd, - * SilcTaskCallback callback, - * void *context, - * long seconds, long useconds, - * SilcTaskType type); - * - * DESCRIPTION - * - * Registers a new task to the scheduler. This same function is used - * to register all types of tasks. The `type' argument tells what type - * of the task is. Note that when registering non-timeout (fd) tasks one - * should also pass 0 as timeout, as the timeout will be ignored anyway. - * Also, note, that one cannot register timeout task with 0 timeout. - * There cannot be zero timeouts, passing zero means no timeout is used - * for the task and SILC_TASK_FD is used as default task type in - * this case. - * - * The `schedule' is the scheduler context. The `fd' is the file - * descriptor of the task. On WIN32 systems the `fd' is not actual - * file descriptor but some WIN32 event handle. On WIN32 system the `fd' - * may be a socket created by the SILC Net API routines, WSAEVENT object - * created by Winsock2 network routines or arbitrary WIN32 HANDLE object. - * On Unix systems the `fd' is always the real file descriptor. The - * same `fd' can be added only once. - * - * The `callback' is the task callback that will be called when some - * event occurs for this task. The `context' is sent as argument to - * the task `callback' function. For timeout tasks the callback is - * called after the specified timeout has elapsed. - * - * If the `type' is SILC_TASK_TIMEOUT then `seconds' and `useconds' - * may be non-zero. Otherwise they should be zero. - * - * It is always safe to call this function in any place. New tasks - * may be added also in task callbacks, and in multi-threaded environment - * in other threads as well. - * - ***/ -SilcTask silc_schedule_task_add(SilcSchedule schedule, SilcUInt32 fd, - SilcTaskCallback callback, void *context, - long seconds, long useconds, - SilcTaskType type); - /****f* silcutil/SilcScheduleAPI/silc_schedule_task_add_fd * * SYNOPSIS @@ -400,8 +358,10 @@ SilcTask silc_schedule_task_add(SilcSchedule schedule, SilcUInt32 fd, * * DESCRIPTION * - * A convenience function to add fd task. You may use this if you - * don't want to use the silc_schedule_task_add function to add fd task. + * Add file descriptor task to scheduler. The `fd' may be either real + * file descriptor, socket or on some platforms an opaque file descriptor + * handle. To receive events for the file descriptor set the correct + * request events with silc_schedule_set_listen_fd function. * ***/ #define silc_schedule_task_add_fd(schedule, fd, callback, context) \ @@ -418,15 +378,45 @@ SilcTask silc_schedule_task_add(SilcSchedule schedule, SilcUInt32 fd, * * DESCRIPTION * - * A convenience function to add timeout task. You may use this if - * you don't want to use the silc_schedule_task_add function to add - * timeout task. + * Add timeout task to scheduler. The `callback' will be called once + * the specified timeout has elapsed. The task will be removed from the + * scheduler automatically once the task expires. The event returned + * to the `callback' is SILC_TASK_EXPIRE. * ***/ #define silc_schedule_task_add_timeout(schedule, callback, context, s, u) \ silc_schedule_task_add(schedule, 0, callback, context, s, u, \ SILC_TASK_TIMEOUT) +/****f* silcutil/SilcScheduleAPI/silc_schedule_task_add_signal + * + * SYNOPSIS + * + * SilcTask + * silc_schedule_task_add_signal(SilcSchedule schedule, int signal, + * SilcTaskCallback callback, void *context); + * + * DESCRIPTION + * + * Add platform specific process signal handler to scheduler. On Unix + * systems the `signal' is one of the signal specified in signal(7). On + * other platforms this function may not be available at all, and has no + * effect when called. The event delivered to the `callback' is + * SILC_TASK_INTERRUPT. + * + * NOTES + * + * One signal may be registered only one callback. Adding second callback + * for signal that already has one will fail. + * + * This function always returns NULL. To remove signal from scheduler by + * the signal call silc_schedule_task_del_by_fd. + * + ***/ +#define silc_schedule_task_add_signal(schedule, signal, callback, context) \ + silc_schedule_task_add(schedule, signal, callback, context, 0, 0, \ + SILC_TASK_SIGNAL) + /****f* silcutil/SilcScheduleAPI/silc_schedule_task_del * * SYNOPSIS @@ -566,95 +556,6 @@ 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, - * 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. - * 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 - * no 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, - SilcTaskCallback callback, void *context); - -/****f* silcutil/SilcScheduleAPI/silc_schedule_signal_unregister - * - * SYNOPSIS - * - * void silc_schedule_signal_unregister(SilcSchedule schedule, - * SilcUInt32 signal, - * SilcTaskCallback callback, - * void *context); - * - * 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, - 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 in 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); - #include "silcschedule_i.h" #endif diff --git a/lib/silcutil/silcschedule_i.h b/lib/silcutil/silcschedule_i.h index 4abf530d..6853d253 100644 --- a/lib/silcutil/silcschedule_i.h +++ b/lib/silcutil/silcschedule_i.h @@ -104,11 +104,7 @@ typedef struct { /* Unregister signal */ void (*signal_unregister)(SilcSchedule schedule, void *context, - SilcUInt32 signal, SilcTaskCallback callback, - void *callback_context); - - /* Mark signal to be called later. */ - void (*signal_call)(SilcSchedule schedule, void *context, SilcUInt32 signal); + SilcUInt32 signal); /* Call all signals */ void (*signals_call)(SilcSchedule schedule, void *context); @@ -120,6 +116,16 @@ typedef struct { void (*signals_unblock)(SilcSchedule schedule, void *context); } SilcScheduleOps; +/* The generic function to add any type of task to the scheduler. This + used to be exported as is to application, but now they should use the + macro wrappers defined in silcschedule.h. For Fd task the timeout must + be zero, for timeout task the timeout must not be zero, for signal task + the fd argument is the signal. */ +SilcTask silc_schedule_task_add(SilcSchedule schedule, SilcUInt32 fd, + SilcTaskCallback callback, void *context, + long seconds, long useconds, + SilcTaskType type); + #if defined(SILC_DEBUG) /* Print scheduler statistics to stdout. */ void silc_schedule_stats(SilcSchedule schedule); diff --git a/lib/silcutil/unix/silcunixschedule.c b/lib/silcutil/unix/silcunixschedule.c index 67e8d1d3..ccf410e9 100644 --- a/lib/silcutil/unix/silcunixschedule.c +++ b/lib/silcutil/unix/silcunixschedule.c @@ -4,7 +4,7 @@ Author: Pekka Riikonen - Copyright (C) 1998 - 2005 Pekka Riikonen + Copyright (C) 1998 - 2006 Pekka Riikonen This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -26,15 +26,6 @@ const SilcScheduleOps schedule_ops; -#define SIGNAL_COUNT 32 - -typedef struct { - SilcUInt32 signal; - SilcTaskCallback callback; - void *context; - SilcBool call; -} SilcUnixSignal; - /* Internal context. */ typedef struct { #if defined(HAVE_POLL) && defined(HAVE_SETRLIMIT) && defined(RLIMIT_NOFILE) @@ -47,9 +38,18 @@ typedef struct { SilcTask wakeup_task; sigset_t signals; sigset_t signals_blocked; - SilcUnixSignal signal_call[SIGNAL_COUNT]; } *SilcUnixScheduler; +typedef struct { + SilcUInt32 signal; + SilcTaskCallback callback; + void *context; + SilcBool call; +} SilcUnixSignal; + +#define SIGNAL_COUNT 32 +SilcUnixSignal signal_call[SIGNAL_COUNT]; + #if defined(HAVE_POLL) && defined(HAVE_SETRLIMIT) && defined(RLIMIT_NOFILE) /* Calls normal poll() system call. */ @@ -261,6 +261,8 @@ void *silc_schedule_internal_init(SilcSchedule schedule, internal->app_context = app_context; + memset(signal_call, 0, sizeof(signal_call) / sizeof(signal_call[0])); + return (void *)internal; } @@ -306,9 +308,25 @@ void silc_schedule_internal_wakeup(SilcSchedule schedule, void *context) #endif } +/* Signal handler */ + +static void silc_schedule_internal_sighandler(int signal) +{ + int i; + + for (i = 0; i < SIGNAL_COUNT; i++) { + if (signal_call[i].signal == signal) { + signal_call[i].call = TRUE; + SILC_LOG_DEBUG(("Scheduling signal %d to be called", + signal_call[i].signal)); + break; + } + } +} + void silc_schedule_internal_signal_register(SilcSchedule schedule, void *context, - SilcUInt32 signal, + SilcUInt32 sig, SilcTaskCallback callback, void *callback_context) { @@ -323,24 +341,23 @@ void silc_schedule_internal_signal_register(SilcSchedule schedule, silc_schedule_internal_signals_block(schedule, context); 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; + if (!signal_call[i].signal) { + signal_call[i].signal = sig; + signal_call[i].callback = callback; + signal_call[i].context = callback_context; + signal_call[i].call = FALSE; + signal(sig, silc_schedule_internal_sighandler); break; } } silc_schedule_internal_signals_unblock(schedule, context); - sigaddset(&internal->signals, signal); + sigaddset(&internal->signals, sig); } void silc_schedule_internal_signal_unregister(SilcSchedule schedule, void *context, - SilcUInt32 signal, - SilcTaskCallback callback, - void *callback_context) + SilcUInt32 sig) { SilcUnixScheduler internal = (SilcUnixScheduler)context; int i; @@ -353,42 +370,17 @@ void silc_schedule_internal_signal_unregister(SilcSchedule schedule, silc_schedule_internal_signals_block(schedule, context); 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; - } - } - - silc_schedule_internal_signals_unblock(schedule, context); - sigdelset(&internal->signals, signal); -} - -/* Mark signal to be called later. */ - -void silc_schedule_internal_signal_call(SilcSchedule schedule, - void *context, SilcUInt32 signal) -{ - SilcUnixScheduler internal = (SilcUnixScheduler)context; - int i; - - if (!internal) - return; - - silc_schedule_internal_signals_block(schedule, context); - - for (i = 0; i < SIGNAL_COUNT; i++) { - if (internal->signal_call[i].signal == signal) { - internal->signal_call[i].call = TRUE; - SILC_LOG_DEBUG(("Scheduling signal %d to be called", - internal->signal_call[i].signal)); + if (signal_call[i].signal == sig) { + signal_call[i].signal = 0; + signal_call[i].callback = NULL; + signal_call[i].context = NULL; + signal_call[i].call = FALSE; + signal(sig, SIG_DFL); } } silc_schedule_internal_signals_unblock(schedule, context); + sigdelset(&internal->signals, sig); } /* Call all signals */ @@ -406,15 +398,15 @@ void silc_schedule_internal_signals_call(SilcSchedule schedule, void *context) silc_schedule_internal_signals_block(schedule, context); for (i = 0; i < SIGNAL_COUNT; i++) { - if (internal->signal_call[i].call && - internal->signal_call[i].callback) { + if (signal_call[i].call && + signal_call[i].callback) { SILC_LOG_DEBUG(("Calling signal %d callback", - internal->signal_call[i].signal)); - internal->signal_call[i].callback(schedule, internal->app_context, - SILC_TASK_INTERRUPT, - internal->signal_call[i].signal, - internal->signal_call[i].context); - internal->signal_call[i].call = FALSE; + signal_call[i].signal)); + signal_call[i].callback(schedule, internal->app_context, + SILC_TASK_INTERRUPT, + signal_call[i].signal, + signal_call[i].context); + signal_call[i].call = FALSE; } } @@ -458,7 +450,6 @@ const SilcScheduleOps schedule_ops = silc_schedule_internal_wakeup, silc_schedule_internal_signal_register, silc_schedule_internal_signal_unregister, - silc_schedule_internal_signal_call, silc_schedule_internal_signals_call, silc_schedule_internal_signals_block, silc_schedule_internal_signals_unblock, diff --git a/lib/silcutil/win32/silcwin32schedule.c b/lib/silcutil/win32/silcwin32schedule.c index 32d34508..f4a263fc 100644 --- a/lib/silcutil/win32/silcwin32schedule.c +++ b/lib/silcutil/win32/silcwin32schedule.c @@ -4,7 +4,7 @@ Author: Pekka Riikonen - Copyright (C) 2001 - 2005 Pekka Riikonen + Copyright (C) 2001 - 2006 Pekka Riikonen This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -290,17 +290,7 @@ void silc_schedule_internal_signal_register(SilcSchedule schedule, void silc_schedule_internal_signal_unregister(SilcSchedule schedule, void *context, - SilcUInt32 signal, - SilcTaskCallback callback, - void *callback_context) -{ - -} - -/* Mark signal to be called later. */ - -void silc_schedule_internal_signal_call(SilcSchedule schedule, - void *context, SilcUInt32 signal) + SilcUInt32 signal) { } @@ -338,7 +328,6 @@ const SilcScheduleOps schedule_ops = silc_schedule_internal_wakeup, silc_schedule_internal_signal_register, silc_schedule_internal_signal_unregister, - silc_schedule_internal_signal_call, silc_schedule_internal_signals_call, silc_schedule_internal_signals_block, silc_schedule_internal_signals_unblock, -- 2.24.0