structure memory optimizations.
[silc.git] / lib / silcutil / silcschedule.c
index 240ddeb28e3e208f8e56405e9edf1bd9d8932bdd..828e78748e639167b95b043064312d28656fb5c7 100644 (file)
@@ -45,11 +45,22 @@ void silc_schedule_internal_wakeup(void *context);
 
 /* Register signal */
 void silc_schedule_internal_signal_register(void *context,
-                                           SilcUInt32 signal);
+                                            SilcUInt32 signal,
+                                            SilcTaskCallback callback,
+                                            void *callback_context);
 
 /* Unregister signal */
 void silc_schedule_internal_signal_unregister(void *context,
-                                             SilcUInt32 signal);
+                                              SilcUInt32 signal,
+                                              SilcTaskCallback callback,
+                                              void *callback_context);
+
+/* Mark signal to be called later. */
+void silc_schedule_internal_signal_call(void *context, SilcUInt32 signal);
+
+/* Call all signals */
+void silc_schedule_internal_signals_call(void *context,
+                                        SilcSchedule schedule);
 
 /* Block registered signals in scheduler. */
 void silc_schedule_internal_signals_block(void *context);
@@ -98,12 +109,12 @@ do {                                                               \
 /* SILC Task object. Represents one task in the scheduler. */
 struct SilcTaskStruct {
   SilcUInt32 fd;
-  struct timeval timeout;
-  SilcTaskCallback callback;
-  void *context;
-  bool valid;
-  SilcTaskPriority priority;
-  SilcTaskType type;
+  SilcTaskCallback callback;      /* Task callback */
+  void *context;                  /* Task callback context */
+  struct timeval timeout;         /* Set for timeout tasks */
+  unsigned int valid : 1;         /* Set when task is valid */
+  unsigned int priority : 2;      /* Priority of the task */
+  unsigned int type : 5;           /* Type of the task */
 
   /* Pointers forming doubly linked circular list */
   struct SilcTaskStruct *next;
@@ -190,6 +201,11 @@ struct SilcTaskQueueStruct {
   
        Scheduler lock.
 
+   bool signal_tasks
+
+       TRUE when tasks has been registered from signals.  Next round in
+       scheduler will call the callbacks when this is TRUE.
+
 */
 struct SilcScheduleStruct {
   SilcTaskQueue fd_queue;
@@ -203,6 +219,7 @@ struct SilcScheduleStruct {
   void *internal;
   SILC_MUTEX_DEFINE(lock);
   bool is_locked;
+  bool signal_tasks;
 };
 
 /* Initializes the scheduler. This returns the scheduler context that
@@ -238,7 +255,6 @@ SilcSchedule silc_schedule_init(int max_tasks)
 
   /* Initialize the platform specific scheduler. */
   schedule->internal = silc_schedule_internal_init(schedule);
-  silc_schedule_signal_register(schedule, SIGALRM);
 
   return schedule;
 }
@@ -547,6 +563,14 @@ bool silc_schedule_one(SilcSchedule schedule, int timeout_usecs)
   if (!schedule->is_locked)
     SILC_SCHEDULE_LOCK(schedule);
 
+  /* Deliver signals if any has been set to be called */
+  if (schedule->signal_tasks) {
+    SILC_SCHEDULE_UNLOCK(schedule);
+    silc_schedule_internal_signals_call(schedule->internal, schedule);
+    schedule->signal_tasks = FALSE;
+    SILC_SCHEDULE_LOCK(schedule);
+  }
+
   /* If the task queues aren't initialized or we aren't valid anymore
      we will return */
   if ((!schedule->fd_queue && !schedule->timeout_queue 
@@ -874,16 +898,29 @@ void silc_schedule_unset_listen_fd(SilcSchedule schedule, SilcUInt32 fd)
 
 /* Register a new signal */
 
-void silc_schedule_signal_register(SilcSchedule schedule, SilcUInt32 signal)
+void silc_schedule_signal_register(SilcSchedule schedule, SilcUInt32 signal,
+                                  SilcTaskCallback callback, void *context)
 {
-  silc_schedule_internal_signal_register(schedule->internal, signal);
+  silc_schedule_internal_signal_register(schedule->internal, signal,
+                                        callback, context);
 }
 
 /* Unregister a new signal */
 
-void silc_schedule_signal_unregister(SilcSchedule schedule, SilcUInt32 signal)
+void silc_schedule_signal_unregister(SilcSchedule schedule, SilcUInt32 signal,
+                                    SilcTaskCallback callback, void *context)
+{
+  silc_schedule_internal_signal_unregister(schedule->internal, signal,
+                                          callback, context);
+}
+
+/* Call signal indicated by `signal'. */
+
+void silc_schedule_signal_call(SilcSchedule schedule, SilcUInt32 signal)
 {
-  silc_schedule_internal_signal_unregister(schedule->internal, signal);
+  /* Mark that signals needs to be delivered later. */
+  silc_schedule_internal_signal_call(schedule->internal, signal);
+  schedule->signal_tasks = TRUE;
 }
 
 /* Allocates a newtask task queue into the scheduler */