Added SilcRwLock, a read/write lock API.
authorPekka Riikonen <priikone@silcnet.org>
Mon, 29 Jan 2007 16:03:51 +0000 (16:03 +0000)
committerPekka Riikonen <priikone@silcnet.org>
Mon, 29 Jan 2007 16:03:51 +0000 (16:03 +0000)
CHANGES
TODO
lib/silcutil/silcmutex.h
lib/silcutil/symbian/silcsymbianthread.cpp
lib/silcutil/unix/silcunixthread.c
lib/silcutil/win32/silcwin32thread.c

diff --git a/CHANGES b/CHANGES
index ce0636bb48f11187f484ed3a1963ff4ac8c697ea..c8a43fb7f34ba00d2174aa43ad8c571198b97122 100644 (file)
--- a/CHANGES
+++ b/CHANGES
@@ -1,3 +1,8 @@
+Sat Jan 27 22:37:30 EET 2007  Pekka Riikonen <priikone@silcnet.org>
+
+       * 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 <priikone@silcnet.org>
 
        * 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 <priikone@silcnet.org>
 
        * 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 <priikone@silcnet.org>
diff --git a/TODO b/TODO
index 1d77eafbfbfee7028905701b1eeed73c7ab74b2a..5e7ca9a28db9c1f65f6055c0be283569f4e63237 100644 (file)
--- 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
index 37f08add5715266a1c68e573538527f9956e1a65..82a9da3922130fb76549f8424ed67fefc52896ed 100644 (file)
@@ -4,7 +4,7 @@
 
   Author: Pekka Riikonen <priikone@silcnet.org>
 
-  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.
  *
  ***/
 
  ***/
 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
index 7e134e527d13281ec9880ca8fd69b7595f36e9be..d4d788dc81824f279bd001b94752968c00650561 100644 (file)
@@ -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 *******************************/
 
index 7f52de901daca7baafd9d1c1bca4aaf949e52ad3..6e85dd743981702723a8f34e7a006d3eb8ef73d4 100644 (file)
@@ -4,7 +4,7 @@
 
   Author: Pekka Riikonen <priikone@silcnet.org>
 
-  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 *******************************/
 
index 97e516bcc6ceeea5d3ede7bda015767c75458729..d54a13e6c83088fd13ca9f8be2c359e5f7fa5d5c 100644 (file)
@@ -4,7 +4,7 @@
 
   Author: Pekka Riikonen <priikone@silcnet.org>
 
-  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;
 }