From: Pekka Riikonen Date: Sun, 8 Jul 2001 18:14:41 +0000 (+0000) Subject: updates. X-Git-Tag: robodoc-323~95 X-Git-Url: http://git.silcnet.org/gitweb/?p=silc.git;a=commitdiff_plain;h=a0fe867f869c85822eacf159feeda6b94464423e updates. --- diff --git a/CHANGES b/CHANGES index 012d0b51..713f6333 100644 --- a/CHANGES +++ b/CHANGES @@ -1,3 +1,19 @@ +Sun Jul 8 18:44:53 EEST 2001 Pekka Riikonen + + * 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 * Implemented the SILC Mutex API and SILC Thread API for WIN32 diff --git a/TODO b/TODO index b5a01159..bcdeaa2e 100644 --- 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 diff --git a/configure.in.pre b/configure.in.pre index 23e6da76..9999270a 100644 --- a/configure.in.pre +++ b/configure.in.pre @@ -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_attr_t attr; pthread_attr_init(&attr);], diff --git a/lib/silcutil/silcmutex.h b/lib/silcutil/silcmutex.h index ef02621e..9e8267fa 100644 --- a/lib/silcutil/silcmutex.h +++ b/lib/silcutil/silcmutex.h @@ -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 */ diff --git a/lib/silcutil/silcschedule.c b/lib/silcutil/silcschedule.c index b7e99ed4..036b0bda 100644 --- a/lib/silcutil/silcschedule.c +++ b/lib/silcutil/silcschedule.c @@ -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; diff --git a/lib/silcutil/silctask.c b/lib/silcutil/silctask.c index 5a1c6a3e..738edae8 100644 --- a/lib/silcutil/silctask.c +++ b/lib/silcutil/silctask.c @@ -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 diff --git a/lib/silcutil/silctask.h b/lib/silcutil/silctask.h index 744c2f8d..7719c519 100644 --- a/lib/silcutil/silctask.h +++ b/lib/silcutil/silctask.h @@ -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 diff --git a/lib/silcutil/unix/silcunixmutex.c b/lib/silcutil/unix/silcunixmutex.c index 7875eb80..1b531b0a 100644 --- a/lib/silcutil/unix/silcunixmutex.c +++ b/lib/silcutil/unix/silcunixmutex.c @@ -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) diff --git a/lib/silcutil/win32/silcwin32mutex.c b/lib/silcutil/win32/silcwin32mutex.c index 690c2a20..0a186f59 100644 --- a/lib/silcutil/win32/silcwin32mutex.c +++ b/lib/silcutil/win32/silcwin32mutex.c @@ -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)