2 * wait.c: wait for handles to become signalled
5 * Dick Porter (dick@ximian.com)
7 * (C) 2002 Ximian, Inc.
19 #include <mono/io-layer/wapi.h>
20 #include <mono/io-layer/handles-private.h>
21 #include <mono/io-layer/wapi-private.h>
22 #include <mono/io-layer/mono-mutex.h>
23 #include <mono/io-layer/misc-private.h>
28 * WaitForSingleObject:
29 * @handle: an object to wait for
30 * @timeout: the maximum time in milliseconds to wait for
32 * This function returns when either @handle is signalled, or @timeout
33 * ms elapses. If @timeout is zero, the object's state is tested and
34 * the function returns immediately. If @timeout is %INFINITE, the
35 * function waits forever.
37 * Return value: %WAIT_ABANDONED - @handle is a mutex that was not
38 * released by the owning thread when it exited. Ownership of the
39 * mutex object is granted to the calling thread and the mutex is set
40 * to nonsignalled. %WAIT_OBJECT_0 - The state of @handle is
41 * signalled. %WAIT_TIMEOUT - The @timeout interval elapsed and
42 * @handle's state is still not signalled. %WAIT_FAILED - an error
45 guint32 WaitForSingleObject(gpointer handle, guint32 timeout)
48 struct timespec abstime;
50 if(_wapi_handle_test_capabilities (handle,
51 WAPI_HANDLE_CAP_WAIT)==FALSE) {
53 g_message (G_GNUC_PRETTY_FUNCTION
54 ": handle %p can't be waited for", handle);
60 _wapi_handle_lock_handle (handle);
62 if(_wapi_handle_test_capabilities (handle,
63 WAPI_HANDLE_CAP_OWN)==TRUE) {
64 if(_wapi_handle_ops_isowned (handle)==TRUE) {
66 g_message (G_GNUC_PRETTY_FUNCTION
67 ": handle %p already owned", handle);
69 _wapi_handle_ops_own (handle);
75 if(_wapi_handle_issignalled (handle)) {
77 g_message (G_GNUC_PRETTY_FUNCTION
78 ": handle %p already signalled", handle);
81 _wapi_handle_ops_own (handle);
86 /* Have to wait for it */
87 if(timeout!=INFINITE) {
88 _wapi_calc_timeout (&abstime, timeout);
92 if(timeout==INFINITE) {
93 waited=_wapi_handle_wait_signal_handle (handle);
95 waited=_wapi_handle_timedwait_signal_handle (handle,
100 /* Condition was signalled, so hopefully
101 * handle is signalled now. (It might not be
102 * if someone else got in before us.)
104 if(_wapi_handle_issignalled (handle)) {
106 g_message (G_GNUC_PRETTY_FUNCTION
107 ": handle %p signalled", handle);
110 _wapi_handle_ops_own (handle);
115 /* Better luck next time */
119 /* Timeout or other error */
121 g_message (G_GNUC_PRETTY_FUNCTION ": wait on handle %p error: %s",
122 handle, strerror (ret));
128 _wapi_handle_unlock_handle (handle);
133 * SignalObjectAndWait:
134 * @signal_handle: An object to signal
135 * @wait: An object to wait for
136 * @timeout: The maximum time in milliseconds to wait for
137 * @alertable: Specifies whether the function returnes when the system
138 * queues an I/O completion routine or an APC for the calling thread.
140 * Atomically signals @signal and waits for @wait to become signalled,
141 * or @timeout ms elapses. If @timeout is zero, the object's state is
142 * tested and the function returns immediately. If @timeout is
143 * %INFINITE, the function waits forever.
145 * @signal can be a semaphore, mutex or event object.
147 * If @alertable is %TRUE and the system queues an I/O completion
148 * routine or an APC for the calling thread, the function returns and
149 * the thread calls the completion routine or APC function. If
150 * %FALSE, the function does not return, and the thread does not call
151 * the completion routine or APC function. A completion routine is
152 * queued when the ReadFileEx() or WriteFileEx() function in which it
153 * was specified has completed. The calling thread is the thread that
154 * initiated the read or write operation. An APC is queued when
155 * QueueUserAPC() is called. Currently completion routines and APC
156 * functions are not supported.
158 * Return value: %WAIT_ABANDONED - @wait is a mutex that was not
159 * released by the owning thread when it exited. Ownershop of the
160 * mutex object is granted to the calling thread and the mutex is set
161 * to nonsignalled. %WAIT_IO_COMPLETION - the wait was ended by one
162 * or more user-mode asynchronous procedure calls queued to the
163 * thread. %WAIT_OBJECT_0 - The state of @wait is signalled.
164 * %WAIT_TIMEOUT - The @timeout interval elapsed and @wait's state is
165 * still not signalled. %WAIT_FAILED - an error occurred.
167 guint32 SignalObjectAndWait(gpointer signal_handle, gpointer wait,
168 guint32 timeout, gboolean alertable)
171 struct timespec abstime;
173 if(_wapi_handle_test_capabilities (signal_handle,
174 WAPI_HANDLE_CAP_SIGNAL)==FALSE) {
178 if(_wapi_handle_test_capabilities (wait,
179 WAPI_HANDLE_CAP_WAIT)==FALSE) {
183 _wapi_handle_lock_handle (wait);
185 _wapi_handle_ops_signal (signal_handle);
187 if(_wapi_handle_test_capabilities (wait, WAPI_HANDLE_CAP_OWN)==TRUE) {
188 if(_wapi_handle_ops_isowned (wait)==TRUE) {
190 g_message (G_GNUC_PRETTY_FUNCTION
191 ": handle %p already owned", wait);
193 _wapi_handle_ops_own (wait);
199 if(_wapi_handle_issignalled (wait)) {
201 g_message (G_GNUC_PRETTY_FUNCTION
202 ": handle %p already signalled", wait);
205 _wapi_handle_ops_own (wait);
210 /* Have to wait for it */
211 if(timeout!=INFINITE) {
212 _wapi_calc_timeout (&abstime, timeout);
216 if(timeout==INFINITE) {
217 waited=_wapi_handle_wait_signal_handle (wait);
219 waited=_wapi_handle_timedwait_signal_handle (wait,
224 /* Condition was signalled, so hopefully
225 * handle is signalled now. (It might not be
226 * if someone else got in before us.)
228 if(_wapi_handle_issignalled (wait)) {
230 g_message (G_GNUC_PRETTY_FUNCTION
231 ": handle %p signalled", wait);
234 _wapi_handle_ops_own (wait);
239 /* Better luck next time */
243 /* Timeout or other error */
245 g_message (G_GNUC_PRETTY_FUNCTION ": wait on handle %p error: %s",
246 wait, strerror (ret));
252 _wapi_handle_unlock_handle (wait);
254 if(alertable==TRUE) {
255 /* Deal with queued APC or IO completion routines */
262 * WaitForMultipleObjects:
263 * @numobjects: The number of objects in @handles. The maximum allowed
264 * is %MAXIMUM_WAIT_OBJECTS.
265 * @handles: An array of object handles. Duplicates are not allowed.
266 * @waitall: If %TRUE, this function waits until all of the handles
267 * are signalled. If %FALSE, this function returns when any object is
269 * @timeout: The maximum time in milliseconds to wait for.
271 * This function returns when either one or more of @handles is
272 * signalled, or @timeout ms elapses. If @timeout is zero, the state
273 * of each item of @handles is tested and the function returns
274 * immediately. If @timeout is %INFINITE, the function waits forever.
276 * Return value: %WAIT_OBJECT_0 to %WAIT_OBJECT_0 + @numobjects - 1 -
277 * if @waitall is %TRUE, indicates that all objects are signalled. If
278 * @waitall is %FALSE, the return value minus %WAIT_OBJECT_0 indicates
279 * the first index into @handles of the objects that are signalled.
280 * %WAIT_ABANDONED_0 to %WAIT_ABANDONED_0 + @numobjects - 1 - if
281 * @waitall is %TRUE, indicates that all objects are signalled, and at
282 * least one object is an abandoned mutex object (See
283 * WaitForSingleObject() for a description of abandoned mutexes.) If
284 * @waitall is %FALSE, the return value minus %WAIT_ABANDONED_0
285 * indicates the first index into @handles of an abandoned mutex.
286 * %WAIT_TIMEOUT - The @timeout interval elapsed and no objects in
287 * @handles are signalled. %WAIT_FAILED - an error occurred.
289 guint32 WaitForMultipleObjects(guint32 numobjects, gpointer *handles,
290 gboolean waitall, guint32 timeout)
293 gboolean duplicate=FALSE, bogustype=FALSE, done;
294 guint32 count, lowest;
295 struct timespec abstime;
299 if(numobjects>MAXIMUM_WAIT_OBJECTS) {
301 g_message(G_GNUC_PRETTY_FUNCTION ": Too many handles: %d",
308 /* Check for duplicates */
309 dups=g_hash_table_new(g_direct_hash, g_direct_equal);
310 for(i=0; i<numobjects; i++) {
311 gpointer exists=g_hash_table_lookup(dups, handles[i]);
314 g_message(G_GNUC_PRETTY_FUNCTION
315 ": Handle %p duplicated", handles[i]);
322 if(_wapi_handle_test_capabilities (handles[i], WAPI_HANDLE_CAP_WAIT)==FALSE) {
324 g_message (G_GNUC_PRETTY_FUNCTION
325 ": Handle %p can't be waited for",
332 g_hash_table_insert(dups, handles[i], handles[i]);
334 g_hash_table_destroy(dups);
336 if(duplicate==TRUE) {
338 g_message(G_GNUC_PRETTY_FUNCTION
339 ": Returning due to duplicates");
345 if(bogustype==TRUE) {
347 g_message(G_GNUC_PRETTY_FUNCTION
348 ": Returning due to bogus type");
354 done=_wapi_handle_count_signalled_handles (numobjects, handles,
355 waitall, &count, &lowest);
357 for(i=0; i<numobjects; i++) {
358 _wapi_handle_ops_own (handles[i]);
361 _wapi_handle_unlock_handles (numobjects, handles);
362 return(WAIT_OBJECT_0+lowest);
365 /* Have to wait for some or all handles to become signalled
368 _wapi_handle_unlock_handles (numobjects, handles);
370 if(timeout!=INFINITE) {
371 _wapi_calc_timeout (&abstime, timeout);
374 _wapi_handle_lock_signal_mutex ();
377 if(timeout==INFINITE) {
378 ret=_wapi_handle_wait_signal ();
380 ret=_wapi_handle_timedwait_signal (&abstime);
384 /* Something was signalled ... */
385 done=_wapi_handle_count_signalled_handles (numobjects,
391 for(i=0; i<numobjects; i++) {
392 _wapi_handle_ops_own (handles[i]);
395 _wapi_handle_unlock_handles (numobjects,
397 _wapi_handle_unlock_signal_mutex ();
398 return(WAIT_OBJECT_0+lowest);
400 _wapi_handle_unlock_handles (numobjects, handles);
402 /* Timeout or other error */
404 g_message (G_GNUC_PRETTY_FUNCTION ": wait returned error: %s", strerror (ret));
407 _wapi_handle_unlock_signal_mutex ();
409 return(WAIT_TIMEOUT);