"Fossies" - the Fresh Open Source Software Archive

Member "bind-9.11.23/lib/isc/win32/condition.c" (7 Sep 2020, 5806 Bytes) of package /linux/misc/dns/bind9/9.11.23/bind-9.11.23.tar.gz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. For more information about "condition.c" see the Fossies "Dox" file reference documentation.

    1 /*
    2  * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
    3  *
    4  * This Source Code Form is subject to the terms of the Mozilla Public
    5  * License, v. 2.0. If a copy of the MPL was not distributed with this
    6  * file, You can obtain one at http://mozilla.org/MPL/2.0/.
    7  *
    8  * See the COPYRIGHT file distributed with this work for additional
    9  * information regarding copyright ownership.
   10  */
   11 
   12 
   13 #include <config.h>
   14 
   15 #include <inttypes.h>
   16 #include <stdbool.h>
   17 
   18 #include <isc/condition.h>
   19 #include <isc/assertions.h>
   20 #include <isc/util.h>
   21 #include <isc/thread.h>
   22 #include <isc/time.h>
   23 
   24 #define LSIGNAL     0
   25 #define LBROADCAST  1
   26 
   27 isc_result_t
   28 isc_condition_init(isc_condition_t *cond) {
   29     HANDLE h;
   30 
   31     REQUIRE(cond != NULL);
   32 
   33     cond->waiters = 0;
   34     /*
   35      * This handle is shared across all threads
   36      */
   37     h = CreateEvent(NULL, FALSE, FALSE, NULL);
   38     if (h == NULL) {
   39         /* XXX */
   40         return (ISC_R_UNEXPECTED);
   41     }
   42     cond->events[LSIGNAL] = h;
   43 
   44     /*
   45      * The threadlist will hold the actual events needed
   46      * for the wait condition
   47      */
   48     ISC_LIST_INIT(cond->threadlist);
   49 
   50     return (ISC_R_SUCCESS);
   51 }
   52 
   53 /*
   54  * Add the thread to the threadlist along with the required events
   55  */
   56 static isc_result_t
   57 register_thread(unsigned long thrd, isc_condition_t *gblcond,
   58         isc_condition_thread_t **localcond)
   59 {
   60     HANDLE hc;
   61     isc_condition_thread_t *newthread;
   62 
   63     REQUIRE(localcond != NULL && *localcond == NULL);
   64 
   65     newthread = malloc(sizeof(isc_condition_thread_t));
   66     if (newthread == NULL)
   67         return (ISC_R_NOMEMORY);
   68 
   69     /*
   70      * Create the thread-specific handle
   71      */
   72     hc = CreateEvent(NULL, FALSE, FALSE, NULL);
   73     if (hc == NULL) {
   74         free(newthread);
   75         return (ISC_R_UNEXPECTED);
   76     }
   77 
   78     /*
   79      * Add the thread ID and handles to list of threads for broadcast
   80      */
   81     newthread->handle[LSIGNAL] = gblcond->events[LSIGNAL];
   82     newthread->handle[LBROADCAST] = hc;
   83     newthread->th = thrd;
   84 
   85     /*
   86      * The thread is holding the manager lock so this is safe
   87      */
   88     ISC_LINK_INIT(newthread, link);
   89     ISC_LIST_APPEND(gblcond->threadlist, newthread, link);
   90     *localcond = newthread;
   91     return (ISC_R_SUCCESS);
   92 }
   93 
   94 static isc_result_t
   95 find_thread_condition(unsigned long thrd, isc_condition_t *cond,
   96               isc_condition_thread_t **threadcondp)
   97 {
   98     isc_condition_thread_t *threadcond;
   99 
  100     REQUIRE(threadcondp != NULL && *threadcondp == NULL);
  101 
  102     /*
  103      * Look for the thread ID.
  104      */
  105     for (threadcond = ISC_LIST_HEAD(cond->threadlist);
  106          threadcond != NULL;
  107          threadcond = ISC_LIST_NEXT(threadcond, link)) {
  108 
  109         if (threadcond->th == thrd) {
  110             *threadcondp = threadcond;
  111             return (ISC_R_SUCCESS);
  112         }
  113     }
  114 
  115     /*
  116      * Not found, so add it.
  117      */
  118     return (register_thread(thrd, cond, threadcondp));
  119 }
  120 
  121 isc_result_t
  122 isc_condition_signal(isc_condition_t *cond) {
  123 
  124     /*
  125      * Unlike pthreads, the caller MUST hold the lock associated with
  126      * the condition variable when calling us.
  127      */
  128     REQUIRE(cond != NULL);
  129 
  130     if (!SetEvent(cond->events[LSIGNAL])) {
  131         /* XXX */
  132         return (ISC_R_UNEXPECTED);
  133     }
  134 
  135     return (ISC_R_SUCCESS);
  136 }
  137 
  138 isc_result_t
  139 isc_condition_broadcast(isc_condition_t *cond) {
  140 
  141     isc_condition_thread_t *threadcond;
  142     bool failed = false;
  143 
  144     /*
  145      * Unlike pthreads, the caller MUST hold the lock associated with
  146      * the condition variable when calling us.
  147      */
  148     REQUIRE(cond != NULL);
  149 
  150     /*
  151      * Notify every thread registered for this
  152      */
  153     for (threadcond = ISC_LIST_HEAD(cond->threadlist);
  154          threadcond != NULL;
  155          threadcond = ISC_LIST_NEXT(threadcond, link)) {
  156 
  157         if (!SetEvent(threadcond->handle[LBROADCAST]))
  158             failed = true;
  159     }
  160 
  161     if (failed)
  162         return (ISC_R_UNEXPECTED);
  163 
  164     return (ISC_R_SUCCESS);
  165 }
  166 
  167 isc_result_t
  168 isc_condition_destroy(isc_condition_t *cond) {
  169 
  170     isc_condition_thread_t *next, *threadcond;
  171 
  172     REQUIRE(cond != NULL);
  173     REQUIRE(cond->waiters == 0);
  174 
  175     (void)CloseHandle(cond->events[LSIGNAL]);
  176 
  177     /*
  178      * Delete the threadlist
  179      */
  180     threadcond = ISC_LIST_HEAD(cond->threadlist);
  181 
  182     while (threadcond != NULL) {
  183         next = ISC_LIST_NEXT(threadcond, link);
  184         DEQUEUE(cond->threadlist, threadcond, link);
  185         (void) CloseHandle(threadcond->handle[LBROADCAST]);
  186         free(threadcond);
  187         threadcond = next;
  188     }
  189 
  190     return (ISC_R_SUCCESS);
  191 }
  192 
  193 /*
  194  * This is always called when the mutex (lock) is held, but because
  195  * we are waiting we need to release it and reacquire it as soon as the wait
  196  * is over. This allows other threads to make use of the object guarded
  197  * by the mutex but it should never try to delete it as long as the
  198  * number of waiters > 0. Always reacquire the mutex regardless of the
  199  * result of the wait. Note that EnterCriticalSection will wait to acquire
  200  * the mutex.
  201  */
  202 static isc_result_t
  203 wait(isc_condition_t *cond, isc_mutex_t *mutex, DWORD milliseconds) {
  204     DWORD result;
  205     isc_result_t tresult;
  206     isc_condition_thread_t *threadcond = NULL;
  207 
  208     /*
  209      * Get the thread events needed for the wait
  210      */
  211     tresult = find_thread_condition(isc_thread_self(), cond, &threadcond);
  212     if (tresult !=  ISC_R_SUCCESS)
  213         return (tresult);
  214 
  215     cond->waiters++;
  216     LeaveCriticalSection(mutex);
  217     result = WaitForMultipleObjects(2, threadcond->handle, FALSE,
  218                     milliseconds);
  219     EnterCriticalSection(mutex);
  220     cond->waiters--;
  221     if (result == WAIT_FAILED) {
  222         /* XXX */
  223         return (ISC_R_UNEXPECTED);
  224     }
  225     if (result == WAIT_TIMEOUT)
  226         return (ISC_R_TIMEDOUT);
  227 
  228     return (ISC_R_SUCCESS);
  229 }
  230 
  231 isc_result_t
  232 isc_condition_wait(isc_condition_t *cond, isc_mutex_t *mutex) {
  233     return (wait(cond, mutex, INFINITE));
  234 }
  235 
  236 isc_result_t
  237 isc_condition_waituntil(isc_condition_t *cond, isc_mutex_t *mutex,
  238             isc_time_t *t) {
  239     DWORD milliseconds;
  240     uint64_t microseconds;
  241     isc_time_t now;
  242 
  243     if (isc_time_now(&now) != ISC_R_SUCCESS) {
  244         /* XXX */
  245         return (ISC_R_UNEXPECTED);
  246     }
  247 
  248     microseconds = isc_time_microdiff(t, &now);
  249     if (microseconds > 0xFFFFFFFFi64 * 1000)
  250         milliseconds = 0xFFFFFFFF;
  251     else
  252         milliseconds = (DWORD)(microseconds / 1000);
  253 
  254     return (wait(cond, mutex, milliseconds));
  255 }