From: Pekka Riikonen Date: Mon, 29 Jan 2007 16:03:51 +0000 (+0000) Subject: Added SilcRwLock, a read/write lock API. X-Git-Tag: silc.client.1.1.beta1~37 X-Git-Url: http://git.silcnet.org/gitweb/?p=silc.git;a=commitdiff_plain;h=0f95f4926c8579fe3cc36c9e68f36b67170a0c8e Added SilcRwLock, a read/write lock API. --- diff --git a/CHANGES b/CHANGES index ce0636bb..c8a43fb7 100644 --- a/CHANGES +++ b/CHANGES @@ -1,3 +1,8 @@ +Sat Jan 27 22:37:30 EET 2007 Pekka Riikonen + + * Added SilcRwLock API, a read/write lock. Affected files are + lib/silcutil/silcmutex.h and in lib/silcutil/[unix|win32|symbian]/. + Wed Jan 24 18:55:21 EET 2007 Pekka Riikonen * Merged Irssi SVN (irssi 0.8.11). Affected files in apps/irssi/. @@ -21,7 +26,7 @@ Tue Jan 16 18:22:08 EET 2007 Pekka Riikonen * Implemented PKCS #1 with appendix with hash OID in the signature. Affected files are lib/silccrypt/silcpkcs1.[ch], - lib/silccrypt/silchash.[ch] and + lib/silccrypt/silchash.[ch] and lib/silcasn1/silcasn1[_encode|decode].[ch]. Sun Jan 14 23:12:41 EET 2007 Pekka Riikonen diff --git a/TODO b/TODO index 1d77eafb..5e7ca9a2 100644 --- a/TODO +++ b/TODO @@ -176,6 +176,8 @@ lib/silcutil ****PARTLY DONE**** No need to make it silcutil/unix/ specific. Add them to generic silcutil.c. + o Fix universal time decoding (doesn't accept all forms) in silctime.c. + o silc_stringprep to non-allocating version. o Compression routines are missing. The protocol supports packet diff --git a/lib/silcutil/silcmutex.h b/lib/silcutil/silcmutex.h index 37f08add..82a9da39 100644 --- a/lib/silcutil/silcmutex.h +++ b/lib/silcutil/silcmutex.h @@ -4,7 +4,7 @@ Author: Pekka Riikonen - Copyright (C) 2001 - 2005 Pekka Riikonen + Copyright (C) 2001 - 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 @@ -21,9 +21,9 @@ * * DESCRIPTION * - * Interface for the SILC Mutex locking implementation. This is platform - * independent mutual exclusion interface for applications that need - * concurrency control. + * Interface for mutual exclusion locks and read/write locks. This is + * platform independent interface for applications that need concurrency + * control. * ***/ @@ -45,6 +45,21 @@ ***/ typedef struct SilcMutexStruct *SilcMutex; +/****s* silcutil/SilcMutexAPI/SilcRwLock + * + * NAME + * + * typedef struct SilcRwLockStruct *SilcRwLock; + * + * DESCRIPTION + * + * This context is the actual SILC read/write lock and is allocated + * by silc_rwlock_alloc and given as argument to all silc_rwlock_* + * functions. It is freed by the silc_rwlock_free function. + * + ***/ +typedef struct SilcRwLockStruct *SilcRwLock; + /****f* silcutil/SilcMutexAPI/silc_mutex_alloc * * SYNOPSIS @@ -132,4 +147,84 @@ void silc_mutex_unlock(SilcMutex mutex); ***/ void silc_mutex_assert_locked(SilcMutex mutex); +/****f* silcutil/SilcMutexAPI/silc_rwlock_alloc + * + * SYNOPSIS + * + * SilcBool silc_rwlock_alloc(SilcRwLock *rwlock); + * + * DESCRIPTION + * + * Allocates SILC read/write lock. The read/write lock must be allocated + * before it can be used. It is freed by the silc_rwlock_free function. + * This returns TRUE and allocated read/write lock in to the `rwlock' and + * FALSE on error. + * + ***/ +SilcBool silc_rwlock_alloc(SilcRwLock *rwlock); + +/****f* silcutil/SilcRwLockAPI/silc_rwlock_free + * + * SYNOPSIS + * + * void silc_rwlock_free(SilcRwLock rwlock); + * + * DESCRIPTION + * + * Free SILC Rwlock object and frees all allocated memory. If `rwlock' + * is NULL this function has no effect. + * + ***/ +void silc_rwlock_free(SilcRwLock rwlock); + +/****f* silcutil/SilcRwLockAPI/silc_rwlock_rdlock + * + * SYNOPSIS + * + * void silc_rwlock_rdlock(SilcRwLock rwlock); + * + * DESCRIPTION + * + * Acquires read lock of the read/write lock `rwlock'. If the `rwlock' + * is locked by a writer the current thread will block until the other + * thread has issued silc_rwlock_unlock for the `rwlock'. This function + * may be called multiple times to acquire the read lock. There must be + * same amount of silc_rwlock_unlock calls. If `rwlock' is NULL this + * function has no effect. + * + ***/ +void silc_rwlock_rdlock(SilcRwLock rwlock); + +/****f* silcutil/SilcRwLockAPI/silc_rwlock_wrlock + * + * SYNOPSIS + * + * void silc_rwlock_wrlock(SilcRwLock rwlock); + * + * DESCRIPTION + * + * Acquires write lock of the read/write lock `rwlock'. If the `rwlock' + * is locked by a writer or a reader the current thread will block until + * the other thread(s) have issued silc_rwlock_unlock for the `rwlock'. + * If `rwlock' is NULL this function has no effect. + * + ***/ +void silc_rwlock_wrlock(SilcRwLock rwlock); + +/****f* silcutil/SilcRwLockAPI/silc_rwlock_unlock + * + * SYNOPSIS + * + * void silc_rwlock_unlock(SilcRwLock rwlock); + * + * DESCRIPTION + * + * Releases the lock of the read/write lock `rwlock'. If `rwlock' was + * locked by a writer this will release the writer lock. Otherwise this + * releases the reader lock. If `rwlock' is NULL this function has no + * effect. + * + ***/ +void silc_rwlock_unlock(SilcRwLock rwlock); + #endif diff --git a/lib/silcutil/symbian/silcsymbianthread.cpp b/lib/silcutil/symbian/silcsymbianthread.cpp index 7e134e52..d4d788dc 100644 --- a/lib/silcutil/symbian/silcsymbianthread.cpp +++ b/lib/silcutil/symbian/silcsymbianthread.cpp @@ -214,6 +214,92 @@ void silc_mutex_assert_locked(SilcMutex mutex) #endif /* SILC_THREADS */ } +/***************************** SILC Rwlock API *****************************/ + +/* SILC read/write lock structure */ +struct SilcRwLockStruct { +#ifdef SILC_THREADS + SilcMutex mutex; + SilcCond cond; +#endif /* SILC_THREADS */ + unsigned int readers : 31; + unsigned int locked : 1; +}; + +SilcBool silc_rwlock_alloc(SilcRwLock *rwlock) +{ +#ifdef SILC_THREADS + *rwlock = (SilcRwLock)silc_calloc(1, sizeof(**rwlock)); + if (!(*rwlock)) + return FALSE; + if (!silc_mutex_alloc(&(*rwlock)->mutex)) { + silc_free(*rwlock); + return FALSE; + } + if (!silc_cond_alloc(&(*rwlock)->cond)) { + silc_mutex_free((*rwlock)->mutex); + silc_free(*rwlock); + return FALSE; + } + return TRUE; +#else + return FALSE; +#endif /* SILC_THREADS */ +} + +void silc_rwlock_free(SilcRwLock rwlock) +{ +#ifdef SILC_THREADS + if (mutex) { + silc_mutex_free(rwlock->mutex); + silc_cond_free(rwlock->cond); + silc_free(rwlock); + } +#endif /* SILC_THREADS */ +} + +void silc_rwlock_rdlock(SilcRwLock rwlock) +{ +#ifdef SILC_THREADS + if (rwlock) { + silc_mutex_lock(rwlock->mutex); + rwlock->readers++; + silc_mutex_unlock(rwlock->mutex); + } +#endif /* SILC_THREADS */ +} + +void silc_rwlock_wrlock(SilcRwLock rwlock) +{ +#ifdef SILC_THREADS + if (rwlock) { + silc_mutex_lock(rwlock->mutex); + while (rwlock->readers > 0) + silc_cond_wait(rwlock->cond, rwlock->mutex); + rwlock->locked = TRUE; + } +#endif /* SILC_THREADS */ +} + +void silc_rwlock_unlock(SilcRwLock rwlock) +{ +#ifdef SILC_THREADS + if (rwlock) { + if (rwlock->locked) { + /* Unlock writer */ + rwlock->locked = FALSE; + silc_mutex_unlock(rwlock->mutex); + return; + } + + /* Unlock reader */ + silc_mutex_lock(rwlock->mutex); + rwlock->readers--; + silc_cond_broadcast(rwlock->cond); + silc_mutex_unlock(rwlock->mutex); + } +#endif /* SILC_THREADS */ +} /****************************** SILC Cond API *******************************/ diff --git a/lib/silcutil/unix/silcunixthread.c b/lib/silcutil/unix/silcunixthread.c index 7f52de90..6e85dd74 100644 --- a/lib/silcutil/unix/silcunixthread.c +++ b/lib/silcutil/unix/silcunixthread.c @@ -4,7 +4,7 @@ Author: Pekka Riikonen - Copyright (C) 2001 - 2006 Pekka Riikonen + Copyright (C) 2001 - 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 @@ -162,6 +162,63 @@ void silc_mutex_assert_locked(SilcMutex mutex) #endif /* SILC_THREADS */ } +/***************************** SILC Rwlock API ******************************/ + +/* SILC read/write lock structure */ +struct SilcRwLockStruct { +#ifdef SILC_THREADS + pthread_rwlock_t rwlock; +#else + void *tmp; +#endif /* SILC_THREADS */ +}; + +SilcBool silc_rwlock_alloc(SilcRwLock *rwlock) +{ +#ifdef SILC_THREADS + *rwlock = silc_calloc(1, sizeof(**rwlock)); + if (*rwlock == NULL) + return FALSE; + pthread_rwlock_init(&(*rwlock)->rwlock, NULL); + return TRUE; +#else + return FALSE; +#endif /* SILC_THREADS */ +} + +void silc_rwlock_free(SilcRwLock rwlock) +{ +#ifdef SILC_THREADS + if (rwlock) { + pthread_rwlock_destroy(&rwlock->rwlock); + silc_free(rwlock); + } +#endif /* SILC_THREADS */ +} + +void silc_rwlock_rdlock(SilcRwLock rwlock) +{ +#ifdef SILC_THREADS + if (rwlock) + pthread_rwlock_rdlock(&rwlock->rwlock); +#endif /* SILC_THREADS */ +} + +void silc_rwlock_wrlock(SilcRwLock rwlock) +{ +#ifdef SILC_THREADS + if (rwlock) + pthread_rwlock_wrlock(&rwlock->rwlock); +#endif /* SILC_THREADS */ +} + +void silc_rwlock_unlock(SilcRwLock rwlock) +{ +#ifdef SILC_THREADS + if (rwlock) + pthread_rwlock_unlock(&rwlock->rwlock); +#endif /* SILC_THREADS */ +} /****************************** SILC Cond API *******************************/ diff --git a/lib/silcutil/win32/silcwin32thread.c b/lib/silcutil/win32/silcwin32thread.c index 97e516bc..d54a13e6 100644 --- a/lib/silcutil/win32/silcwin32thread.c +++ b/lib/silcutil/win32/silcwin32thread.c @@ -4,7 +4,7 @@ Author: Pekka Riikonen - Copyright (C) 2001 - 2006 Pekka Riikonen + Copyright (C) 2001 - 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 @@ -211,6 +211,94 @@ void silc_mutex_assert_locked(SilcMutex mutex) } +/***************************** SILC Rwlock API ******************************/ + +/* SILC read/write lock structure */ +struct SilcRwLockStruct { +#ifdef SILC_THREADS + SilcMutex mutex; + SilcCond cond; +#endif /* SILC_THREADS */ + unsigned int readers : 31; + unsigned int locked : 1; +}; + +SilcBool silc_rwlock_alloc(SilcRwLock *rwlock) +{ +#ifdef SILC_THREADS + *rwlock = silc_calloc(1, sizeof(**rwlock)); + if (!(*rwlock)) + return FALSE; + if (!silc_mutex_alloc(&(*rwlock)->mutex)) { + silc_free(*rwlock); + return FALSE; + } + if (!silc_cond_alloc(&(*rwlock)->cond)) { + silc_mutex_free((*rwlock)->mutex); + silc_free(*rwlock); + return FALSE; + } + return TRUE; +#else + return FALSE; +#endif /* SILC_THREADS */ +} + +void silc_rwlock_free(SilcRwLock rwlock) +{ +#ifdef SILC_THREADS + if (mutex) { + silc_mutex_free(rwlock->mutex); + silc_cond_free(rwlock->cond); + silc_free(rwlock); + } +#endif /* SILC_THREADS */ +} + +void silc_rwlock_rdlock(SilcRwLock rwlock) +{ +#ifdef SILC_THREADS + if (rwlock) { + silc_mutex_lock(rwlock->mutex); + rwlock->readers++; + silc_mutex_unlock(rwlock->mutex); + } +#endif /* SILC_THREADS */ +} + +void silc_rwlock_wrlock(SilcRwLock rwlock) +{ +#ifdef SILC_THREADS + if (rwlock) { + silc_mutex_lock(rwlock->mutex); + while (rwlock->readers > 0) + silc_cond_wait(rwlock->cond, rwlock->mutex); + rwlock->locked = TRUE; + } +#endif /* SILC_THREADS */ +} + +void silc_rwlock_unlock(SilcRwLock rwlock) +{ +#ifdef SILC_THREADS + if (rwlock) { + if (rwlock->locked) { + /* Unlock writer */ + rwlock->locked = FALSE; + silc_mutex_unlock(rwlock->mutex); + return; + } + + /* Unlock reader */ + silc_mutex_lock(rwlock->mutex); + rwlock->readers--; + silc_cond_broadcast(rwlock->cond); + silc_mutex_unlock(rwlock->mutex); + } +#endif /* SILC_THREADS */ +} + + /**************************** SILC Cond API ******************************/ /* SILC Conditional Variable context */ @@ -294,4 +382,5 @@ SilcBool silc_cond_timedwait(SilcCond cond, SilcMutex mutex, } } #endif /* SILC_THREADS*/ + return TRUE; }