Added silc_schedule_set_notify. Notification callback is called
authorPekka Riikonen <priikone@silcnet.org>
Wed, 6 Jun 2007 14:32:17 +0000 (14:32 +0000)
committerPekka Riikonen <priikone@silcnet.org>
Wed, 6 Jun 2007 14:32:17 +0000 (14:32 +0000)
whenever task is added to or deleted from scheduler.

lib/configure.ad
lib/silcutil/silcschedule.c
lib/silcutil/silcschedule.h
lib/silcutil/silcschedule_i.h
lib/silcutil/tests/test_silcschedule.c
lib/silcutil/unix/silcunixschedule.c

index e79611b4c08e40d7633353d184ef4ccf88578dfa..5c8701be279b95673fb9b3a9c3d8db30df886072 100644 (file)
@@ -83,9 +83,9 @@ SILC_LIB_INCLUDES="$SILC_LIB_INCLUDES -I$SILC_TOP_SRCDIR/lib/silcvcard"
 LIB_BASE_VERSION=1.1
 
 # libsilc versions
 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
 
 # libsilcclient versions
 LIBSILCCLIENT_CURRENT=1                # prev = 1
index 6d3f09e1c3d3794f4776ea5211a4115c1492494c..53cb0aa7426f22eb883c7fc5ee73fc427a9db48f 100644 (file)
@@ -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);
       /* 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 {
       continue;
 
     } else {
@@ -543,6 +548,15 @@ void *silc_schedule_get_context(SilcSchedule schedule)
   return schedule->app_context;
 }
 
   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,
 /* 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;
 
 
     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;
 
   } 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;
 
 
     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,
   } 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);
 
     /* 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;
       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);
     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;
 
       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;
   }
     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;
   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;
   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;
                                       (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;
   }
 
     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;
   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;
     }
   }
       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;
   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;
     }
   }
       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;
   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;
     }
   }
       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) {
   silc_list_start(list);
   while ((task = (SilcTask)silc_list_get(list))) {
     if (task->context == context) {
-      ret = TRUE;
       task->valid = FALSE;
       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;
   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;
     }
   }
       ret = TRUE;
     }
   }
@@ -883,6 +956,12 @@ SilcBool silc_schedule_set_listen_fd(SilcSchedule schedule, SilcUInt32 fd,
       task->revents = mask;
       silc_schedule_dispatch_fd(schedule);
     }
       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);
   }
 
   SILC_SCHEDULE_UNLOCK(schedule);
index e92bb830e45e989ad4e234c7d63227ff2f79206a..8c2154a5619e405f63df48f7dc8152307922124e 100644 (file)
@@ -158,6 +158,49 @@ typedef void (*SilcTaskCallback)(SilcSchedule schedule, void *app_context,
                                 SilcTaskEvent type, SilcUInt32 fd,
                                 void *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
 /* Macros */
 
 /****d* silcutil/SilcScheduleAPI/SILC_ALL_TASKS
@@ -184,8 +227,8 @@ typedef void (*SilcTaskCallback)(SilcSchedule schedule, void *app_context,
  *
  * DESCRIPTION
  *
  *
  * 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
  */
  *
  * SOURCE
  */
@@ -335,6 +378,22 @@ void silc_schedule_wakeup(SilcSchedule schedule);
  ***/
 void *silc_schedule_get_context(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
 /****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
  *    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.
  *
  ***/
  *    timeout will be executed immediately next time tasks are scheduled.
  *
  ***/
index 3282990fdfd7de6ead8833362cca2e3e05f4fe35..61ea48125a0d96d374db7f2730fd8d95cd6a2adc 100644 (file)
@@ -74,6 +74,8 @@ typedef struct SilcTaskFdStruct {
 struct SilcScheduleStruct {
   void *internal;
   void *app_context;              /* Application specific context */
 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 */
   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.
      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. */
   void *(*init)(SilcSchedule schedule, void *app_context);
 
   /* Uninitializes the platform specific scheduler context. */
index 5a6824ccac31003556908d9e877b9bc03110ea2d..204f632fede304c8f21b84d09621f418399ff2fc 100644 (file)
@@ -13,6 +13,15 @@ typedef void (*Callback)(void *context);
 
 SilcSchedule schedule;
 
 
 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)
 {
 
 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;
   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);
 
 
   silc_schedule_task_add_signal(schedule, SIGINT, interrupt, NULL);
 
index d117f522346b858ecbc64aa025230772c776e1ca..e661ca6461da95a589cdf25cf4bee93a22c50a85 100644 (file)
@@ -319,6 +319,23 @@ SILC_TASK_CALLBACK(silc_schedule_wakeup_cb)
   (void)read(internal->wakeup_pipe[0], &c, 1);
 }
 
   (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
 #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;
   }
 
     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;
 #endif /* SILC_THREADS */
 
   internal->app_context = app_context;