Added SilcRwLock, a read/write lock API.
[silc.git] / lib / silcutil / win32 / silcwin32thread.c
index f55a55ac8090851af7374ebb1809d16973548bff..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
@@ -153,10 +153,8 @@ SilcBool silc_thread_wait(SilcThread thread, void **exit_value)
 struct SilcMutexStruct {
 #ifdef SILC_THREADS
   CRITICAL_SECTION mutex;
-  BOOL locked;
-#else
-  void *tmp;
 #endif /* SILC_THREADS */
+  unsigned int locked : 1;
 };
 
 SilcBool silc_mutex_alloc(SilcMutex *mutex)
@@ -187,7 +185,7 @@ void silc_mutex_lock(SilcMutex mutex)
 #ifdef SILC_THREADS
   if (mutex) {
     EnterCriticalSection(&mutex->mutex);
-    assert(mutex->locked == FALSE);
+    SILC_ASSERT(mutex->locked == FALSE);
     mutex->locked = TRUE;
   }
 #endif /* SILC_THREADS */
@@ -197,18 +195,114 @@ void silc_mutex_unlock(SilcMutex mutex)
 {
 #ifdef SILC_THREADS
   if (mutex) {
-    assert(mutex->locked == TRUE);
+    SILC_ASSERT(mutex->locked == TRUE);
     mutex->locked = FALSE;
     LeaveCriticalSection(&mutex->mutex);
   }
 #endif /* SILC_THREADS */
 }
 
+void silc_mutex_assert_locked(SilcMutex mutex)
+{
+#ifdef SILC_THREADS
+  if (mutex)
+    SILC_ASSERT(mutex->locked);
+#endif /* SILC_THREADS */
+}
+
+
+/***************************** SILC Rwlock API ******************************/
 
-/**************************** SILC CondVar 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 */
-struct SilcCondVarStruct {
+struct SilcCondStruct {
 #ifdef SILC_THREADS
   HANDLE event;
 #endif /* SILC_THREADS*/
@@ -216,7 +310,7 @@ struct SilcCondVarStruct {
   unsigned int signal  : 1;
 };
 
-SilcBool silc_condvar_alloc(SilcCondVar *cond)
+SilcBool silc_cond_alloc(SilcCond *cond)
 {
 #ifdef SILC_THREADS
   *cond = silc_calloc(1, sizeof(**cond));
@@ -229,7 +323,7 @@ SilcBool silc_condvar_alloc(SilcCondVar *cond)
 #endif /* SILC_THREADS*/
 }
 
-void silc_condvar_free(SilcCondVar cond)
+void silc_cond_free(SilcCond cond)
 {
 #ifdef SILC_THREADS
   CloseHandle(cond->event);
@@ -237,7 +331,7 @@ void silc_condvar_free(SilcCondVar cond)
 #endif /* SILC_THREADS*/
 }
 
-void silc_condvar_signal(SilcCondVar cond)
+void silc_cond_signal(SilcCond cond)
 {
 #ifdef SILC_THREADS
   cond->signal = TRUE;
@@ -245,7 +339,7 @@ void silc_condvar_signal(SilcCondVar cond)
 #endif /* SILC_THREADS*/
 }
 
-void silc_condvar_broadcast(SilcCondVar cond)
+void silc_cond_broadcast(SilcCond cond)
 {
 #ifdef SILC_THREADS
   cond->signal = TRUE;
@@ -253,15 +347,15 @@ void silc_condvar_broadcast(SilcCondVar cond)
 #endif /* SILC_THREADS*/
 }
 
-void silc_condvar_wait(SilcCondVar cond, SilcMutex mutex)
+void silc_cond_wait(SilcCond cond, SilcMutex mutex)
 {
 #ifdef SILC_THREADS
-  silc_condvar_timedwait(cond, mutex, NULL);
+  silc_cond_timedwait(cond, mutex, NULL);
 #endif /* SILC_THREADS*/
 }
 
-SilcBool silc_condvar_timedwait(SilcCondVar cond, SilcMutex mutex,
-                               int timeout)
+SilcBool silc_cond_timedwait(SilcCond cond, SilcMutex mutex,
+                            int timeout)
 {
 #ifdef SILC_THREADS
   DWORD ret, t = INFINITE;
@@ -288,4 +382,5 @@ SilcBool silc_condvar_timedwait(SilcCondVar cond, SilcMutex mutex,
     }
   }
 #endif /* SILC_THREADS*/
+  return TRUE;
 }