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>