"Fossies" - the Fresh Open Source Software Archive

Member "bind-9.16.7/lib/isc/win32/condition.c" (4 Sep 2020, 5958 Bytes) of package /linux/misc/dns/bind9/9.16.7/bind-9.16.7.tar.xz:


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 #include <inttypes.h>
   13 #include <stdbool.h>
   14 
   15 #include <isc/assertions.h>
   16 #include <isc/condition.h>
   17 #include <isc/error.h>
   18 #include <isc/strerr.h>
   19 #include <isc/thread.h>
   20 #include <isc/time.h>
   21 #include <isc/util.h>
   22 
   23 #define LSIGNAL    0
   24 #define LBROADCAST 1
   25 
   26 void
   27 isc_condition_init(isc_condition_t *cond) {
   28     HANDLE h;
   29 
   30     REQUIRE(cond != NULL);
   31 
   32     cond->waiters = 0;
   33     /*
   34      * This handle is shared across all threads
   35      */
   36     h = CreateEvent(NULL, FALSE, FALSE, NULL);
   37     if (h == NULL) {
   38         char strbuf[ISC_STRERRORSIZE];
   39         DWORD err = GetLastError();
   40         strerror_r(err, strbuf, sizeof(strbuf));
   41         isc_error_fatal(__FILE__, __LINE__, "CreateEvent failed: %s",
   42                 strbuf);
   43     }
   44     cond->events[LSIGNAL] = h;
   45 
   46     /*
   47      * The threadlist will hold the actual events needed
   48      * for the wait condition
   49      */
   50     ISC_LIST_INIT(cond->threadlist);
   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     HANDLE hc;
   60     isc_condition_thread_t *newthread;
   61 
   62     REQUIRE(localcond != NULL && *localcond == NULL);
   63 
   64     newthread = malloc(sizeof(isc_condition_thread_t));
   65     if (newthread == NULL) {
   66         return (ISC_R_NOMEMORY);
   67     }
   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     isc_condition_thread_t *threadcond;
   98 
   99     REQUIRE(threadcondp != NULL && *threadcondp == NULL);
  100 
  101     /*
  102      * Look for the thread ID.
  103      */
  104     for (threadcond = ISC_LIST_HEAD(cond->threadlist); threadcond != NULL;
  105          threadcond = ISC_LIST_NEXT(threadcond, link))
  106     {
  107         if (threadcond->th == thrd) {
  108             *threadcondp = threadcond;
  109             return (ISC_R_SUCCESS);
  110         }
  111     }
  112 
  113     /*
  114      * Not found, so add it.
  115      */
  116     return (register_thread(thrd, cond, threadcondp));
  117 }
  118 
  119 isc_result_t
  120 isc_condition_signal(isc_condition_t *cond) {
  121     /*
  122      * Unlike pthreads, the caller MUST hold the lock associated with
  123      * the condition variable when calling us.
  124      */
  125     REQUIRE(cond != NULL);
  126 
  127     if (!SetEvent(cond->events[LSIGNAL])) {
  128         /* XXX */
  129         return (ISC_R_UNEXPECTED);
  130     }
  131     return (ISC_R_SUCCESS);
  132 }
  133 
  134 isc_result_t
  135 isc_condition_broadcast(isc_condition_t *cond) {
  136     isc_condition_thread_t *threadcond;
  137     bool failed = false;
  138 
  139     /*
  140      * Unlike pthreads, the caller MUST hold the lock associated with
  141      * the condition variable when calling us.
  142      */
  143     REQUIRE(cond != NULL);
  144 
  145     /*
  146      * Notify every thread registered for this
  147      */
  148     for (threadcond = ISC_LIST_HEAD(cond->threadlist); threadcond != NULL;
  149          threadcond = ISC_LIST_NEXT(threadcond, link))
  150     {
  151         if (!SetEvent(threadcond->handle[LBROADCAST])) {
  152             failed = true;
  153         }
  154     }
  155 
  156     if (failed) {
  157         return (ISC_R_UNEXPECTED);
  158     }
  159 
  160     return (ISC_R_SUCCESS);
  161 }
  162 
  163 isc_result_t
  164 isc_condition_destroy(isc_condition_t *cond) {
  165     isc_condition_thread_t *next, *threadcond;
  166 
  167     REQUIRE(cond != NULL);
  168     REQUIRE(cond->waiters == 0);
  169 
  170     (void)CloseHandle(cond->events[LSIGNAL]);
  171 
  172     /*
  173      * Delete the threadlist
  174      */
  175     threadcond = ISC_LIST_HEAD(cond->threadlist);
  176 
  177     while (threadcond != NULL) {
  178         next = ISC_LIST_NEXT(threadcond, link);
  179         DEQUEUE(cond->threadlist, threadcond, link);
  180         (void)CloseHandle(threadcond->handle[LBROADCAST]);
  181         free(threadcond);
  182         threadcond = next;
  183     }
  184 
  185     return (ISC_R_SUCCESS);
  186 }
  187 
  188 /*
  189  * This is always called when the mutex (lock) is held, but because
  190  * we are waiting we need to release it and reacquire it as soon as the wait
  191  * is over. This allows other threads to make use of the object guarded
  192  * by the mutex but it should never try to delete it as long as the
  193  * number of waiters > 0. Always reacquire the mutex regardless of the
  194  * result of the wait. Note that EnterCriticalSection will wait to acquire
  195  * the mutex.
  196  */
  197 static isc_result_t
  198 wait(isc_condition_t *cond, isc_mutex_t *mutex, DWORD milliseconds) {
  199     DWORD result;
  200     isc_result_t tresult;
  201     isc_condition_thread_t *threadcond = NULL;
  202 
  203     /*
  204      * Get the thread events needed for the wait
  205      */
  206     tresult = find_thread_condition(isc_thread_self(), cond, &threadcond);
  207     if (tresult != ISC_R_SUCCESS) {
  208         return (tresult);
  209     }
  210 
  211     cond->waiters++;
  212     LeaveCriticalSection(mutex);
  213     result = WaitForMultipleObjects(2, threadcond->handle, FALSE,
  214                     milliseconds);
  215     EnterCriticalSection(mutex);
  216     cond->waiters--;
  217     if (result == WAIT_FAILED) {
  218         /* XXX */
  219         return (ISC_R_UNEXPECTED);
  220     }
  221     if (result == WAIT_TIMEOUT) {
  222         return (ISC_R_TIMEDOUT);
  223     }
  224 
  225     return (ISC_R_SUCCESS);
  226 }
  227 
  228 isc_result_t
  229 isc_condition_wait(isc_condition_t *cond, isc_mutex_t *mutex) {
  230     return (wait(cond, mutex, INFINITE));
  231 }
  232 
  233 isc_result_t
  234 isc_condition_waituntil(isc_condition_t *cond, isc_mutex_t *mutex,
  235             isc_time_t *t) {
  236     DWORD milliseconds;
  237     uint64_t microseconds;
  238     isc_time_t now;
  239 
  240     if (isc_time_now(&now) != ISC_R_SUCCESS) {
  241         /* XXX */
  242         return (ISC_R_UNEXPECTED);
  243     }
  244 
  245     microseconds = isc_time_microdiff(t, &now);
  246     if (microseconds > 0xFFFFFFFFi64 * 1000) {
  247         milliseconds = 0xFFFFFFFF;
  248     } else {
  249         milliseconds = (DWORD)(microseconds / 1000);
  250     }
  251 
  252     return (wait(cond, mutex, milliseconds));
  253 }