2 * wait.c: wait for handles to become signalled
5 * Dick Porter (dick@ximian.com)
7 * (C) 2002 Ximian, Inc.
15 #include <mono/os/gc_wrapper.h>
17 #include <mono/io-layer/wapi.h>
18 #include <mono/io-layer/handles-private.h>
19 #include <mono/io-layer/wapi-private.h>
20 #include <mono/io-layer/mono-mutex.h>
21 #include <mono/io-layer/misc-private.h>
26 * WaitForSingleObject:
27 * @handle: an object to wait for
28 * @timeout: the maximum time in milliseconds to wait for
30 * This function returns when either @handle is signalled, or @timeout
31 * ms elapses. If @timeout is zero, the object's state is tested and
32 * the function returns immediately. If @timeout is %INFINITE, the
33 * function waits forever.
35 * Return value: %WAIT_ABANDONED - @handle is a mutex that was not
36 * released by the owning thread when it exited. Ownership of the
37 * mutex object is granted to the calling thread and the mutex is set
38 * to nonsignalled. %WAIT_OBJECT_0 - The state of @handle is
39 * signalled. %WAIT_TIMEOUT - The @timeout interval elapsed and
40 * @handle's state is still not signalled. %WAIT_FAILED - an error
43 guint32 WaitForSingleObject(gpointer handle, guint32 timeout)
46 struct timespec abstime;
48 if(_wapi_handle_test_capabilities (handle,
49 WAPI_HANDLE_CAP_WAIT)==FALSE) {
51 g_message (G_GNUC_PRETTY_FUNCTION
52 ": handle %p can't be waited for", handle);
59 g_message (G_GNUC_PRETTY_FUNCTION ": locking handle %p", handle);
62 _wapi_handle_lock_handle (handle);
64 if(_wapi_handle_test_capabilities (handle,
65 WAPI_HANDLE_CAP_OWN)==TRUE) {
66 if(_wapi_handle_ops_isowned (handle)==TRUE) {
68 g_message (G_GNUC_PRETTY_FUNCTION
69 ": handle %p already owned", handle);
71 _wapi_handle_ops_own (handle);
77 if(_wapi_handle_issignalled (handle)) {
79 g_message (G_GNUC_PRETTY_FUNCTION
80 ": handle %p already signalled", handle);
83 _wapi_handle_ops_own (handle);
88 /* Have to wait for it */
89 if(timeout!=INFINITE) {
90 _wapi_calc_timeout (&abstime, timeout);
94 if(timeout==INFINITE) {
95 waited=_wapi_handle_wait_signal_handle (handle);
97 waited=_wapi_handle_timedwait_signal_handle (handle,
102 /* Condition was signalled, so hopefully
103 * handle is signalled now. (It might not be
104 * if someone else got in before us.)
106 if(_wapi_handle_issignalled (handle)) {
108 g_message (G_GNUC_PRETTY_FUNCTION
109 ": handle %p signalled", handle);
112 _wapi_handle_ops_own (handle);
117 /* Better luck next time */
121 /* Timeout or other error */
123 g_message (G_GNUC_PRETTY_FUNCTION ": wait on handle %p error: %s",
124 handle, strerror (ret));
132 g_message (G_GNUC_PRETTY_FUNCTION ": unlocking handle %p", handle);
135 _wapi_handle_unlock_handle (handle);
140 * SignalObjectAndWait:
141 * @signal_handle: An object to signal
142 * @wait: An object to wait for
143 * @timeout: The maximum time in milliseconds to wait for
144 * @alertable: Specifies whether the function returnes when the system
145 * queues an I/O completion routine or an APC for the calling thread.
147 * Atomically signals @signal and waits for @wait to become signalled,
148 * or @timeout ms elapses. If @timeout is zero, the object's state is
149 * tested and the function returns immediately. If @timeout is
150 * %INFINITE, the function waits forever.
152 * @signal can be a semaphore, mutex or event object.
154 * If @alertable is %TRUE and the system queues an I/O completion
155 * routine or an APC for the calling thread, the function returns and
156 * the thread calls the completion routine or APC function. If
157 * %FALSE, the function does not return, and the thread does not call
158 * the completion routine or APC function. A completion routine is
159 * queued when the ReadFileEx() or WriteFileEx() function in which it
160 * was specified has completed. The calling thread is the thread that
161 * initiated the read or write operation. An APC is queued when
162 * QueueUserAPC() is called. Currently completion routines and APC
163 * functions are not supported.
165 * Return value: %WAIT_ABANDONED - @wait is a mutex that was not
166 * released by the owning thread when it exited. Ownershop of the
167 * mutex object is granted to the calling thread and the mutex is set
168 * to nonsignalled. %WAIT_IO_COMPLETION - the wait was ended by one
169 * or more user-mode asynchronous procedure calls queued to the
170 * thread. %WAIT_OBJECT_0 - The state of @wait is signalled.
171 * %WAIT_TIMEOUT - The @timeout interval elapsed and @wait's state is
172 * still not signalled. %WAIT_FAILED - an error occurred.
174 guint32 SignalObjectAndWait(gpointer signal_handle, gpointer wait,
175 guint32 timeout, gboolean alertable)
178 struct timespec abstime;
180 if(_wapi_handle_test_capabilities (signal_handle,
181 WAPI_HANDLE_CAP_SIGNAL)==FALSE) {
185 if(_wapi_handle_test_capabilities (wait,
186 WAPI_HANDLE_CAP_WAIT)==FALSE) {
191 g_message (G_GNUC_PRETTY_FUNCTION ": locking handle %p", wait);
194 _wapi_handle_lock_handle (wait);
196 _wapi_handle_ops_signal (signal_handle);
198 if(_wapi_handle_test_capabilities (wait, WAPI_HANDLE_CAP_OWN)==TRUE) {
199 if(_wapi_handle_ops_isowned (wait)==TRUE) {
201 g_message (G_GNUC_PRETTY_FUNCTION
202 ": handle %p already owned", wait);
204 _wapi_handle_ops_own (wait);
210 if(_wapi_handle_issignalled (wait)) {
212 g_message (G_GNUC_PRETTY_FUNCTION
213 ": handle %p already signalled", wait);
216 _wapi_handle_ops_own (wait);
221 /* Have to wait for it */
222 if(timeout!=INFINITE) {
223 _wapi_calc_timeout (&abstime, timeout);
227 if(timeout==INFINITE) {
228 waited=_wapi_handle_wait_signal_handle (wait);
230 waited=_wapi_handle_timedwait_signal_handle (wait,
235 /* Condition was signalled, so hopefully
236 * handle is signalled now. (It might not be
237 * if someone else got in before us.)
239 if(_wapi_handle_issignalled (wait)) {
241 g_message (G_GNUC_PRETTY_FUNCTION
242 ": handle %p signalled", wait);
245 _wapi_handle_ops_own (wait);
250 /* Better luck next time */
254 /* Timeout or other error */
256 g_message (G_GNUC_PRETTY_FUNCTION ": wait on handle %p error: %s",
257 wait, strerror (ret));
265 g_message (G_GNUC_PRETTY_FUNCTION ": unlocking handle %p", wait);
268 _wapi_handle_unlock_handle (wait);
270 if(alertable==TRUE) {
271 /* Deal with queued APC or IO completion routines */
278 * WaitForMultipleObjects:
279 * @numobjects: The number of objects in @handles. The maximum allowed
280 * is %MAXIMUM_WAIT_OBJECTS.
281 * @handles: An array of object handles. Duplicates are not allowed.
282 * @waitall: If %TRUE, this function waits until all of the handles
283 * are signalled. If %FALSE, this function returns when any object is
285 * @timeout: The maximum time in milliseconds to wait for.
287 * This function returns when either one or more of @handles is
288 * signalled, or @timeout ms elapses. If @timeout is zero, the state
289 * of each item of @handles is tested and the function returns
290 * immediately. If @timeout is %INFINITE, the function waits forever.
292 * Return value: %WAIT_OBJECT_0 to %WAIT_OBJECT_0 + @numobjects - 1 -
293 * if @waitall is %TRUE, indicates that all objects are signalled. If
294 * @waitall is %FALSE, the return value minus %WAIT_OBJECT_0 indicates
295 * the first index into @handles of the objects that are signalled.
296 * %WAIT_ABANDONED_0 to %WAIT_ABANDONED_0 + @numobjects - 1 - if
297 * @waitall is %TRUE, indicates that all objects are signalled, and at
298 * least one object is an abandoned mutex object (See
299 * WaitForSingleObject() for a description of abandoned mutexes.) If
300 * @waitall is %FALSE, the return value minus %WAIT_ABANDONED_0
301 * indicates the first index into @handles of an abandoned mutex.
302 * %WAIT_TIMEOUT - The @timeout interval elapsed and no objects in
303 * @handles are signalled. %WAIT_FAILED - an error occurred.
305 guint32 WaitForMultipleObjects(guint32 numobjects, gpointer *handles,
306 gboolean waitall, guint32 timeout)
309 gboolean duplicate=FALSE, bogustype=FALSE, done;
310 guint32 count, lowest;
311 struct timespec abstime;
315 if(numobjects>MAXIMUM_WAIT_OBJECTS) {
317 g_message(G_GNUC_PRETTY_FUNCTION ": Too many handles: %d",
324 if (numobjects == 1) {
325 return WaitForSingleObject (handles [0], timeout);
328 /* Check for duplicates */
329 dups=g_hash_table_new(g_direct_hash, g_direct_equal);
330 for(i=0; i<numobjects; i++) {
331 gpointer exists=g_hash_table_lookup(dups, handles[i]);
334 g_message(G_GNUC_PRETTY_FUNCTION
335 ": Handle %p duplicated", handles[i]);
342 if(_wapi_handle_test_capabilities (handles[i], WAPI_HANDLE_CAP_WAIT)==FALSE) {
344 g_message (G_GNUC_PRETTY_FUNCTION
345 ": Handle %p can't be waited for",
352 g_hash_table_insert(dups, handles[i], handles[i]);
354 g_hash_table_destroy(dups);
356 if(duplicate==TRUE) {
358 g_message(G_GNUC_PRETTY_FUNCTION
359 ": Returning due to duplicates");
365 if(bogustype==TRUE) {
367 g_message(G_GNUC_PRETTY_FUNCTION
368 ": Returning due to bogus type");
375 g_message (G_GNUC_PRETTY_FUNCTION ": locking handles");
378 done=_wapi_handle_count_signalled_handles (numobjects, handles,
379 waitall, &count, &lowest);
381 for(i=0; i<numobjects; i++) {
382 _wapi_handle_ops_own (handles[i]);
386 g_message (G_GNUC_PRETTY_FUNCTION ": unlocking handles");
389 _wapi_handle_unlock_handles (numobjects, handles);
390 return(WAIT_OBJECT_0+lowest);
393 /* Have to wait for some or all handles to become signalled
397 g_message (G_GNUC_PRETTY_FUNCTION ": unlocking handles");
400 _wapi_handle_unlock_handles (numobjects, handles);
402 if(timeout!=INFINITE) {
403 _wapi_calc_timeout (&abstime, timeout);
408 g_message (G_GNUC_PRETTY_FUNCTION ": locking signal mutex");
411 _wapi_handle_lock_signal_mutex ();
413 if(timeout==INFINITE) {
414 ret=_wapi_handle_wait_signal ();
416 ret=_wapi_handle_timedwait_signal (&abstime);
420 g_message (G_GNUC_PRETTY_FUNCTION ": unlocking signal mutex");
423 _wapi_handle_unlock_signal_mutex ();
426 /* Something was signalled ... */
427 done=_wapi_handle_count_signalled_handles (numobjects,
433 for(i=0; i<numobjects; i++) {
434 _wapi_handle_ops_own (handles[i]);
438 g_message (G_GNUC_PRETTY_FUNCTION ": unlocking handles");
441 _wapi_handle_unlock_handles (numobjects,
444 return(WAIT_OBJECT_0+lowest);
448 g_message (G_GNUC_PRETTY_FUNCTION ": unlocking handles");
451 _wapi_handle_unlock_handles (numobjects, handles);
453 /* Timeout or other error */
455 g_message (G_GNUC_PRETTY_FUNCTION ": wait returned error: %s", strerror (ret));
459 return(WAIT_TIMEOUT);