Annotation of embedaddon/ntp/lib/isc/win32/condition.c, revision 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>