Added conditional variables.
authorPekka Riikonen <priikone@silcnet.org>
Sat, 24 Jun 2006 19:32:34 +0000 (19:32 +0000)
committerPekka Riikonen <priikone@silcnet.org>
Sat, 24 Jun 2006 19:32:34 +0000 (19:32 +0000)
lib/silcutil/DIRECTORY
lib/silcutil/silccondvar.h [new file with mode: 0644]
lib/silcutil/unix/Makefile.am
lib/silcutil/unix/silcunixmutex.c [deleted file]
lib/silcutil/unix/silcunixthread.c
lib/silcutil/win32/Makefile.am
lib/silcutil/win32/silcwin32mutex.c [deleted file]
lib/silcutil/win32/silcwin32thread.c

index 46c522ac0a64c7d2d5ae7e7f4a0b62d71ef48386..d72eb1aac2f63a76fdf99e5fda37b3800ec9c323 100644 (file)
@@ -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 (file)
index 0000000..ada9007
--- /dev/null
@@ -0,0 +1,171 @@
+/*
+
+  silccondvar.h
+
+  Author: Pekka Riikonen <priikone@silcnet.org>
+
+  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 */
index 3f7fb8c3fd913596b60ad201bc5860076e3db185..bb9719e1fc99dded7b12e465d2644f2897b01f2c 100644 (file)
@@ -3,7 +3,7 @@
 #
 #  Author: Pekka Riikonen <priikone@silcnet.org>
 #
-#  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 (file)
index 0eae149..0000000
+++ /dev/null
@@ -1,73 +0,0 @@
-/*
-
-  silcunixmutex.c
-
-  Author: Pekka Riikonen <priikone@silcnet.org>
-
-  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 */
-}
index 099d75d934865fc8846e2326482a7f232c8c1c3e..b32f61d62d6d663f4042b7d6b513ae65ea6f0dcc 100644 (file)
@@ -4,12 +4,12 @@
 
   Author: Pekka Riikonen <priikone@silcnet.org>
 
-  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*/
+}
index ed709606edd103d4a3bc251aa39729e548444b05..4bb647ad619194fb3b37fbc608da548aa0a0401d 100644 (file)
@@ -3,7 +3,7 @@
 #
 #  Author: Pekka Riikonen <priikone@silcnet.org>
 #
-#  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 (file)
index 34db890..0000000
+++ /dev/null
@@ -1,76 +0,0 @@
-/*
-
-  silcwin32mutex.c
-
-  Author: Pekka Riikonen <priikone@silcnet.org>
-
-  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 */
-}
index c31e70931381d2f68cecb669bb040f462b102839..f55a55ac8090851af7374ebb1809d16973548bff 100644 (file)
@@ -4,12 +4,12 @@
 
   Author: Pekka Riikonen <priikone@silcnet.org>
 
-  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*/
+}