Annotation of embedaddon/ntp/lib/isc/win32/condition.c, revision 1.1.1.1

1.1       misho       1: /*
                      2:  * Copyright (C) 2004, 2006, 2007  Internet Systems Consortium, Inc. ("ISC")
                      3:  * Copyright (C) 1998-2001  Internet Software Consortium.
                      4:  *
                      5:  * Permission to use, copy, modify, and/or distribute this software for any
                      6:  * purpose with or without fee is hereby granted, provided that the above
                      7:  * copyright notice and this permission notice appear in all copies.
                      8:  *
                      9:  * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
                     10:  * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
                     11:  * AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
                     12:  * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
                     13:  * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
                     14:  * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
                     15:  * PERFORMANCE OF THIS SOFTWARE.
                     16:  */
                     17: 
                     18: /* $Id: condition.c,v 1.23 2007/06/18 23:47:49 tbox Exp $ */
                     19: 
                     20: #include <config.h>
                     21: 
                     22: #include <isc/condition.h>
                     23: #include <isc/assertions.h>
                     24: #include <isc/util.h>
                     25: #include <isc/thread.h>
                     26: #include <isc/time.h>
                     27: 
                     28: #define LSIGNAL                0
                     29: #define LBROADCAST     1
                     30: 
                     31: isc_result_t
                     32: isc_condition_init(isc_condition_t *cond) {
                     33:        HANDLE h;
                     34: 
                     35:        REQUIRE(cond != NULL);
                     36: 
                     37:        cond->waiters = 0;
                     38:        /*
                     39:         * This handle is shared across all threads
                     40:         */
                     41:        h = CreateEvent(NULL, FALSE, FALSE, NULL);
                     42:        if (h == NULL) {
                     43:                /* XXX */
                     44:                return (ISC_R_UNEXPECTED);
                     45:        }
                     46:        cond->events[LSIGNAL] = h;
                     47: 
                     48:        /*
                     49:         * The threadlist will hold the actual events needed
                     50:         * for the wait condition
                     51:         */
                     52:        ISC_LIST_INIT(cond->threadlist);
                     53: 
                     54:        return (ISC_R_SUCCESS);
                     55: }
                     56: 
                     57: /*
                     58:  * Add the thread to the threadlist along with the required events
                     59:  */
                     60: static isc_result_t
                     61: register_thread(unsigned long thrd, isc_condition_t *gblcond,
                     62:                isc_condition_thread_t **localcond)
                     63: {
                     64:        HANDLE hc;
                     65:        isc_condition_thread_t *newthread;
                     66: 
                     67:        REQUIRE(localcond != NULL && *localcond == NULL);
                     68: 
                     69:        newthread = malloc(sizeof(isc_condition_thread_t));
                     70:        if (newthread == NULL)
                     71:                return (ISC_R_NOMEMORY);
                     72: 
                     73:        /*
                     74:         * Create the thread-specific handle
                     75:         */
                     76:        hc = CreateEvent(NULL, FALSE, FALSE, NULL);
                     77:        if (hc == NULL) {
                     78:                free(newthread);
                     79:                return (ISC_R_UNEXPECTED);
                     80:        }
                     81: 
                     82:        /*
                     83:         * Add the thread ID and handles to list of threads for broadcast
                     84:         */
                     85:        newthread->handle[LSIGNAL] = gblcond->events[LSIGNAL];
                     86:        newthread->handle[LBROADCAST] = hc;
                     87:        newthread->th = thrd;
                     88: 
                     89:        /*
                     90:         * The thread is holding the manager lock so this is safe
                     91:         */
                     92:        ISC_LIST_APPEND(gblcond->threadlist, newthread, link);
                     93:        *localcond = newthread;
                     94:        return (ISC_R_SUCCESS);
                     95: }
                     96: 
                     97: static isc_result_t
                     98: find_thread_condition(unsigned long thrd, isc_condition_t *cond,
                     99:                      isc_condition_thread_t **threadcondp)
                    100: {
                    101:        isc_condition_thread_t *threadcond;
                    102: 
                    103:        REQUIRE(threadcondp != NULL && *threadcondp == NULL);
                    104: 
                    105:        /*
                    106:         * Look for the thread ID.
                    107:         */
                    108:        for (threadcond = ISC_LIST_HEAD(cond->threadlist);
                    109:             threadcond != NULL;
                    110:             threadcond = ISC_LIST_NEXT(threadcond, link)) {
                    111: 
                    112:                if (threadcond->th == thrd) {
                    113:                        *threadcondp = threadcond;
                    114:                        return (ISC_R_SUCCESS);
                    115:                }
                    116:        }
                    117: 
                    118:        /*
                    119:         * Not found, so add it.
                    120:         */
                    121:        return (register_thread(thrd, cond, threadcondp));
                    122: }
                    123: 
                    124: isc_result_t
                    125: isc_condition_signal(isc_condition_t *cond) {
                    126: 
                    127:        /*
                    128:         * Unlike pthreads, the caller MUST hold the lock associated with
                    129:         * the condition variable when calling us.
                    130:         */
                    131:        REQUIRE(cond != NULL);
                    132: 
                    133:        if (!SetEvent(cond->events[LSIGNAL])) {
                    134:                /* XXX */
                    135:                return (ISC_R_UNEXPECTED);
                    136:        }
                    137: 
                    138:        return (ISC_R_SUCCESS);
                    139: }
                    140: 
                    141: isc_result_t
                    142: isc_condition_broadcast(isc_condition_t *cond) {
                    143: 
                    144:        isc_condition_thread_t *threadcond;
                    145:        isc_boolean_t failed = ISC_FALSE;
                    146: 
                    147:        /*
                    148:         * Unlike pthreads, the caller MUST hold the lock associated with
                    149:         * the condition variable when calling us.
                    150:         */
                    151:        REQUIRE(cond != NULL);
                    152: 
                    153:        /*
                    154:         * Notify every thread registered for this
                    155:         */
                    156:        for (threadcond = ISC_LIST_HEAD(cond->threadlist);
                    157:             threadcond != NULL;
                    158:             threadcond = ISC_LIST_NEXT(threadcond, link)) {
                    159: 
                    160:                if (!SetEvent(threadcond->handle[LBROADCAST]))
                    161:                        failed = ISC_TRUE;
                    162:        }
                    163: 
                    164:        if (failed)
                    165:                return (ISC_R_UNEXPECTED);
                    166: 
                    167:        return (ISC_R_SUCCESS);
                    168: }
                    169: 
                    170: isc_result_t
                    171: isc_condition_destroy(isc_condition_t *cond) {
                    172: 
                    173:        isc_condition_thread_t *next, *threadcond;
                    174: 
                    175:        REQUIRE(cond != NULL);
                    176:        REQUIRE(cond->waiters == 0);
                    177: 
                    178:        (void)CloseHandle(cond->events[LSIGNAL]);
                    179: 
                    180:        /*
                    181:         * Delete the threadlist
                    182:         */
                    183:        threadcond = ISC_LIST_HEAD(cond->threadlist);
                    184: 
                    185:        while (threadcond != NULL) {
                    186:                next = ISC_LIST_NEXT(threadcond, link);
                    187:                DEQUEUE(cond->threadlist, threadcond, link);
                    188:                (void) CloseHandle(threadcond->handle[LBROADCAST]);
                    189:                free(threadcond);
                    190:                threadcond = next;
                    191:        }
                    192: 
                    193:        return (ISC_R_SUCCESS);
                    194: }
                    195: 
                    196: /*
                    197:  * This is always called when the mutex (lock) is held, but because
                    198:  * we are waiting we need to release it and reacquire it as soon as the wait
                    199:  * is over. This allows other threads to make use of the object guarded
                    200:  * by the mutex but it should never try to delete it as long as the
                    201:  * number of waiters > 0. Always reacquire the mutex regardless of the
                    202:  * result of the wait. Note that EnterCriticalSection will wait to acquire
                    203:  * the mutex.
                    204:  */
                    205: static isc_result_t
                    206: wait(isc_condition_t *cond, isc_mutex_t *mutex, DWORD milliseconds) {
                    207:        DWORD result;
                    208:        isc_result_t tresult;
                    209:        isc_condition_thread_t *threadcond = NULL;
                    210: 
                    211:        /*
                    212:         * Get the thread events needed for the wait
                    213:         */
                    214:        tresult = find_thread_condition(isc_thread_self(), cond, &threadcond);
                    215:        if (tresult !=  ISC_R_SUCCESS)
                    216:                return (tresult);
                    217: 
                    218:        cond->waiters++;
                    219:        LeaveCriticalSection(mutex);
                    220:        result = WaitForMultipleObjects(2, threadcond->handle, FALSE,
                    221:                                        milliseconds);
                    222:        EnterCriticalSection(mutex);
                    223:        cond->waiters--;
                    224:        if (result == WAIT_FAILED) {
                    225:                /* XXX */
                    226:                return (ISC_R_UNEXPECTED);
                    227:        }
                    228:        if (result == WAIT_TIMEOUT)
                    229:                return (ISC_R_TIMEDOUT);
                    230: 
                    231:        return (ISC_R_SUCCESS);
                    232: }
                    233: 
                    234: isc_result_t
                    235: isc_condition_wait(isc_condition_t *cond, isc_mutex_t *mutex) {
                    236:        return (wait(cond, mutex, INFINITE));
                    237: }
                    238: 
                    239: isc_result_t
                    240: isc_condition_waituntil(isc_condition_t *cond, isc_mutex_t *mutex,
                    241:                        isc_time_t *t) {
                    242:        DWORD milliseconds;
                    243:        isc_uint64_t microseconds;
                    244:        isc_time_t now;
                    245: 
                    246:        if (isc_time_now(&now) != ISC_R_SUCCESS) {
                    247:                /* XXX */
                    248:                return (ISC_R_UNEXPECTED);
                    249:        }
                    250: 
                    251:        microseconds = isc_time_microdiff(t, &now);
                    252:        if (microseconds > 0xFFFFFFFFi64 * 1000)
                    253:                milliseconds = 0xFFFFFFFF;
                    254:        else
                    255:                milliseconds = (DWORD)(microseconds / 1000);
                    256: 
                    257:        return (wait(cond, mutex, milliseconds));
                    258: }

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>