From: Pekka Riikonen Date: Wed, 6 Jun 2007 14:32:17 +0000 (+0000) Subject: Added silc_schedule_set_notify. Notification callback is called X-Git-Tag: silc.toolkit.1.1.1~42 X-Git-Url: http://git.silcnet.org/gitweb/?p=silc.git;a=commitdiff_plain;h=619b07dee2e25aeb8834f1a3a9588d44b0a21b71 Added silc_schedule_set_notify. Notification callback is called whenever task is added to or deleted from scheduler. --- diff --git a/lib/configure.ad b/lib/configure.ad index e79611b4..5c8701be 100644 --- a/lib/configure.ad +++ b/lib/configure.ad @@ -83,9 +83,9 @@ SILC_LIB_INCLUDES="$SILC_LIB_INCLUDES -I$SILC_TOP_SRCDIR/lib/silcvcard" LIB_BASE_VERSION=1.1 # libsilc versions -LIBSILC_CURRENT=1 # prev = 1 -LIBSILC_REVISION=1 # prev = 0 -LIBSILC_AGE=0 # prev = 0 +LIBSILC_CURRENT=2 # prev = 1 +LIBSILC_REVISION=0 # prev = 0 +LIBSILC_AGE=1 # prev = 0 # libsilcclient versions LIBSILCCLIENT_CURRENT=1 # prev = 1 diff --git a/lib/silcutil/silcschedule.c b/lib/silcutil/silcschedule.c index 6d3f09e1..53cb0aa7 100644 --- a/lib/silcutil/silcschedule.c +++ b/lib/silcutil/silcschedule.c @@ -473,6 +473,11 @@ static SilcBool silc_schedule_iterate(SilcSchedule schedule, int timeout_usecs) /* There is some data available now */ SILC_LOG_DEBUG(("Running fd tasks")); silc_schedule_dispatch_fd(schedule); + + /* If timeout was very short, dispatch also timeout tasks */ + if (schedule->has_timeout && schedule->timeout.tv_sec == 0 && + schedule->timeout.tv_usec < 50000) + silc_schedule_dispatch_timeout(schedule, FALSE); continue; } else { @@ -543,6 +548,15 @@ void *silc_schedule_get_context(SilcSchedule schedule) return schedule->app_context; } +/* Set notify callback */ + +void silc_schedule_set_notify(SilcSchedule schedule, + SilcTaskNotifyCb notify, void *context) +{ + schedule->notify = notify; + schedule->notify_context = context; +} + /* Add new task to the scheduler */ SilcTask silc_schedule_task_add(SilcSchedule schedule, SilcUInt32 fd, @@ -607,6 +621,11 @@ SilcTask silc_schedule_task_add(SilcSchedule schedule, SilcUInt32 fd, task = (SilcTask)ttask; + /* Call notify callback */ + if (schedule->notify) + schedule->notify(schedule, TRUE, task, FALSE, 0, 0, seconds, useconds, + schedule->notify_context); + } else if (silc_likely(type == SILC_TASK_FD)) { SilcTaskFd ftask; @@ -660,6 +679,11 @@ SilcTask silc_schedule_task_add(SilcSchedule schedule, SilcUInt32 fd, task = (SilcTask)ftask; + /* Call notify callback */ + if (schedule->notify) + schedule->notify(schedule, TRUE, task, TRUE, ftask->fd, + SILC_TASK_READ, 0, 0, schedule->notify_context); + } else if (silc_unlikely(type == SILC_TASK_SIGNAL)) { SILC_SCHEDULE_UNLOCK(schedule); schedule_ops.signal_register(schedule, schedule->internal, fd, @@ -694,16 +718,28 @@ SilcBool silc_schedule_task_del(SilcSchedule schedule, SilcTask task) /* Delete from fd queue */ silc_hash_table_list(schedule->fd_queue, &htl); - while (silc_hash_table_get(&htl, NULL, (void *)&task)) + while (silc_hash_table_get(&htl, NULL, (void *)&task)) { task->valid = FALSE; + + /* Call notify callback */ + if (schedule->notify) + schedule->notify(schedule, FALSE, task, TRUE, + ((SilcTaskFd)task)->fd, 0, 0, 0, + schedule->notify_context); + } silc_hash_table_list_reset(&htl); /* Delete from timeout queue */ silc_list_start(schedule->timeout_queue); - while ((task = (SilcTask)silc_list_get(schedule->timeout_queue)) - != SILC_LIST_END) + while ((task = (SilcTask)silc_list_get(schedule->timeout_queue))) { task->valid = FALSE; + /* Call notify callback */ + if (schedule->notify) + schedule->notify(schedule, FALSE, task, FALSE, 0, 0, 0, 0, + schedule->notify_context); + } + SILC_SCHEDULE_UNLOCK(schedule); return TRUE; } @@ -711,6 +747,11 @@ SilcBool silc_schedule_task_del(SilcSchedule schedule, SilcTask task) SILC_LOG_DEBUG(("Unregistering task %p", task)); SILC_SCHEDULE_LOCK(schedule); task->valid = FALSE; + + /* Call notify callback */ + if (schedule->notify) + schedule->notify(schedule, FALSE, task, !task->type, 0, 0, 0, 0, + schedule->notify_context); SILC_SCHEDULE_UNLOCK(schedule); return TRUE; @@ -733,6 +774,11 @@ SilcBool silc_schedule_task_del_by_fd(SilcSchedule schedule, SilcUInt32 fd) (void *)&task))) { SILC_LOG_DEBUG(("Deleting task %p", task)); task->valid = FALSE; + + /* Call notify callback */ + if (schedule->notify) + schedule->notify(schedule, FALSE, task, TRUE, fd, 0, 0, 0, + schedule->notify_context); ret = TRUE; } @@ -766,6 +812,12 @@ SilcBool silc_schedule_task_del_by_callback(SilcSchedule schedule, while (silc_hash_table_get(&htl, NULL, (void *)&task)) { if (task->callback == callback) { task->valid = FALSE; + + /* Call notify callback */ + if (schedule->notify) + schedule->notify(schedule, FALSE, task, TRUE, + ((SilcTaskFd)task)->fd, 0, 0, 0, + schedule->notify_context); ret = TRUE; } } @@ -777,6 +829,11 @@ SilcBool silc_schedule_task_del_by_callback(SilcSchedule schedule, while ((task = (SilcTask)silc_list_get(list))) { if (task->callback == callback) { task->valid = FALSE; + + /* Call notify callback */ + if (schedule->notify) + schedule->notify(schedule, FALSE, task, FALSE, 0, 0, 0, 0, + schedule->notify_context); ret = TRUE; } } @@ -805,6 +862,12 @@ SilcBool silc_schedule_task_del_by_context(SilcSchedule schedule, while (silc_hash_table_get(&htl, NULL, (void *)&task)) { if (task->context == context) { task->valid = FALSE; + + /* Call notify callback */ + if (schedule->notify) + schedule->notify(schedule, FALSE, task, TRUE, + ((SilcTaskFd)task)->fd, 0, 0, 0, + schedule->notify_context); ret = TRUE; } } @@ -815,8 +878,13 @@ SilcBool silc_schedule_task_del_by_context(SilcSchedule schedule, silc_list_start(list); while ((task = (SilcTask)silc_list_get(list))) { if (task->context == context) { - ret = TRUE; task->valid = FALSE; + + /* Call notify callback */ + if (schedule->notify) + schedule->notify(schedule, FALSE, task, FALSE, 0, 0, 0, 0, + schedule->notify_context); + ret = TRUE; } } @@ -849,6 +917,11 @@ SilcBool silc_schedule_task_del_by_all(SilcSchedule schedule, int fd, while ((task = (SilcTask)silc_list_get(list))) { if (task->callback == callback && task->context == context) { task->valid = FALSE; + + /* Call notify callback */ + if (schedule->notify) + schedule->notify(schedule, FALSE, task, FALSE, 0, 0, 0, 0, + schedule->notify_context); ret = TRUE; } } @@ -883,6 +956,12 @@ SilcBool silc_schedule_set_listen_fd(SilcSchedule schedule, SilcUInt32 fd, task->revents = mask; silc_schedule_dispatch_fd(schedule); } + + /* Call notify callback */ + if (schedule->notify) + schedule->notify(schedule, TRUE, (SilcTask)task, + TRUE, task->fd, mask, 0, 0, + schedule->notify_context); } SILC_SCHEDULE_UNLOCK(schedule); diff --git a/lib/silcutil/silcschedule.h b/lib/silcutil/silcschedule.h index e92bb830..8c2154a5 100644 --- a/lib/silcutil/silcschedule.h +++ b/lib/silcutil/silcschedule.h @@ -158,6 +158,49 @@ typedef void (*SilcTaskCallback)(SilcSchedule schedule, void *app_context, SilcTaskEvent type, SilcUInt32 fd, void *context); +/****f* silcutil/SilcScheduleAPI/SilcTaskNotifyCb + * + * SYNOPSIS + * + * typedef void (*SilcTaskNotifyCb)(SilcSchedule schedule, + * SilcBool added, SilcTask task, + * SilcBool fd_task, SilcUInt32 fd, + * SilcTaskEvent event, + * long seconds, long useconds, + * void *context); + * + * DESCRIPTION + * + * Task notify callback. Callback of this type can be set to scheduler + * by calling silc_schedule_set_notify and will be called whenever new + * task is added or old task is removed. If `added' is TRUE then `task' + * is added to scheduler. If `added' is FALSE then `task' will be removed + * from the scheduler. If `fd_task' is TRUE the `task' is file descriptor + * task and has `fd' is its file descriptor. If `fd_task' is FALSE then + * the task is timeout task and `seconds' and `useconds' specify the + * timeout. The `context' is the context given to silc_schedule_set_notify. + * + * NOTES + * + * The `schedule' is locked while this callback is called. This means that + * new tasks cannot be added or removed inside this callback. + * + * When timeout task expires this callback is not called. This is called + * only when task is explicitly deleted from the scheduler. Note that, + * when timeout task expires it is removed from the scheduler and `task' + * will become invalid. + * + * If fd task changes its events, this will be called as if it was a new + * task with different `event' mask. + * + ***/ +typedef void (*SilcTaskNotifyCb)(SilcSchedule schedule, + SilcBool added, SilcTask task, + SilcBool fd_task, SilcUInt32 fd, + SilcTaskEvent event, + long seconds, long useconds, + void *app_context); + /* Macros */ /****d* silcutil/SilcScheduleAPI/SILC_ALL_TASKS @@ -184,8 +227,8 @@ typedef void (*SilcTaskCallback)(SilcSchedule schedule, void *app_context, * * DESCRIPTION * - * Generic macro to define task callback functions. This defines a - * static function with name `func' as a task callback function. + * Generic macro to declare task callback functions. This defines a + * function with name `func' as a task callback function. * * SOURCE */ @@ -335,6 +378,22 @@ void silc_schedule_wakeup(SilcSchedule schedule); ***/ void *silc_schedule_get_context(SilcSchedule schedule); +/****f* silcutil/SilcScheduleAPI/silc_schedule_set_notify + * + * SYNOPSIS + * + * void silc_schedule_set_notify(SilcSchedule schedule, + * SilcTaskNotifyCb notify, void *context); + * + * DESCRIPTION + * + * Set notify callback to scheduler. The `notify' will be called whenever + * task is added to or deleted from scheduler. + * + ***/ +void silc_schedule_set_notify(SilcSchedule schedule, + SilcTaskNotifyCb notify, void *context); + /****f* silcutil/SilcScheduleAPI/silc_schedule_task_add_fd * * SYNOPSIS @@ -374,7 +433,7 @@ void *silc_schedule_get_context(SilcSchedule schedule); * 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. The task added with zero (0) + * to the `callback' is SILC_TASK_EXPIRE. A task added with zero (0) * timeout will be executed immediately next time tasks are scheduled. * ***/ diff --git a/lib/silcutil/silcschedule_i.h b/lib/silcutil/silcschedule_i.h index 3282990f..61ea4812 100644 --- a/lib/silcutil/silcschedule_i.h +++ b/lib/silcutil/silcschedule_i.h @@ -74,6 +74,8 @@ typedef struct SilcTaskFdStruct { struct SilcScheduleStruct { void *internal; void *app_context; /* Application specific context */ + SilcTaskNotifyCb notify; /* Notify callback */ + void *notify_context; /* Notify context */ SilcHashTable fd_queue; /* FD task queue */ SilcList fd_dispatch; /* Dispatched FDs */ SilcList timeout_queue; /* Timeout queue */ @@ -106,7 +108,8 @@ typedef struct { 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. Returns context to the platform specific scheduler. - If this returns NULL the scheduler initialization will fail. */ + If this returns NULL the scheduler initialization will fail. Do not + add FD tasks inside function. Timeout tasks can be added. */ void *(*init)(SilcSchedule schedule, void *app_context); /* Uninitializes the platform specific scheduler context. */ diff --git a/lib/silcutil/tests/test_silcschedule.c b/lib/silcutil/tests/test_silcschedule.c index 5a6824cc..204f632f 100644 --- a/lib/silcutil/tests/test_silcschedule.c +++ b/lib/silcutil/tests/test_silcschedule.c @@ -13,6 +13,15 @@ typedef void (*Callback)(void *context); SilcSchedule schedule; +void notify_cb(SilcSchedule schedule, SilcBool added, SilcTask task, + SilcBool fd_task, SilcUInt32 fd, long sec, long usec, + void *context) +{ + SILC_LOG_DEBUG(("Notify cb, %s %s task, fd %d, sec %d usec %d", + added ? "added" : "deleted", fd_task ? "fd" :"timeout", + fd, sec, usec)); +} + SILC_TASK_CALLBACK(foo) { @@ -92,6 +101,7 @@ int main(int argc, char **argv) schedule = silc_schedule_init(NUM_FTASK, NULL); if (!schedule) goto err; + silc_schedule_set_notify(schedule, notify_cb, NULL); silc_schedule_task_add_signal(schedule, SIGINT, interrupt, NULL); diff --git a/lib/silcutil/unix/silcunixschedule.c b/lib/silcutil/unix/silcunixschedule.c index d117f522..e661ca64 100644 --- a/lib/silcutil/unix/silcunixschedule.c +++ b/lib/silcutil/unix/silcunixschedule.c @@ -319,6 +319,23 @@ SILC_TASK_CALLBACK(silc_schedule_wakeup_cb) (void)read(internal->wakeup_pipe[0], &c, 1); } +SILC_TASK_CALLBACK(silc_schedule_wakeup_init) +{ + SilcUnixScheduler internal = schedule->internal; + + internal->wakeup_task = + silc_schedule_task_add(schedule, internal->wakeup_pipe[0], + silc_schedule_wakeup_cb, internal, + 0, 0, SILC_TASK_FD); + if (!internal->wakeup_task) { + SILC_LOG_WARNING(("Could not add a wakeup task, threads won't work")); + close(internal->wakeup_pipe[0]); + return; + } + silc_schedule_internal_schedule_fd(schedule, internal, + (SilcTaskFd)internal->wakeup_task, + SILC_TASK_READ); +} #endif /* SILC_THREADS */ /* Initializes the platform specific scheduler. This for example initializes @@ -376,20 +393,8 @@ void *silc_schedule_internal_init(SilcSchedule schedule, return NULL; } - internal->wakeup_task = - silc_schedule_task_add(schedule, internal->wakeup_pipe[0], - silc_schedule_wakeup_cb, internal, - 0, 0, SILC_TASK_FD); - if (!internal->wakeup_task) { - SILC_LOG_ERROR(("Could not add a wakeup task, threads won't work")); - close(internal->wakeup_pipe[0]); - close(internal->wakeup_pipe[1]); - silc_free(internal); - return NULL; - } - silc_schedule_internal_schedule_fd(schedule, internal, - (SilcTaskFd)internal->wakeup_task, - SILC_TASK_READ); + silc_schedule_task_add_timeout(schedule, silc_schedule_wakeup_init, + internal, 0, 0); #endif /* SILC_THREADS */ internal->app_context = app_context;