From a9f6fe9c6d50556c346119b44e46169f93147134 Mon Sep 17 00:00:00 2001 From: Pekka Riikonen Date: Sat, 24 Jun 2006 19:32:34 +0000 Subject: [PATCH] Added conditional variables. --- lib/silcutil/DIRECTORY | 3 +- lib/silcutil/silccondvar.h | 171 +++++++++++++++++++++++++++ lib/silcutil/unix/Makefile.am | 3 +- lib/silcutil/unix/silcunixmutex.c | 73 ------------ lib/silcutil/unix/silcunixthread.c | 134 ++++++++++++++++++++- lib/silcutil/win32/Makefile.am | 3 +- lib/silcutil/win32/silcwin32mutex.c | 76 ------------ lib/silcutil/win32/silcwin32thread.c | 156 +++++++++++++++++++++++- 8 files changed, 456 insertions(+), 163 deletions(-) create mode 100644 lib/silcutil/silccondvar.h delete mode 100644 lib/silcutil/unix/silcunixmutex.c delete mode 100644 lib/silcutil/win32/silcwin32mutex.c diff --git a/lib/silcutil/DIRECTORY b/lib/silcutil/DIRECTORY index 46c522ac..d72eb1aa 100644 --- a/lib/silcutil/DIRECTORY +++ b/lib/silcutil/DIRECTORY @@ -7,8 +7,9 @@ @LINK=silchashtable.html:SILC Hash Table Interface @LINK=silclog.html:SILC Logging Interface @LINK=silcmemory.html:SILC Memory Interface -@LINK=silcmutex.html:SILC Mutex Interface @LINK=silcthread.html:SILC Thread Interface +@LINK=silcmutex.html:SILC Mutex Interface +@LINK=silccondvar.html:SILC Conditional Variable Interface @LINK=silcnet.html:SILC Network Interface @LINK=silcschedule.html:SILC Schedule Interface @LINK=silcsockconn.html:SILC Socket Interface diff --git a/lib/silcutil/silccondvar.h b/lib/silcutil/silccondvar.h new file mode 100644 index 00000000..ada9007e --- /dev/null +++ b/lib/silcutil/silccondvar.h @@ -0,0 +1,171 @@ +/* + + silccondvar.h + + Author: Pekka Riikonen + + Copyright (C) 2006 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 + the Free Software Foundation; version 2 of the License. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + +*/ + +/****h* silcutil/SILC Conditional Variable Interface + * + * DESCRIPTION + * + * A conditional variable interface for multi-thread synchronization. + * Conditional variables enable threads to suspend execution and yield + * the processors until some predicate on some shared data is satisfied. + * + ***/ + +#ifndef SILCCONDVAR_H +#define SILCCONDVAR_H + +/****s* silcutil/SilcCondVarAPI/SilcCondVar + * + * NAME + * + * typedef struct SilcCondVarStruct *SilcCondVar; + * + * DESCRIPTION + * + * This context is the actual conditional variable and is allocated + * by silc_condvar_alloc and given as argument to all silc_condvar_* + * functions. It is freed by the silc_condvar_free function. + * + ***/ +typedef struct SilcCondVarStruct *SilcCondVar; + +/****s* silcutil/SilcCondVarAPI/silc_condvar_alloc + * + * SYNOPSIS + * + * SilcBool silc_condvar_alloc(SilcCondVar *cond); + * + * DESCRIPTION + * + * Allocates SILC Conditional variable context. The conditional must + * be allocated before it can be used. It is freed by the + * silc_condvar_free function. This returns TRUE and allocated + * conditional in to the `cond' pointer and FALSE on error. + * + ***/ +SilcBool silc_condvar_alloc(SilcCondVar *cond); + +/****s* silcutil/SilcCondVarAPI/silc_condvar_free + * + * SYNOPSIS + * + * void silc_condvar_free(SilcCondVar cond); + * + * DESCRIPTION + * + * Free conditional variable context. If `cond' is NULL this function + * has no effect. + * + ***/ +void silc_condvar_free(SilcCondVar cond); + +/****s* silcutil/SilcCondVarAPI/silc_condvar_wait + * + * SYNOPSIS + * + * void silc_condvar_wait(SilcCondVar cond, SilcMutex mutex); + * + * DESCRIPTION + * + * Waits for conditional variable `cond' to be signalled. This function + * will block the calling thread until the conditional variable is + * signalled. The `mutex' must be locked before calling this function. + * The `mutex' will be unlocked inside this function. After this + * function returns the `mutex' is in locked state again. + * + * EXAMPLE + * + * silc_mutex_lock(lock); + * while (c->a == NULL) + * silc_condvar_wait(cond, lock); + * ... + * silc_mutex_unlock(lock); + * + ***/ +void silc_condvar_wait(SilcCondVar cond, SilcMutex mutex); + +/****s* silcutil/SilcCondVarAPI/silc_condvar_timedwait + * + * SYNOPSIS + * + * void silc_condvar_timedwait(SilcCondVar cond, SilcMutex mutex, + * struct timespec *timeout); + * + * DESCRIPTION + * + * Waits for conditional variable `cond' to be signalled or for the + * `timeout' to expire. The timeout is in milliseconds. If it is 0 + * no timeout exist. Returns FALSE if timeout expired, TRUE when + * signalled. This function will block the calling thread until the + * conditional variable is signalled. The `mutex' must be locked before + * calling this function. The `mutex' will be unlocked inside this + * function. After this function returns the `mutex' is in locked + * state again. + * + ***/ +SilcBool silc_condvar_timedwait(SilcCondVar cond, SilcMutex mutex, + int timeout); + +/****s* silcutil/SilcCondVarAPI/silc_condvar_signal + * + * SYNOPSIS + * + * void silc_condvar_signal(SilcCondVar cond); + * + * DESCRIPTION + * + * Signals a waiting thread and wakes it up. If there are no waiters + * this function has no effect. In case of multiple waiters only one + * is signalled. To signal all of them use silc_condvar_broadcast. + * + * NOTES + * + * Before calling this function the mutex used with the silc_condvar_wait + * must be acquired. + * + * EXAMPLE + * + * silc_mutex_lock(lock); + * c->a = context; + * silc_condvar_signal(cond); + * silc_mutex_unlock(lock); + * + ***/ +void silc_condvar_signal(SilcCondVar cond); + +/****s* silcutil/SilcCondVarAPI/silc_condvar_broadcast + * + * SYNOPSIS + * + * void silc_condvar_broadcast(SilcCondVar cond); + * + * DESCRIPTION + * + * Signals and wakes up all waiters. If there are no waiters this + * function has no effect. + * + * NOTES + * + * Before calling this function the mutex used with the silc_condvar_wait + * must be acquired. + * + ***/ +void silc_condvar_broadcast(SilcCondVar cond); + +#endif /* SILCCONDVAR_H */ diff --git a/lib/silcutil/unix/Makefile.am b/lib/silcutil/unix/Makefile.am index 3f7fb8c3..bb9719e1 100644 --- a/lib/silcutil/unix/Makefile.am +++ b/lib/silcutil/unix/Makefile.am @@ -3,7 +3,7 @@ # # Author: Pekka Riikonen # -# Copyright (C) 2001 Pekka Riikonen +# Copyright (C) 2001 - 2006 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 @@ -25,7 +25,6 @@ libsilcunixutil_la_SOURCES = \ silcunixnet.c \ silcunixutil.c \ silcunixsocketstream.c \ - silcunixmutex.c \ silcunixthread.c include $(top_srcdir)/Makefile.defines.in diff --git a/lib/silcutil/unix/silcunixmutex.c b/lib/silcutil/unix/silcunixmutex.c deleted file mode 100644 index 0eae1496..00000000 --- a/lib/silcutil/unix/silcunixmutex.c +++ /dev/null @@ -1,73 +0,0 @@ -/* - - silcunixmutex.c - - Author: Pekka Riikonen - - Copyright (C) 2001 - 2005 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 - the Free Software Foundation; version 2 of the License. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - -*/ -/* $Id$ */ - -#include "silc.h" - -/* SILC Mutex structure */ -struct SilcMutexStruct { -#ifdef SILC_THREADS - pthread_mutex_t mutex; -#else - void *tmp; -#endif /* SILC_THREADS */ -}; - -SilcBool silc_mutex_alloc(SilcMutex *mutex) -{ -#ifdef SILC_THREADS - *mutex = silc_calloc(1, sizeof(**mutex)); - if (*mutex == NULL) - return FALSE; - pthread_mutex_init(&(*mutex)->mutex, NULL); - return TRUE; -#else - return FALSE; -#endif /* SILC_THREADS */ -} - -void silc_mutex_free(SilcMutex mutex) -{ -#ifdef SILC_THREADS - if (mutex) { - pthread_mutex_destroy(&mutex->mutex); - silc_free(mutex); - } -#endif /* SILC_THREADS */ -} - -void silc_mutex_lock(SilcMutex mutex) -{ -#ifdef SILC_THREADS - if (mutex) { - if (pthread_mutex_lock(&mutex->mutex)) - assert(FALSE); - } -#endif /* SILC_THREADS */ -} - -void silc_mutex_unlock(SilcMutex mutex) -{ -#ifdef SILC_THREADS - if (mutex) { - if (pthread_mutex_unlock(&mutex->mutex)) - assert(FALSE); - } -#endif /* SILC_THREADS */ -} diff --git a/lib/silcutil/unix/silcunixthread.c b/lib/silcutil/unix/silcunixthread.c index 099d75d9..b32f61d6 100644 --- a/lib/silcutil/unix/silcunixthread.c +++ b/lib/silcutil/unix/silcunixthread.c @@ -4,12 +4,12 @@ Author: Pekka Riikonen - Copyright (C) 2001 - 2005 Pekka Riikonen + Copyright (C) 2001 - 2006 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 the Free Software Foundation; version 2 of the License. - + This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the @@ -20,6 +20,8 @@ #include "silc.h" +/**************************** SILC Thread API *******************************/ + SilcThread silc_thread_create(SilcThreadStart start_func, void *context, SilcBool waitable) { @@ -39,14 +41,14 @@ SilcThread silc_thread_create(SilcThreadStart start_func, void *context, } if (pthread_attr_setdetachstate(&attr, - waitable ? PTHREAD_CREATE_JOINABLE : + waitable ? PTHREAD_CREATE_JOINABLE : PTHREAD_CREATE_DETACHED)) { SILC_LOG_ERROR(("Thread error: %s", strerror(errno))); pthread_attr_destroy(&attr); return NULL; } - ret = pthread_create(&thread, &attr, (void * (*)(void *))start_func, + ret = pthread_create(&thread, &attr, (void * (*)(void *))start_func, context); if (ret) { SILC_LOG_ERROR(("Thread error: %s", strerror(errno))); @@ -94,3 +96,127 @@ SilcBool silc_thread_wait(SilcThread thread, void **exit_value) return FALSE; #endif } + + +/***************************** SILC Mutex API *******************************/ + +/* SILC Mutex structure */ +struct SilcMutexStruct { +#ifdef SILC_THREADS + pthread_mutex_t mutex; +#else + void *tmp; +#endif /* SILC_THREADS */ +}; + +SilcBool silc_mutex_alloc(SilcMutex *mutex) +{ +#ifdef SILC_THREADS + *mutex = silc_calloc(1, sizeof(**mutex)); + if (*mutex == NULL) + return FALSE; + pthread_mutex_init(&(*mutex)->mutex, NULL); + return TRUE; +#else + return FALSE; +#endif /* SILC_THREADS */ +} + +void silc_mutex_free(SilcMutex mutex) +{ +#ifdef SILC_THREADS + if (mutex) { + pthread_mutex_destroy(&mutex->mutex); + silc_free(mutex); + } +#endif /* SILC_THREADS */ +} + +void silc_mutex_lock(SilcMutex mutex) +{ +#ifdef SILC_THREADS + if (mutex) { + if (pthread_mutex_lock(&mutex->mutex)) + assert(FALSE); + } +#endif /* SILC_THREADS */ +} + +void silc_mutex_unlock(SilcMutex mutex) +{ +#ifdef SILC_THREADS + if (mutex) { + if (pthread_mutex_unlock(&mutex->mutex)) + assert(FALSE); + } +#endif /* SILC_THREADS */ +} + + +/**************************** SILC CondVar API ******************************/ + +/* SILC Conditional Variable context */ +struct SilcCondVarStruct { +#ifdef SILC_THREADS + pthread_cond_t cond; +#else + void *tmp; +#endif /* SILC_THREADS*/ +}; + +SilcBool silc_condvar_alloc(SilcCondVar *cond) +{ +#ifdef SILC_THREADS + *cond = silc_calloc(1, sizeof(**cond)); + if (*cond == NULL) + return FALSE; + pthread_cond_init(&(*cond)->cond, NULL); + return TRUE; +#else + return FALSE; +#endif /* SILC_THREADS*/ +} + +void silc_condvar_free(SilcCondVar cond) +{ +#ifdef SILC_THREADS + pthread_cond_destroy(&cond->cond); + silc_free(cond); +#endif /* SILC_THREADS*/ +} + +void silc_condvar_signal(SilcCondVar cond) +{ +#ifdef SILC_THREADS + pthread_cond_signal(&cond->cond); +#endif /* SILC_THREADS*/ +} + +void silc_condvar_broadcast(SilcCondVar cond) +{ +#ifdef SILC_THREADS + pthread_cond_broadcast(&cond->cond); +#endif /* SILC_THREADS*/ +} + +void silc_condvar_wait(SilcCondVar cond, SilcMutex mutex) +{ +#ifdef SILC_THREADS + pthread_cond_wait(&cond->cond, &mutex->mutex); +#endif /* SILC_THREADS*/ +} + +SilcBool silc_condvar_timedwait(SilcCondVar cond, SilcMutex mutex, + int timeout) +{ +#ifdef SILC_THREADS + struct timespec t; + if (timeout) { + t.tv_sec = timeout / 1000; + t.tv_nsec = (timeout % 1000) * 1000; + return pthread_cond_timedwait(&cond->cond, &mutex->mutex, &t) == 0; + } + + return pthread_cond_wait(&cond->cond, &mutex->mutex) == 0; +#endif /* SILC_THREADS*/ +} diff --git a/lib/silcutil/win32/Makefile.am b/lib/silcutil/win32/Makefile.am index ed709606..4bb647ad 100644 --- a/lib/silcutil/win32/Makefile.am +++ b/lib/silcutil/win32/Makefile.am @@ -3,7 +3,7 @@ # # Author: Pekka Riikonen # -# Copyright (C) 2001 Pekka Riikonen +# Copyright (C) 2001 - 2006 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 @@ -25,7 +25,6 @@ libsilcwin32util_la_SOURCES = \ silcwin32schedule.c \ silcwin32sockconn.c \ silcwin32util.c \ - silcwin32mutex.c \ silcwin32thread.c include $(top_srcdir)/Makefile.defines.in diff --git a/lib/silcutil/win32/silcwin32mutex.c b/lib/silcutil/win32/silcwin32mutex.c deleted file mode 100644 index 34db890f..00000000 --- a/lib/silcutil/win32/silcwin32mutex.c +++ /dev/null @@ -1,76 +0,0 @@ -/* - - silcwin32mutex.c - - Author: Pekka Riikonen - - Copyright (C) 2001 - 2005 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 - the Free Software Foundation; version 2 of the License. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - -*/ -/* $Id$ */ - -#include "silc.h" - -/* SILC Mutex structure */ -struct SilcMutexStruct { -#ifdef SILC_THREADS - CRITICAL_SECTION mutex; - BOOL locked; -#else - void *tmp; -#endif /* SILC_THREADS */ -}; - -SilcBool silc_mutex_alloc(SilcMutex *mutex) -{ -#ifdef SILC_THREADS - *mutex = silc_calloc(1, sizeof(**mutex)); - if (!(*mutex)) - return FALSE; - InitializeCriticalSection(&((*mutex)->mutex)); - return TRUE; -#else - return FALSE; -#endif /* SILC_THREADS */ -} - -void silc_mutex_free(SilcMutex mutex) -{ -#ifdef SILC_THREADS - if (mutex) { - DeleteCriticalSection(&mutex->mutex); - silc_free(mutex); - } -#endif /* SILC_THREADS */ -} - -void silc_mutex_lock(SilcMutex mutex) -{ -#ifdef SILC_THREADS - if (mutex) { - EnterCriticalSection(&mutex->mutex); - assert(mutex->locked == FALSE); - mutex->locked = TRUE; - } -#endif /* SILC_THREADS */ -} - -void silc_mutex_unlock(SilcMutex mutex) -{ -#ifdef SILC_THREADS - if (mutex) { - assert(mutex->locked == TRUE); - mutex->locked = FALSE; - LeaveCriticalSection(&mutex->mutex); - } -#endif /* SILC_THREADS */ -} diff --git a/lib/silcutil/win32/silcwin32thread.c b/lib/silcutil/win32/silcwin32thread.c index c31e7093..f55a55ac 100644 --- a/lib/silcutil/win32/silcwin32thread.c +++ b/lib/silcutil/win32/silcwin32thread.c @@ -4,12 +4,12 @@ Author: Pekka Riikonen - Copyright (C) 2001 - 2005 Pekka Riikonen + Copyright (C) 2001 - 2006 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 the Free Software Foundation; version 2 of the License. - + This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the @@ -20,6 +20,8 @@ #include "silc.h" +/**************************** SILC Thread API *******************************/ + #ifdef SILC_THREADS /* Thread structure for WIN32 */ @@ -82,7 +84,7 @@ void silc_thread_exit(void *exit_value) { #ifdef SILC_THREADS SilcWin32Thread thread = TlsGetValue(silc_thread_tls); - + if (thread) { /* If the thread is waitable the memory is freed only in silc_thread_wait by another thread. If not waitable, free it now. */ @@ -107,8 +109,8 @@ SilcThread silc_thread_self(void) HANDLE handle = GetCurrentThread (); HANDLE process = GetCurrentProcess (); self = silc_calloc(1, sizeof(*self)); - DuplicateHandle(process, handle, process, - &self->thread, 0, FALSE, + DuplicateHandle(process, handle, process, + &self->thread, 0, FALSE, DUPLICATE_SAME_ACCESS); TlsSetValue(silc_thread_tls, self); } @@ -143,3 +145,147 @@ SilcBool silc_thread_wait(SilcThread thread, void **exit_value) return FALSE; #endif } + + +/***************************** SILC Mutex API *******************************/ + +/* SILC Mutex structure */ +struct SilcMutexStruct { +#ifdef SILC_THREADS + CRITICAL_SECTION mutex; + BOOL locked; +#else + void *tmp; +#endif /* SILC_THREADS */ +}; + +SilcBool silc_mutex_alloc(SilcMutex *mutex) +{ +#ifdef SILC_THREADS + *mutex = silc_calloc(1, sizeof(**mutex)); + if (!(*mutex)) + return FALSE; + InitializeCriticalSection(&((*mutex)->mutex)); + return TRUE; +#else + return FALSE; +#endif /* SILC_THREADS */ +} + +void silc_mutex_free(SilcMutex mutex) +{ +#ifdef SILC_THREADS + if (mutex) { + DeleteCriticalSection(&mutex->mutex); + silc_free(mutex); + } +#endif /* SILC_THREADS */ +} + +void silc_mutex_lock(SilcMutex mutex) +{ +#ifdef SILC_THREADS + if (mutex) { + EnterCriticalSection(&mutex->mutex); + assert(mutex->locked == FALSE); + mutex->locked = TRUE; + } +#endif /* SILC_THREADS */ +} + +void silc_mutex_unlock(SilcMutex mutex) +{ +#ifdef SILC_THREADS + if (mutex) { + assert(mutex->locked == TRUE); + mutex->locked = FALSE; + LeaveCriticalSection(&mutex->mutex); + } +#endif /* SILC_THREADS */ +} + + +/**************************** SILC CondVar API ******************************/ + +/* SILC Conditional Variable context */ +struct SilcCondVarStruct { +#ifdef SILC_THREADS + HANDLE event; +#endif /* SILC_THREADS*/ + unsigned int waiters : 23; + unsigned int signal : 1; +}; + +SilcBool silc_condvar_alloc(SilcCondVar *cond) +{ +#ifdef SILC_THREADS + *cond = silc_calloc(1, sizeof(**cond)); + if (*cond == NULL) + return FALSE; + (*cond)->event = CreateEvent(NULL, TRUE, FALSE, NULL); + return TRUE; +#else + return FALSE; +#endif /* SILC_THREADS*/ +} + +void silc_condvar_free(SilcCondVar cond) +{ +#ifdef SILC_THREADS + CloseHandle(cond->event); + silc_free(cond); +#endif /* SILC_THREADS*/ +} + +void silc_condvar_signal(SilcCondVar cond) +{ +#ifdef SILC_THREADS + cond->signal = TRUE; + SetEvent(cond->event); +#endif /* SILC_THREADS*/ +} + +void silc_condvar_broadcast(SilcCondVar cond) +{ +#ifdef SILC_THREADS + cond->signal = TRUE; + SetEvent(cond->event); +#endif /* SILC_THREADS*/ +} + +void silc_condvar_wait(SilcCondVar cond, SilcMutex mutex) +{ +#ifdef SILC_THREADS + silc_condvar_timedwait(cond, mutex, NULL); +#endif /* SILC_THREADS*/ +} + +SilcBool silc_condvar_timedwait(SilcCondVar cond, SilcMutex mutex, + int timeout) +{ +#ifdef SILC_THREADS + DWORD ret, t = INFINITE; + + if (timeout) + t = timeout; + + while (TRUE) { + cond->waiters++; + silc_mutex_unlock(mutex); + + ret = WaitForSingleObject(cond->event, t); + + silc_mutex_lock(mutex); + cond->waiters--; + + if (ret != WAIT_OBJECT_0) + return FALSE; + + if (cond->signal) { + cond->signal = FALSE; + ResetEvent(cond->event); + break; + } + } +#endif /* SILC_THREADS*/ +} -- 2.24.0