updates.
authorPekka Riikonen <priikone@silcnet.org>
Sun, 8 Jul 2001 18:14:41 +0000 (18:14 +0000)
committerPekka Riikonen <priikone@silcnet.org>
Sun, 8 Jul 2001 18:14:41 +0000 (18:14 +0000)
CHANGES
TODO
configure.in.pre
lib/silcutil/silcmutex.h
lib/silcutil/silcschedule.c
lib/silcutil/silctask.c
lib/silcutil/silctask.h
lib/silcutil/unix/silcunixmutex.c
lib/silcutil/win32/silcwin32mutex.c

diff --git a/CHANGES b/CHANGES
index 012d0b51a102cddd15a8e757df3c9e4aacd6b8c4..713f6333efe30a2cf1cc63eb8b4d7ab5fe15c229 100644 (file)
--- a/CHANGES
+++ b/CHANGES
@@ -1,3 +1,19 @@
+Sun Jul  8 18:44:53 EEST 2001  Pekka Riikonen <priikone@silcnet.org>
+
+       * Added SILC_MUTEX_DEFINE to define the mutex on environments
+         that may or may not compile the mutex support in.
+       
+         Changed the silc_mutex_alloc interface. It allocates the
+         mutex now to the sent pointer and returns TRUE or FALSE.
+
+         Affected file lib/silcutil/silcmutex.h.
+
+       * Wrote the SILC Task Queue interface to support multi-threads.
+         Affected file lib/silcutil/silctask.[ch].
+
+       * Wrote the SILC Scheduler to support multi-threads.  Affected
+         file lib/silcutil/silcschedule.c.
+
 Sun Jul  8 11:16:01 EEST 2001  Pekka Riikonen <priikone@silcnet.org>
 
        * Implemented the SILC Mutex API and SILC Thread API for WIN32
diff --git a/TODO b/TODO
index b5a01159025e574f3f6bf5b64456dfd1bd49037b..bcdeaa2e64101287970343f11709117fe51fc910 100644 (file)
--- a/TODO
+++ b/TODO
@@ -91,8 +91,6 @@ TODO/bugs In SILC Server
 TODO/bugs In SILC Libraries
 ===========================
 
- o Complete the SILC Mutex API and SILC Thread API.
-
  o Incomplete IPv6 support:
 
        o All network routines in lib/silcutil/silcnet.[ch] does not
index 23e6da76e54640f1b99a19930513ebd0641c4033..9999270a50e55ec5f0eee1de28375e3d5ecafe31 100644 (file)
@@ -563,16 +563,15 @@ AC_ARG_ENABLE(threads,
 [ case "${enableval}" in
   yes)
     AC_DEFINE(SILC_THREADS)
-    AM_CONDITIONAL(SILC_THREADS)
     want_threads=true
     ;;
   *)
     want_threads=false
     ;;
 esac ], AC_DEFINE(SILC_THREADS)
-        AM_CONDITIONAL(SILC_THREADS)
-        want_threads=true)
+       want_threads=true)
 
+AM_CONDITIONAL(SILC_THREADS, test x$want_threads = xtrue)
 if test x$want_threads = xtrue; then
   AC_TRY_COMPILE([#include <pthread.h>],
                 [pthread_attr_t attr; pthread_attr_init(&attr);],
index ef02621ee07d19bb3346a9466edceb3ab2facfce..9e8267facf744c81ad49a18da95d73f5ca471bad 100644 (file)
@@ -69,15 +69,17 @@ typedef struct SilcMutexStruct *SilcMutex;
  *
  * SYNOPSIS
  *
- *    SilcMutex silc_mutex_alloc(void);
+ *    bool silc_mutex_alloc(SilcMutex *mutex);
  *
  * DESCRIPTION
  *
  *    Allocates SILC Mutex object.  The mutex object must be allocated
  *    before it can be used.  It is freed by the silc_mutex_free function.
+ *    This returns TRUE and allocated mutex in to the `mutex' and FALSE
+ *    on error.
  *
  ***/
-SilcMutex silc_mutex_alloc(void);
+bool silc_mutex_alloc(SilcMutex *mutex);
 
 /****f* silcutil/SilcMutexAPI/silc_mutex_free
  *
@@ -136,10 +138,10 @@ void silc_mutex_unlock(SilcMutex mutex);
 #else
 
 #define SILC_MUTEX_DEFINE(name)
-#define silc_mutex_alloc()
-#define silc_mutex_free(mutex)
-#define silc_mutex_lock(mutex)
-#define silc_mutex_unlock(mutex)
+#define silc_mutex_alloc(mutex) (void)0
+#define silc_mutex_free(mutex) (void)0
+#define silc_mutex_lock(mutex) (void)0
+#define silc_mutex_unlock(mutex) (void)0
 
 #endif         /* SILC_THREADS */
 
index b7e99ed406dd8fa081e62668e33b5cac4d7c2037..036b0bda1e5961d0e454f275ee94a1bcdb678847 100644 (file)
@@ -18,6 +18,7 @@
 
 */
 /* $Id$ */
+/* XXX on multi-threads the task queue locking is missing here. */
 
 #include "silcincludes.h"
 
@@ -108,6 +109,7 @@ struct SilcScheduleStruct {
   fd_set in;
   fd_set out;
   int max_fd;
+  SILC_MUTEX_DEFINE(lock);
 };
 
 /* Initializes the scheduler. Sets the non-timeout task queue hook and
@@ -154,6 +156,7 @@ SilcSchedule silc_schedule_init(SilcTaskQueue *fd_queue,
   schedule->max_fd = -1;
   for (i = 0; i < max_fd; i++)
     schedule->fd_list.fd[i] = -1;
+  silc_mutex_alloc(&schedule->lock);
 
   return schedule;
 }
@@ -193,6 +196,8 @@ bool silc_schedule_uninit(SilcSchedule schedule)
     silc_free(schedule->fd_list.fd);
   }
 
+  silc_mutex_free(schedule->lock);
+
   return TRUE;
 }
 
@@ -203,9 +208,7 @@ bool silc_schedule_uninit(SilcSchedule schedule)
 void silc_schedule_stop(SilcSchedule schedule)
 {
   SILC_LOG_DEBUG(("Stopping scheduler"));
-
-  if (schedule->valid == TRUE)
-    schedule->valid = FALSE;
+  schedule->valid = FALSE;
 }
 
 /* Sets a file descriptor to be listened by select() in scheduler. One can
@@ -214,16 +217,22 @@ void silc_schedule_stop(SilcSchedule schedule)
 
 void silc_schedule_set_listen_fd(SilcSchedule schedule, int fd, uint32 iomask)
 {
+  silc_mutex_lock(schedule->lock);
+
   schedule->fd_list.fd[fd] = iomask;
   
   if (fd > schedule->fd_list.last_fd)
     schedule->fd_list.last_fd = fd;
+
+  silc_mutex_unlock(schedule->lock);
 }
 
 /* Removes a file descriptor from listen list. */
 
 void silc_schedule_unset_listen_fd(SilcSchedule schedule, int fd)
 {
+  silc_mutex_lock(schedule->lock);
+
   schedule->fd_list.fd[fd] = -1;
   
   if (fd == schedule->fd_list.last_fd) {
@@ -235,6 +244,8 @@ void silc_schedule_unset_listen_fd(SilcSchedule schedule, int fd)
 
     schedule->fd_list.last_fd = i < 0 ? 0 : i;
   }
+
+  silc_mutex_unlock(schedule->lock);
 }
 
 /* Executes tasks matching the file descriptor set by select(). The task
@@ -303,8 +314,8 @@ do {                                                                           \
 
 #define SILC_SCHEDULE_SELECT_TASKS                             \
 do {                                                           \
-  for (i = 0; i <= schedule->fd_list.last_fd; i++) {           \
-    if (schedule->fd_list.fd[i] != -1) {                               \
+  for (i = 0; i <= schedule->fd_list.last_fd; i++) {           \
+    if (schedule->fd_list.fd[i] != -1) {                       \
                                                                \
       /* Set the max fd value for select() to listen */                \
       if (i > schedule->max_fd)                                        \
@@ -318,7 +329,7 @@ do {                                                                \
       if ((schedule->fd_list.fd[i] & (1L << SILC_TASK_WRITE))) \
        FD_SET(i, &schedule->out);                              \
     }                                                          \
-  }                                                             \
+  }                                                            \
 } while(0)
 
 /* Executes all tasks whose timeout has expired. The task is removed from
@@ -385,7 +396,7 @@ do {                                                                        \
 
 #define SILC_SCHEDULE_SELECT_TIMEOUT                                       \
 do {                                                                       \
-  if (schedule->timeout_queue && schedule->timeout_queue->valid == TRUE) {    \
+  if (schedule->timeout_queue && schedule->timeout_queue->valid == TRUE) {  \
     queue = schedule->timeout_queue;                                       \
     task = NULL;                                                           \
                                                                            \
@@ -416,13 +427,13 @@ do {                                                                          \
           queue->timeout.tv_sec = task->timeout.tv_sec - curtime.tv_sec;    \
           queue->timeout.tv_usec = task->timeout.tv_usec - curtime.tv_usec; \
          if (queue->timeout.tv_sec < 0)                                    \
-            queue->timeout.tv_sec = 0;                                             \
+            queue->timeout.tv_sec = 0;                                     \
                                                                            \
           /* We wouldn't want to go under zero, check for it. */           \
           if (queue->timeout.tv_usec < 0) {                                \
             queue->timeout.tv_sec -= 1;                                            \
            if (queue->timeout.tv_sec < 0)                                  \
-              queue->timeout.tv_sec = 0;                                   \
+              queue->timeout.tv_sec = 0;                                   \
             queue->timeout.tv_usec += 1000000L;                                    \
           }                                                                \
         }                                                                  \
@@ -451,15 +462,16 @@ do {                                                                          \
 do {                                                                        \
   if (is_run == FALSE) {                                                    \
     SILC_LOG_DEBUG(("Running generic tasks"));                              \
+    silc_mutex_lock(schedule->lock);                                        \
     for (i = 0; i <= schedule->fd_list.last_fd; i++)                        \
       if (schedule->fd_list.fd[i] != -1) {                                  \
                                                                             \
        /* Check whether this fd is select()ed. */                           \
-       if ((FD_ISSET(i, &schedule->in)) || (FD_ISSET(i, &schedule->out))) {   \
+       if ((FD_ISSET(i, &schedule->in)) || (FD_ISSET(i, &schedule->out))) { \
                                                                             \
          /* It was selected. Now find the tasks from task queue and execute \
             all generic tasks. */                                           \
-         if (schedule->generic_queue && schedule->generic_queue->valid) {     \
+         if (schedule->generic_queue && schedule->generic_queue->valid) {   \
            queue = schedule->generic_queue;                                 \
                                                                             \
            if (!queue->task)                                                \
@@ -474,16 +486,22 @@ do {                                                                           \
                                                                             \
              if (task->valid && schedule->fd_list.fd[i] != -1) {            \
                /* Task ready for reading */                                 \
-               if ((schedule->fd_list.fd[i] & (1L << SILC_TASK_READ)))      \
+               if ((schedule->fd_list.fd[i] & (1L << SILC_TASK_READ))) {    \
+                  silc_mutex_unlock(schedule->lock);                        \
                  task->callback(queue, SILC_TASK_READ,                      \
                                 task->context, i);                          \
+                  silc_mutex_lock(schedule->lock);                          \
+               }                                                            \
              }                                                              \
                                                                             \
              if (task->valid && schedule->fd_list.fd[i] != -1) {            \
                /* Task ready for writing */                                 \
-               if ((schedule->fd_list.fd[i] & (1L << SILC_TASK_WRITE)))             \
+               if ((schedule->fd_list.fd[i] & (1L << SILC_TASK_WRITE))) {   \
+                  silc_mutex_unlock(schedule->lock);                        \
                  task->callback(queue, SILC_TASK_WRITE,                     \
                                 task->context, i);                          \
+                  silc_mutex_lock(schedule->lock);                          \
+               }                                                            \
              }                                                              \
                                                                             \
              if (!task->valid) {                                            \
@@ -508,6 +526,7 @@ do {                                                                             \
          }                                                                  \
        }                                                                    \
       }                                                                             \
+    silc_mutex_unlock(schedule->lock);                                      \
   }                                                                         \
 } while(0)
 
@@ -539,10 +558,14 @@ bool silc_schedule_one(SilcSchedule schedule, int timeout_usecs)
      when at earliest some of the timeout tasks expire. */
   SILC_SCHEDULE_SELECT_TIMEOUT;
 
+  silc_mutex_lock(schedule->lock);
+
   /* Add the file descriptors to the fd sets. These are the non-timeout
      tasks. The select() listens to these file descriptors. */
   SILC_SCHEDULE_SELECT_TASKS;
 
+  silc_mutex_unlock(schedule->lock);
+
   if (schedule->max_fd == -1 && !schedule->timeout)
     return FALSE;
 
index 5a1c6a3eb699319f2b09a9c6a20db22d614bb576..738edae84d2febd2d71c741a38aba7cb285e658b 100644 (file)
@@ -35,12 +35,17 @@ void silc_task_queue_alloc(SilcSchedule schedule, SilcTaskQueue *new,
   /* Set the pointers */
   (*new)->schedule = schedule;
   (*new)->valid = valid;
+  silc_mutex_alloc(&(*new)->lock);
 }
 
 /* Free's a task queue. */
 
 void silc_task_queue_free(SilcTaskQueue queue)
 {
+  silc_mutex_lock(queue->lock);
+  queue->valid = FALSE;
+  silc_mutex_unlock(queue->lock);
+  silc_mutex_free(queue->lock);
   silc_free(queue);
 }
 
@@ -273,26 +278,32 @@ SilcTask silc_task_register(SilcTaskQueue queue, int fd,
   /* If the task is generic task, we check whether this task has already
      been registered. Generic tasks are registered only once and after that
      the same task applies to all file descriptors to be registered. */
-  if ((type == SILC_TASK_GENERIC) && queue->task) {
-    SilcTask task;
-
-    task = queue->task;
-    while(1) {
-      if ((task->callback == cb) && (task->context == context)) {
-       SILC_LOG_DEBUG(("Found matching generic task, using the match"));
-
-       /* Add the fd to be listened, the task found now applies to this
-          fd as well. */
-       silc_schedule_set_listen_fd(queue->schedule, 
-                                   fd, (1L << SILC_TASK_READ));
-       return task;
+  if (type == SILC_TASK_GENERIC) {
+    silc_mutex_lock(queue->lock);
+
+    if (queue->task) {
+      SilcTask task = queue->task;
+      while(1) {
+       if ((task->callback == cb) && (task->context == context)) {
+         SILC_LOG_DEBUG(("Found matching generic task, using the match"));
+         
+         silc_mutex_unlock(queue->lock);
+
+         /* Add the fd to be listened, the task found now applies to this
+            fd as well. */
+         silc_schedule_set_listen_fd(queue->schedule, 
+                                     fd, (1L << SILC_TASK_READ));
+         return task;
+       }
+       
+       if (queue->task == task->next)
+         break;
+       
+       task = task->next;
       }
-
-      if (queue->task == task->next)
-       break;
-      
-      task = task->next;
     }
+
+    silc_mutex_unlock(queue->lock);
   }
 
   new = silc_calloc(1, sizeof(*new));
@@ -305,11 +316,6 @@ SilcTask silc_task_register(SilcTaskQueue queue, int fd,
   new->next = new;
   new->prev = new;
 
-  /* If the task is non-timeout task we have to tell the scheduler that we
-     would like to have these tasks scheduled at some odd distant future. */
-  if (type != SILC_TASK_TIMEOUT)
-    silc_schedule_set_listen_fd(queue->schedule, fd, (1L << SILC_TASK_READ));
-
   /* Create timeout if marked to be timeout task */
   if (((seconds + useconds) > 0) && (type == SILC_TASK_TIMEOUT)) {
     silc_gettimeofday(&new->timeout);
@@ -322,16 +328,28 @@ SilcTask silc_task_register(SilcTaskQueue queue, int fd,
     timeout = TRUE;
   }
 
+  /* If the task is non-timeout task we have to tell the scheduler that we
+     would like to have these tasks scheduled at some odd distant future. */
+  if (type != SILC_TASK_TIMEOUT)
+    silc_schedule_set_listen_fd(queue->schedule, fd, (1L << SILC_TASK_READ));
+
+  silc_mutex_lock(queue->lock);
+
   /* Is this first task of the queue? */
   if (queue->task == NULL) {
     queue->task = new;
+    silc_mutex_unlock(queue->lock);
     return new;
   }
 
   if (timeout)
-    return silc_task_add_timeout(queue, new, priority);
+    new = silc_task_add_timeout(queue, new, priority);
   else
-    return silc_task_add(queue, new, priority);
+    new = silc_task_add(queue, new, priority);
+
+  silc_mutex_unlock(queue->lock);
+
+  return new;
 }
 
 /* Removes (unregisters) a task from particular task queue. This function
@@ -343,8 +361,15 @@ int silc_task_remove(SilcTaskQueue queue, SilcTask task)
 {
   SilcTask first, old, next;
 
-  if (!queue || !queue->task)
+  if (!queue)
+    return FALSE;
+
+  silc_mutex_lock(queue->lock);
+
+  if (!queue->task) {
+    silc_mutex_unlock(queue->lock);
     return FALSE;
+  }
 
   first = queue->task;
 
@@ -361,6 +386,7 @@ int silc_task_remove(SilcTaskQueue queue, SilcTask task)
     }
 
     queue->task = NULL;
+    silc_mutex_unlock(queue->lock);
     return TRUE;
   }
 
@@ -383,12 +409,15 @@ int silc_task_remove(SilcTaskQueue queue, SilcTask task)
        queue->task = silc_task_get_first(queue, next);
       
       silc_free(old);
+      silc_mutex_unlock(queue->lock);
       return TRUE;
     }
     old = old->prev;
 
-    if (old == first)
+    if (old == first) {
+      silc_mutex_unlock(queue->lock);
       return FALSE;
+    }
   }
 }
 
@@ -410,8 +439,12 @@ void silc_task_unregister(SilcTaskQueue queue, SilcTask task)
     SilcTask next;
     SILC_LOG_DEBUG(("Unregistering all tasks at once"));
 
-    if (queue->task == NULL)
+    silc_mutex_lock(queue->lock);
+
+    if (!queue->task) {
+      silc_mutex_unlock(queue->lock);
       return;
+    }
 
     next = queue->task;
     
@@ -422,6 +455,8 @@ void silc_task_unregister(SilcTaskQueue queue, SilcTask task)
        break;
       next = next->next;
     }
+
+    silc_mutex_unlock(queue->lock);
     return;
   }
 
@@ -440,8 +475,12 @@ void silc_task_unregister_by_fd(SilcTaskQueue queue, int fd)
 
   SILC_LOG_DEBUG(("Unregister task by fd"));
 
-  if (queue->task == NULL)
+  silc_mutex_lock(queue->lock);
+
+  if (!queue->task) {
+    silc_mutex_unlock(queue->lock);
     return;
+  }
 
   next = queue->task;
 
@@ -452,6 +491,8 @@ void silc_task_unregister_by_fd(SilcTaskQueue queue, int fd)
       break;
     next = next->next;
   }
+
+  silc_mutex_unlock(queue->lock);
 }
 
 /* Unregister a task by callback function. This invalidates the task. */
@@ -463,8 +504,12 @@ void silc_task_unregister_by_callback(SilcTaskQueue queue,
 
   SILC_LOG_DEBUG(("Unregister task by callback"));
 
-  if (queue->task == NULL)
+  silc_mutex_lock(queue->lock);
+
+  if (!queue->task) {
+    silc_mutex_unlock(queue->lock);
     return;
+  }
 
   next = queue->task;
 
@@ -475,6 +520,8 @@ void silc_task_unregister_by_callback(SilcTaskQueue queue,
       break;
     next = next->next;
   }
+
+  silc_mutex_unlock(queue->lock);
 }
 
 /* Unregister a task by context. This invalidates the task. */
@@ -485,8 +532,12 @@ void silc_task_unregister_by_context(SilcTaskQueue queue, void *context)
 
   SILC_LOG_DEBUG(("Unregister task by context"));
 
-  if (queue->task == NULL)
+  silc_mutex_lock(queue->lock);
+
+  if (!queue->task) {
+    silc_mutex_unlock(queue->lock);
     return;
+  }
 
   next = queue->task;
 
@@ -497,6 +548,8 @@ void silc_task_unregister_by_context(SilcTaskQueue queue, void *context)
       break;
     next = next->next;
   }
+
+  silc_mutex_unlock(queue->lock);
 }
 
 /* Sets the I/O type of the task. The scheduler checks for this value
index 744c2f8d5630eda1346c24fe953051c41a4a6207..7719c519328adfa617fc30a5c07a8b89138e552f 100644 (file)
@@ -174,7 +174,7 @@ typedef enum {
 
    SilcTask task
 
-       Pointer to the tasks in the queue.
+       Pointer to the current (first) task in the queue.
 
    int valid
 
@@ -196,6 +196,7 @@ struct SilcTaskQueueStruct {
   SilcTask task;
   int valid;
   struct timeval timeout;
+  SILC_MUTEX_DEFINE(lock);
 };
 
 /* Marks for all tasks in a task queue. This can be passed to 
index 7875eb80a303391279de87512c8e0a717f58c806..1b531b0a481300a2384224413209a60f9be228fc 100644 (file)
@@ -28,11 +28,14 @@ struct SilcMutexStruct {
   pthread_mutex_t mutex;
 };
 
-SilcMutex silc_mutex_alloc(void)
+bool silc_mutex_alloc(SilcMutex *mutex)
 {
-  SilcMutex mutex = silc_calloc(1, sizeof(*mutex));
-  pthread_mutex_init(&mutex->mutex, NULL);
-  return mutex;
+  *mutex = silc_calloc(1, sizeof(**mutex));
+  if (*mutex == NULL)
+    return FALSE;
+
+  pthread_mutex_init(&(*mutex)->mutex, NULL);
+  return TRUE;
 }
 
 void silc_mutex_free(SilcMutex mutex)
index 690c2a2074e602c3b9e5a2dae8d58ff6a391f4d4..0a186f59610ce0774139a976e5c59247b12be2b1 100644 (file)
@@ -28,15 +28,15 @@ struct SilcMutexStruct {
   HANDLE mutex;
 };
 
-SilcMutex silc_mutex_alloc(void)
+bool silc_mutex_alloc(SilcMutex *mutex)
 {
-  SilcMutex mutex = silc_calloc(1, sizeof(*mutex));
-  mutex->mutex = CreateMutex(NULL, FALSE, NULL);
-  if (!mutex->mutex) {
-    silc_free(mutex);
-    return NULL;
+  *mutex = silc_calloc(1, sizeof(**mutex));
+  (*mutex)->mutex = CreateMutex(NULL, FALSE, NULL);
+  if (!(*mutex)->mutex) {
+    silc_free(*mutex);
+    return FALSE;
   }
-  return mutex;
+  return TRUE;
 }
 
 void silc_mutex_free(SilcMutex mutex)