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>