silc_stream_set_notifier and silc_schedule_set_listen_fd now
[silc.git] / lib / silcutil / silcschedule.c
index 2e546ee8576a6ee919bf97e9902268c3431a14d9..5d1760cc150320a26323647f83b4cc94a86fcf66 100644 (file)
@@ -4,7 +4,7 @@
 
   Author: Pekka Riikonen <priikone@silcnet.org>
 
-  Copyright (C) 1998 - 2006 Pekka Riikonen
+  Copyright (C) 1998 - 2007 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
@@ -595,23 +595,35 @@ SilcTask silc_schedule_task_add(SilcSchedule schedule, SilcUInt32 fd,
     task = (SilcTask)ttask;
 
   } else if (silc_likely(type == SILC_TASK_FD)) {
+    SilcTaskFd ftask;
+
     /* Check if fd is already added */
     if (silc_unlikely(silc_hash_table_find(schedule->fd_queue,
                                           SILC_32_TO_PTR(fd),
-                                          NULL, (void **)&task)))
-      goto out;
+                                          NULL, (void **)&task))) {
+      if (task->valid) {
+        task = NULL;
+        goto out;
+      }
+
+      /* Remove invalid task.  We must have unique fd key to hash table. */
+      silc_schedule_task_remove(schedule, task);
+    }
 
     /* Check max tasks */
     if (silc_unlikely(schedule->max_tasks > 0 &&
                      silc_hash_table_count(schedule->fd_queue) >=
                      schedule->max_tasks)) {
       SILC_LOG_WARNING(("Scheduler task limit reached: cannot add new task"));
+      task = NULL;
       goto out;
     }
 
-    SilcTaskFd ftask = silc_calloc(1, sizeof(*ftask));
-    if (silc_unlikely(!ftask))
+    ftask = silc_calloc(1, sizeof(*ftask));
+    if (silc_unlikely(!ftask)) {
+      task = NULL;
       goto out;
+    }
 
     SILC_LOG_DEBUG(("New fd task %p fd=%d", ftask, fd));
 
@@ -622,8 +634,18 @@ SilcTask silc_schedule_task_add(SilcSchedule schedule, SilcUInt32 fd,
     ftask->events = SILC_TASK_READ;
     ftask->fd = fd;
 
-    /* Add task */
-    silc_hash_table_add(schedule->fd_queue, SILC_32_TO_PTR(fd), ftask);
+    /* Add task and schedule it */
+    if (!silc_hash_table_add(schedule->fd_queue, SILC_32_TO_PTR(fd), ftask)) {
+      silc_free(ftask);
+      task = NULL;
+      goto out;
+    }
+    if (!schedule_ops.schedule_fd(schedule, schedule->internal, 
+                                 ftask, ftask->events)) {
+      silc_hash_table_del(schedule->fd_queue, SILC_32_TO_PTR(fd));
+      task = NULL;
+      goto out;
+    }
 
     task = (SilcTask)ftask;
 
@@ -685,8 +707,10 @@ void silc_schedule_task_del_by_fd(SilcSchedule schedule, SilcUInt32 fd)
   /* fd is unique, so there is only one task with this fd in the table */
   if (silc_likely(silc_hash_table_find(schedule->fd_queue,
                                       SILC_32_TO_PTR(fd), NULL,
-                                      (void **)&task)))
+                                      (void **)&task))) {
+    SILC_LOG_DEBUG(("Deleting task %p", task));
     task->valid = FALSE;
+  }
 
   SILC_SCHEDULE_UNLOCK(schedule);
 
@@ -789,20 +813,23 @@ void silc_schedule_task_del_by_all(SilcSchedule schedule, int fd,
    directly if wanted. This can be called multiple times for one file
    descriptor to set different iomasks. */
 
-void silc_schedule_set_listen_fd(SilcSchedule schedule, SilcUInt32 fd,
-                                SilcTaskEvent mask, SilcBool send_events)
+SilcBool silc_schedule_set_listen_fd(SilcSchedule schedule, SilcUInt32 fd,
+                                    SilcTaskEvent mask, SilcBool send_events)
 {
   SilcTaskFd task;
 
   if (silc_unlikely(!schedule->valid))
-    return;
+    return FALSE;
 
   SILC_SCHEDULE_LOCK(schedule);
 
   if (silc_hash_table_find(schedule->fd_queue, SILC_32_TO_PTR(fd),
                           NULL, (void **)&task)) {
+    if (!schedule_ops.schedule_fd(schedule, schedule->internal, task, mask)) {
+      SILC_SCHEDULE_UNLOCK(schedule);
+      return FALSE;
+    }
     task->events = mask;
-    schedule_ops.schedule_fd(schedule, schedule->internal, task, mask);
     if (silc_unlikely(send_events) && mask) {
       task->revents = mask;
       silc_schedule_dispatch_fd(schedule);
@@ -810,9 +837,11 @@ void silc_schedule_set_listen_fd(SilcSchedule schedule, SilcUInt32 fd,
   }
 
   SILC_SCHEDULE_UNLOCK(schedule);
+
+  return TRUE;
 }
 
-/* Returns the file descriptors current requested event mask. */
+/* Returns the file descriptor's current requested event mask. */
 
 SilcTaskEvent silc_schedule_get_fd_events(SilcSchedule schedule,
                                          SilcUInt32 fd)