+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
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.
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)
#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;
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
/* 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)
+{
+
+}
/* 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. */
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 {
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)
SilcUInt32 last_fd;
struct timeval *timeout;
bool valid;
- void *wakeup;
+ void *internal;
SILC_MUTEX_DEFINE(lock);
bool is_locked;
};
/* 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;
}
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);
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
#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
}
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)
***/
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
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);
+}
#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;
#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;
/* 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;
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)
+{
+
+}