]> git.ipfire.org Git - thirdparty/bind9.git/commitdiff
2175. [bug] win32: windows broadcast condition variable support
authorMark Andrews <marka@isc.org>
Wed, 9 May 2007 23:51:44 +0000 (23:51 +0000)
committerMark Andrews <marka@isc.org>
Wed, 9 May 2007 23:51:44 +0000 (23:51 +0000)
                        was broken. [RT #16592]

CHANGES
lib/isc/win32/condition.c
lib/isc/win32/include/isc/condition.h

diff --git a/CHANGES b/CHANGES
index e19dd085857006cc83a9fb437adc39d82ee18793..e1a2da62e5b9ece3546af5c07da49de7e7848b85 100644 (file)
--- a/CHANGES
+++ b/CHANGES
@@ -1,3 +1,6 @@
+2175.  [bug]           win32: windows broadcast condition variable support
+                       was broken. [RT #16592]
+
 2174.  [bug]           I/O errors should always be fatal when reading
                        master files. [RT #16825]
 
index c5688cd70b3fc2462212d4ff857ca765be5723ce..ae865aac4539720f1beb0886e87e8a7ca8490f7b 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2004, 2006  Internet Systems Consortium, Inc. ("ISC")
+ * Copyright (C) 2004-2007  Internet Systems Consortium, Inc. ("ISC")
  * Copyright (C) 1998-2001  Internet Software Consortium.
  *
  * Permission to use, copy, modify, and distribute this software for any
  * PERFORMANCE OF THIS SOFTWARE.
  */
 
-/* $Id: condition.c,v 1.18.18.2 2006/02/13 23:50:53 marka Exp $ */
+/* $Id: condition.c,v 1.18.18.3 2007/05/09 23:51:44 marka Exp $ */
 
 #include <config.h>
 
 #include <isc/condition.h>
 #include <isc/assertions.h>
 #include <isc/util.h>
+#include <isc/thread.h>
 #include <isc/time.h>
 
 #define LSIGNAL                0
@@ -34,23 +35,92 @@ isc_condition_init(isc_condition_t *cond) {
        REQUIRE(cond != NULL);
 
        cond->waiters = 0;
+       /*
+        * This handle is shared across all threads
+        */
        h = CreateEvent(NULL, FALSE, FALSE, NULL);
        if (h == NULL) {
                /* XXX */
                return (ISC_R_UNEXPECTED);
        }
        cond->events[LSIGNAL] = h;
-       h = CreateEvent(NULL, TRUE, FALSE, NULL);
-       if (h == NULL) {
-               (void)CloseHandle(cond->events[LSIGNAL]);
-               /* XXX */
+
+       /*
+        * The threadlist will hold the actual events needed
+        * for the wait condition
+        */
+       ISC_LIST_INIT(cond->threadlist);
+
+       return (ISC_R_SUCCESS);
+}
+
+/*
+ * Add the thread to the threadlist along with the required events
+ */
+static isc_result_t
+register_thread(unsigned long thrd, isc_condition_t *gblcond,
+               isc_condition_thread_t **localcond)
+{
+       HANDLE hc;
+       isc_condition_thread_t *newthread;
+
+       REQUIRE(localcond != NULL && *localcond == NULL);
+
+       newthread = malloc(sizeof(isc_condition_thread_t));
+       if (newthread == NULL)
+               return (ISC_R_NOMEMORY);
+
+       /*
+        * Create the thread-specific handle
+        */
+       hc = CreateEvent(NULL, FALSE, FALSE, NULL);
+       if (hc == NULL) {
+               free(newthread);
                return (ISC_R_UNEXPECTED);
        }
-       cond->events[LBROADCAST] = h;
 
+       /*
+        * Add the thread ID and handles to list of threads for broadcast
+        */
+       newthread->handle[LSIGNAL] = gblcond->events[LSIGNAL];
+       newthread->handle[LBROADCAST] = hc;
+       newthread->th = thrd;
+
+       /*
+        * The thread is holding the manager lock so this is safe
+        */
+       ISC_LIST_APPEND(gblcond->threadlist, newthread, link);
+       *localcond = newthread;
        return (ISC_R_SUCCESS);
 }
 
+static isc_result_t
+find_thread_condition(unsigned long thrd, isc_condition_t *cond,
+                     isc_condition_thread_t **threadcondp)
+{
+       isc_condition_thread_t *threadcond;
+
+       REQUIRE(threadcondp != NULL && *threadcondp == NULL);
+
+       /*
+        * Look for the thread ID.
+        */
+       for (threadcond = ISC_LIST_HEAD(cond->threadlist);
+            threadcond != NULL;
+            threadcond = ISC_LIST_NEXT(threadcond, link)) {
+
+               if (threadcond->th == thrd) {
+                       *threadcondp = threadcond;
+                       return (ISC_R_SUCCESS);
+               }
+       }
+
+       /*
+        * Not found, so add it.
+        */
+       return (register_thread(thrd, cond, threadcondp));
+}
+
 isc_result_t
 isc_condition_signal(isc_condition_t *cond) {
 
@@ -60,8 +130,7 @@ isc_condition_signal(isc_condition_t *cond) {
         */
        REQUIRE(cond != NULL);
 
-       if (cond->waiters > 0 &&
-           !SetEvent(cond->events[LSIGNAL])) {
+       if (!SetEvent(cond->events[LSIGNAL])) {
                /* XXX */
                return (ISC_R_UNEXPECTED);
        }
@@ -72,29 +141,54 @@ isc_condition_signal(isc_condition_t *cond) {
 isc_result_t
 isc_condition_broadcast(isc_condition_t *cond) {
 
+       isc_condition_thread_t *threadcond;
+       isc_boolean_t failed = ISC_FALSE;
+
        /*
         * Unlike pthreads, the caller MUST hold the lock associated with
         * the condition variable when calling us.
         */
        REQUIRE(cond != NULL);
 
-       if (cond->waiters > 0 &&
-           !SetEvent(cond->events[LBROADCAST])) {
-               /* XXX */
-               return (ISC_R_UNEXPECTED);
+       /*
+        * Notify every thread registered for this
+        */
+       for (threadcond = ISC_LIST_HEAD(cond->threadlist);
+            threadcond != NULL;
+            threadcond = ISC_LIST_NEXT(threadcond, link)) {
+
+               if (!SetEvent(threadcond->handle[LBROADCAST]))
+                       failed = ISC_TRUE;
        }
 
+       if (failed)
+               return (ISC_R_UNEXPECTED);
+
        return (ISC_R_SUCCESS);
 }
 
 isc_result_t
 isc_condition_destroy(isc_condition_t *cond) {
 
+       isc_condition_thread_t *next, *threadcond;
+
        REQUIRE(cond != NULL);
        REQUIRE(cond->waiters == 0);
 
        (void)CloseHandle(cond->events[LSIGNAL]);
-       (void)CloseHandle(cond->events[LBROADCAST]);
+
+       /*
+        * Delete the threadlist
+        */
+       threadcond = ISC_LIST_HEAD(cond->threadlist);
+
+       while (threadcond != NULL) {
+               next = ISC_LIST_NEXT(threadcond, link);
+               DEQUEUE(cond->threadlist, threadcond, link);
+               (void) CloseHandle(threadcond->handle[LBROADCAST]);
+               free(threadcond);
+               threadcond = next;
+       }
 
        return (ISC_R_SUCCESS);
 }
@@ -111,22 +205,26 @@ isc_condition_destroy(isc_condition_t *cond) {
 static isc_result_t
 wait(isc_condition_t *cond, isc_mutex_t *mutex, DWORD milliseconds) {
        DWORD result;
+       isc_result_t tresult;
+       isc_condition_thread_t *threadcond = NULL;
+
+       /*
+        * Get the thread events needed for the wait
+        */
+       tresult = find_thread_condition(isc_thread_self(), cond, &threadcond);
+       if (tresult !=  ISC_R_SUCCESS)
+               return (tresult);
 
        cond->waiters++;
        LeaveCriticalSection(mutex);
-       result = WaitForMultipleObjects(2, cond->events, FALSE, milliseconds);
+       result = WaitForMultipleObjects(2, threadcond->handle, FALSE,
+                                       milliseconds);
        EnterCriticalSection(mutex);
        cond->waiters--;
        if (result == WAIT_FAILED) {
                /* XXX */
                return (ISC_R_UNEXPECTED);
        }
-       if (cond->waiters == 0 &&
-           !ResetEvent(cond->events[LBROADCAST])) {
-               /* XXX */
-               return (ISC_R_UNEXPECTED);
-       }
-
        if (result == WAIT_TIMEOUT)
                return (ISC_R_TIMEDOUT);
 
index fff62ac5958a979f3066ee356877fe960c5dc749..c018cae0777490e81e1358e84849119617a9ac0e 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2004  Internet Systems Consortium, Inc. ("ISC")
+ * Copyright (C) 2004-2007  Internet Systems Consortium, Inc. ("ISC")
  * Copyright (C) 1998-2001  Internet Software Consortium.
  *
  * Permission to use, copy, modify, and distribute this software for any
@@ -15,7 +15,7 @@
  * PERFORMANCE OF THIS SOFTWARE.
  */
 
-/* $Id: condition.h,v 1.14 2004/03/05 05:12:05 marka Exp $ */
+/* $Id: condition.h,v 1.14.18.1 2007/05/09 23:51:44 marka Exp $ */
 
 #ifndef ISC_CONDITION_H
 #define ISC_CONDITION_H 1
 
 #include <isc/lang.h>
 #include <isc/mutex.h>
+#include <isc/thread.h>
 #include <isc/types.h>
 
+typedef struct isc_condition_thread isc_condition_thread_t;
+
+struct isc_condition_thread {
+       unsigned long                           th;
+       HANDLE                                  handle[2];
+       ISC_LINK(isc_condition_thread_t)        link;
+
+};
+
 typedef struct isc_condition {
        HANDLE          events[2];
        unsigned int    waiters;
+       ISC_LIST(isc_condition_thread_t) threadlist;
 } isc_condition_t;
 
 ISC_LANG_BEGINDECLS