+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
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
[ 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);],
*
* 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
*
#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 */
*/
/* $Id$ */
+/* XXX on multi-threads the task queue locking is missing here. */
#include "silcincludes.h"
fd_set in;
fd_set out;
int max_fd;
+ SILC_MUTEX_DEFINE(lock);
};
/* Initializes the scheduler. Sets the non-timeout task queue hook and
schedule->max_fd = -1;
for (i = 0; i < max_fd; i++)
schedule->fd_list.fd[i] = -1;
+ silc_mutex_alloc(&schedule->lock);
return schedule;
}
silc_free(schedule->fd_list.fd);
}
+ silc_mutex_free(schedule->lock);
+
return TRUE;
}
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
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) {
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
#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) \
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
#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; \
\
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; \
} \
} \
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) \
\
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) { \
} \
} \
} \
+ silc_mutex_unlock(schedule->lock); \
} \
} while(0)
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;
/* 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);
}
/* 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));
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);
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
{
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;
}
queue->task = NULL;
+ silc_mutex_unlock(queue->lock);
return TRUE;
}
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;
+ }
}
}
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;
break;
next = next->next;
}
+
+ silc_mutex_unlock(queue->lock);
return;
}
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;
break;
next = next->next;
}
+
+ silc_mutex_unlock(queue->lock);
}
/* Unregister a task by callback function. This invalidates the task. */
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;
break;
next = next->next;
}
+
+ silc_mutex_unlock(queue->lock);
}
/* Unregister a task by context. This invalidates the task. */
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;
break;
next = next->next;
}
+
+ silc_mutex_unlock(queue->lock);
}
/* Sets the I/O type of the task. The scheduler checks for this value
SilcTask task
- Pointer to the tasks in the queue.
+ Pointer to the current (first) task in the queue.
int valid
SilcTask task;
int valid;
struct timeval timeout;
+ SILC_MUTEX_DEFINE(lock);
};
/* Marks for all tasks in a task queue. This can be passed to
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)
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)