Merge pull request #2218 from mono/assignProjectConfigurtionFix
[mono.git] / mono / io-layer / wait.c
1 /*
2  * wait.c:  wait for handles to become signalled
3  *
4  * Author:
5  *      Dick Porter (dick@ximian.com)
6  *
7  * (C) 2002-2006 Novell, Inc.
8  */
9
10 #include <config.h>
11 #include <glib.h>
12 #include <string.h>
13 #include <errno.h>
14
15 #include <mono/io-layer/wapi.h>
16 #include <mono/io-layer/handles-private.h>
17 #include <mono/io-layer/wapi-private.h>
18
19 #if 0
20 #define DEBUG(...) g_message(__VA_ARGS__)
21 #else
22 #define DEBUG(...)
23 #endif
24
25 static gboolean own_if_signalled(gpointer handle)
26 {
27         gboolean ret = FALSE;
28         
29         if (_WAPI_SHARED_HANDLE (_wapi_handle_type (handle))) {
30                 if (_wapi_handle_trylock_shared_handles () == EBUSY) {
31                         return (FALSE);
32                 }
33         }
34         
35         if (_wapi_handle_issignalled (handle)) {
36                 _wapi_handle_ops_own (handle);
37                 ret = TRUE;
38         }
39
40         if (_WAPI_SHARED_HANDLE (_wapi_handle_type (handle))) {
41                 _wapi_handle_unlock_shared_handles ();
42         }
43
44         return(ret);
45 }
46
47 static gboolean own_if_owned(gpointer handle)
48 {
49         gboolean ret = FALSE;
50         
51         if (_WAPI_SHARED_HANDLE (_wapi_handle_type (handle))) {
52                 if (_wapi_handle_trylock_shared_handles () == EBUSY) {
53                         return (FALSE);
54                 }
55         }
56         
57         if (_wapi_handle_ops_isowned (handle)) {
58                 _wapi_handle_ops_own (handle);
59                 ret = TRUE;
60         }
61
62         if (_WAPI_SHARED_HANDLE (_wapi_handle_type (handle))) {
63                 _wapi_handle_unlock_shared_handles ();
64         }
65
66         return(ret);
67 }
68
69 /**
70  * WaitForSingleObjectEx:
71  * @handle: an object to wait for
72  * @timeout: the maximum time in milliseconds to wait for
73  * @alertable: if TRUE, the wait can be interrupted by an APC call
74  *
75  * This function returns when either @handle is signalled, or @timeout
76  * ms elapses.  If @timeout is zero, the object's state is tested and
77  * the function returns immediately.  If @timeout is %INFINITE, the
78  * function waits forever.
79  *
80  * Return value: %WAIT_ABANDONED - @handle is a mutex that was not
81  * released by the owning thread when it exited.  Ownership of the
82  * mutex object is granted to the calling thread and the mutex is set
83  * to nonsignalled.  %WAIT_OBJECT_0 - The state of @handle is
84  * signalled.  %WAIT_TIMEOUT - The @timeout interval elapsed and
85  * @handle's state is still not signalled.  %WAIT_FAILED - an error
86  * occurred. %WAIT_IO_COMPLETION - the wait was ended by an APC.
87  */
88 guint32 WaitForSingleObjectEx(gpointer handle, guint32 timeout,
89                               gboolean alertable)
90 {
91         guint32 ret, waited;
92         int thr_ret;
93         gboolean apc_pending = FALSE;
94         gpointer current_thread = wapi_get_current_thread_handle ();
95         
96         if (current_thread == NULL) {
97                 SetLastError (ERROR_INVALID_HANDLE);
98                 return(WAIT_FAILED);
99         }
100
101         if (handle == _WAPI_THREAD_CURRENT) {
102                 handle = wapi_get_current_thread_handle ();
103                 if (handle == NULL) {
104                         SetLastError (ERROR_INVALID_HANDLE);
105                         return(WAIT_FAILED);
106                 }
107         }
108
109         if ((GPOINTER_TO_UINT (handle) & _WAPI_PROCESS_UNHANDLED) == _WAPI_PROCESS_UNHANDLED) {
110                 SetLastError (ERROR_INVALID_HANDLE);
111                 return(WAIT_FAILED);
112         }
113         
114         if (_wapi_handle_test_capabilities (handle,
115                                             WAPI_HANDLE_CAP_WAIT) == FALSE) {
116                 DEBUG ("%s: handle %p can't be waited for", __func__,
117                            handle);
118
119                 return(WAIT_FAILED);
120         }
121
122         _wapi_handle_ops_prewait (handle);
123         
124         if (_wapi_handle_test_capabilities (handle, WAPI_HANDLE_CAP_SPECIAL_WAIT) == TRUE) {
125                 DEBUG ("%s: handle %p has special wait", __func__, handle);
126
127                 ret = _wapi_handle_ops_special_wait (handle, timeout, alertable);
128         
129                 if (alertable && _wapi_thread_cur_apc_pending ())
130                         ret = WAIT_IO_COMPLETION;
131
132                 return ret;
133         }
134         
135         
136         DEBUG ("%s: locking handle %p", __func__, handle);
137
138         thr_ret = _wapi_handle_lock_handle (handle);
139         g_assert (thr_ret == 0);
140
141         if (_wapi_handle_test_capabilities (handle,
142                                             WAPI_HANDLE_CAP_OWN) == TRUE) {
143                 if (own_if_owned (handle) == TRUE) {
144                         DEBUG ("%s: handle %p already owned", __func__,
145                                    handle);
146                         ret = WAIT_OBJECT_0;
147                         goto done;
148                 }
149         }
150
151         if (own_if_signalled (handle) == TRUE) {
152                 DEBUG ("%s: handle %p already signalled", __func__,
153                            handle);
154
155                 ret=WAIT_OBJECT_0;
156                 goto done;
157         }
158
159         if (timeout == 0) {
160                 ret = WAIT_TIMEOUT;
161                 goto done;
162         }
163         
164         do {
165                 /* Check before waiting on the condition, just in case
166                  */
167                 _wapi_handle_ops_prewait (handle);
168
169                 if (own_if_signalled (handle)) {
170                         DEBUG ("%s: handle %p signalled", __func__,
171                                    handle);
172
173                         ret = WAIT_OBJECT_0;
174                         goto done;
175                 }
176
177                 waited = _wapi_handle_timedwait_signal_handle (handle, timeout, alertable, FALSE, &apc_pending);
178
179                 if(waited==0 && !apc_pending) {
180                         /* Condition was signalled, so hopefully
181                          * handle is signalled now.  (It might not be
182                          * if someone else got in before us.)
183                          */
184                         if (own_if_signalled (handle)) {
185                                 DEBUG ("%s: handle %p signalled", __func__,
186                                            handle);
187
188                                 ret=WAIT_OBJECT_0;
189                                 goto done;
190                         }
191                 
192                         /* Better luck next time */
193                 }
194         } while(waited == 0 && !apc_pending);
195
196         /* Timeout or other error */
197         DEBUG ("%s: wait on handle %p error: %s", __func__, handle,
198                    strerror (waited));
199
200         ret = apc_pending ? WAIT_IO_COMPLETION : WAIT_TIMEOUT;
201
202 done:
203
204         DEBUG ("%s: unlocking handle %p", __func__, handle);
205         
206         thr_ret = _wapi_handle_unlock_handle (handle);
207         g_assert (thr_ret == 0);
208
209         return(ret);
210 }
211
212 guint32 WaitForSingleObject(gpointer handle, guint32 timeout)
213 {
214         return WaitForSingleObjectEx (handle, timeout, FALSE);
215 }
216
217
218 /**
219  * SignalObjectAndWait:
220  * @signal_handle: An object to signal
221  * @wait: An object to wait for
222  * @timeout: The maximum time in milliseconds to wait for
223  * @alertable: Specifies whether the function returnes when the system
224  * queues an I/O completion routine or an APC for the calling thread.
225  *
226  * Atomically signals @signal and waits for @wait to become signalled,
227  * or @timeout ms elapses.  If @timeout is zero, the object's state is
228  * tested and the function returns immediately.  If @timeout is
229  * %INFINITE, the function waits forever.
230  *
231  * @signal can be a semaphore, mutex or event object.
232  *
233  * If @alertable is %TRUE and the system queues an I/O completion
234  * routine or an APC for the calling thread, the function returns and
235  * the thread calls the completion routine or APC function.  If
236  * %FALSE, the function does not return, and the thread does not call
237  * the completion routine or APC function.  A completion routine is
238  * queued when the ReadFileEx() or WriteFileEx() function in which it
239  * was specified has completed.  The calling thread is the thread that
240  * initiated the read or write operation.  An APC is queued when
241  * QueueUserAPC() is called.  Currently completion routines and APC
242  * functions are not supported.
243  *
244  * Return value: %WAIT_ABANDONED - @wait is a mutex that was not
245  * released by the owning thread when it exited.  Ownershop of the
246  * mutex object is granted to the calling thread and the mutex is set
247  * to nonsignalled.  %WAIT_IO_COMPLETION - the wait was ended by one
248  * or more user-mode asynchronous procedure calls queued to the
249  * thread.  %WAIT_OBJECT_0 - The state of @wait is signalled.
250  * %WAIT_TIMEOUT - The @timeout interval elapsed and @wait's state is
251  * still not signalled.  %WAIT_FAILED - an error occurred.
252  */
253 guint32 SignalObjectAndWait(gpointer signal_handle, gpointer wait,
254                             guint32 timeout, gboolean alertable)
255 {
256         guint32 ret, waited;
257         int thr_ret;
258         gboolean apc_pending = FALSE;
259         gpointer current_thread = wapi_get_current_thread_handle ();
260         
261         if (current_thread == NULL) {
262                 SetLastError (ERROR_INVALID_HANDLE);
263                 return(WAIT_FAILED);
264         }
265
266         if (signal_handle == _WAPI_THREAD_CURRENT) {
267                 signal_handle = wapi_get_current_thread_handle ();
268                 if (signal_handle == NULL) {
269                         SetLastError (ERROR_INVALID_HANDLE);
270                         return(WAIT_FAILED);
271                 }
272         }
273
274         if (wait == _WAPI_THREAD_CURRENT) {
275                 wait = wapi_get_current_thread_handle ();
276                 if (wait == NULL) {
277                         SetLastError (ERROR_INVALID_HANDLE);
278                         return(WAIT_FAILED);
279                 }
280         }
281
282         if ((GPOINTER_TO_UINT (signal_handle) & _WAPI_PROCESS_UNHANDLED) == _WAPI_PROCESS_UNHANDLED) {
283                 SetLastError (ERROR_INVALID_HANDLE);
284                 return(WAIT_FAILED);
285         }
286
287         if ((GPOINTER_TO_UINT (wait) & _WAPI_PROCESS_UNHANDLED) == _WAPI_PROCESS_UNHANDLED) {
288                 SetLastError (ERROR_INVALID_HANDLE);
289                 return(WAIT_FAILED);
290         }
291         
292         if (_wapi_handle_test_capabilities (signal_handle,
293                                             WAPI_HANDLE_CAP_SIGNAL)==FALSE) {
294                 return(WAIT_FAILED);
295         }
296         
297         if (_wapi_handle_test_capabilities (wait,
298                                             WAPI_HANDLE_CAP_WAIT)==FALSE) {
299                 return(WAIT_FAILED);
300         }
301
302         _wapi_handle_ops_prewait (wait);
303         
304         if (_wapi_handle_test_capabilities (wait, WAPI_HANDLE_CAP_SPECIAL_WAIT) == TRUE) {
305                 g_warning ("%s: handle %p has special wait, implement me!!",
306                            __func__, wait);
307
308                 return (WAIT_FAILED);
309         }
310
311         DEBUG ("%s: locking handle %p", __func__, wait);
312
313         thr_ret = _wapi_handle_lock_handle (wait);
314         g_assert (thr_ret == 0);
315
316         _wapi_handle_ops_signal (signal_handle);
317
318         if (_wapi_handle_test_capabilities (wait, WAPI_HANDLE_CAP_OWN)==TRUE) {
319                 if (own_if_owned (wait)) {
320                         DEBUG ("%s: handle %p already owned", __func__,
321                                    wait);
322                         ret = WAIT_OBJECT_0;
323                         goto done;
324                 }
325         }
326
327         if (own_if_signalled (wait)) {
328                 DEBUG ("%s: handle %p already signalled", __func__, wait);
329
330                 ret = WAIT_OBJECT_0;
331                 goto done;
332         }
333
334         do {
335                 /* Check before waiting on the condition, just in case
336                  */
337                 _wapi_handle_ops_prewait (wait);
338         
339                 if (own_if_signalled (wait)) {
340                         DEBUG ("%s: handle %p signalled", __func__, wait);
341
342                         ret = WAIT_OBJECT_0;
343                         goto done;
344                 }
345
346                 waited = _wapi_handle_timedwait_signal_handle (wait, timeout, alertable, FALSE, &apc_pending);
347
348                 if (waited==0 && !apc_pending) {
349                         /* Condition was signalled, so hopefully
350                          * handle is signalled now.  (It might not be
351                          * if someone else got in before us.)
352                          */
353                         if (own_if_signalled (wait)) {
354                                 DEBUG ("%s: handle %p signalled", __func__,
355                                            wait);
356
357                                 ret = WAIT_OBJECT_0;
358                                 goto done;
359                         }
360                 
361                         /* Better luck next time */
362                 }
363         } while(waited == 0 && !apc_pending);
364
365         /* Timeout or other error */
366         DEBUG ("%s: wait on handle %p error: %s", __func__, wait,
367                    strerror (ret));
368
369         ret = apc_pending ? WAIT_IO_COMPLETION : WAIT_TIMEOUT;
370
371 done:
372
373         DEBUG ("%s: unlocking handle %p", __func__, wait);
374
375         thr_ret = _wapi_handle_unlock_handle (wait);
376         g_assert (thr_ret == 0);
377
378         return(ret);
379 }
380
381 static gboolean test_and_own (guint32 numobjects, gpointer *handles,
382                               gboolean waitall, guint32 *count,
383                               guint32 *lowest)
384 {
385         gboolean done;
386         int i;
387         
388         DEBUG ("%s: locking handles", __func__);
389         
390         done = _wapi_handle_count_signalled_handles (numobjects, handles,
391                                                      waitall, count, lowest);
392         if (done == TRUE) {
393                 if (waitall == TRUE) {
394                         for (i = 0; i < numobjects; i++) {
395                                 own_if_signalled (handles[i]);
396                         }
397                 } else {
398                         own_if_signalled (handles[*lowest]);
399                 }
400         }
401         
402         DEBUG ("%s: unlocking handles", __func__);
403
404         _wapi_handle_unlock_handles (numobjects, handles);
405
406         return(done);
407 }
408
409 /**
410  * WaitForMultipleObjectsEx:
411  * @numobjects: The number of objects in @handles. The maximum allowed
412  * is %MAXIMUM_WAIT_OBJECTS.
413  * @handles: An array of object handles.  Duplicates are not allowed.
414  * @waitall: If %TRUE, this function waits until all of the handles
415  * are signalled.  If %FALSE, this function returns when any object is
416  * signalled.
417  * @timeout: The maximum time in milliseconds to wait for.
418  * @alertable: if TRUE, the wait can be interrupted by an APC call
419  * 
420  * This function returns when either one or more of @handles is
421  * signalled, or @timeout ms elapses.  If @timeout is zero, the state
422  * of each item of @handles is tested and the function returns
423  * immediately.  If @timeout is %INFINITE, the function waits forever.
424  *
425  * Return value: %WAIT_OBJECT_0 to %WAIT_OBJECT_0 + @numobjects - 1 -
426  * if @waitall is %TRUE, indicates that all objects are signalled.  If
427  * @waitall is %FALSE, the return value minus %WAIT_OBJECT_0 indicates
428  * the first index into @handles of the objects that are signalled.
429  * %WAIT_ABANDONED_0 to %WAIT_ABANDONED_0 + @numobjects - 1 - if
430  * @waitall is %TRUE, indicates that all objects are signalled, and at
431  * least one object is an abandoned mutex object (See
432  * WaitForSingleObject() for a description of abandoned mutexes.)  If
433  * @waitall is %FALSE, the return value minus %WAIT_ABANDONED_0
434  * indicates the first index into @handles of an abandoned mutex.
435  * %WAIT_TIMEOUT - The @timeout interval elapsed and no objects in
436  * @handles are signalled.  %WAIT_FAILED - an error occurred.
437  * %WAIT_IO_COMPLETION - the wait was ended by an APC.
438  */
439 guint32 WaitForMultipleObjectsEx(guint32 numobjects, gpointer *handles,
440                                  gboolean waitall, guint32 timeout,
441                                  gboolean alertable)
442 {
443         gboolean duplicate = FALSE, bogustype = FALSE, done;
444         guint32 count, lowest;
445         guint i;
446         guint32 ret;
447         int thr_ret;
448         gpointer current_thread = wapi_get_current_thread_handle ();
449         guint32 retval;
450         gboolean poll;
451         gpointer sorted_handles [MAXIMUM_WAIT_OBJECTS];
452         gboolean apc_pending = FALSE;
453         
454         if (current_thread == NULL) {
455                 SetLastError (ERROR_INVALID_HANDLE);
456                 return(WAIT_FAILED);
457         }
458         
459         if (numobjects > MAXIMUM_WAIT_OBJECTS) {
460                 DEBUG ("%s: Too many handles: %d", __func__, numobjects);
461
462                 return(WAIT_FAILED);
463         }
464         
465         if (numobjects == 1) {
466                 return WaitForSingleObjectEx (handles [0], timeout, alertable);
467         }
468
469         /* Check for duplicates */
470         for (i = 0; i < numobjects; i++) {
471                 if (handles[i] == _WAPI_THREAD_CURRENT) {
472                         handles[i] = wapi_get_current_thread_handle ();
473                         
474                         if (handles[i] == NULL) {
475                                 DEBUG ("%s: Handle %d bogus", __func__, i);
476
477                                 bogustype = TRUE;
478                                 break;
479                         }
480                 }
481
482                 if ((GPOINTER_TO_UINT (handles[i]) & _WAPI_PROCESS_UNHANDLED) == _WAPI_PROCESS_UNHANDLED) {
483                         DEBUG ("%s: Handle %d pseudo process", __func__,
484                                    i);
485
486                         bogustype = TRUE;
487                         break;
488                 }
489
490                 if (_wapi_handle_test_capabilities (handles[i], WAPI_HANDLE_CAP_WAIT) == FALSE) {
491                         DEBUG ("%s: Handle %p can't be waited for",
492                                    __func__, handles[i]);
493
494                         bogustype = TRUE;
495                         break;
496                 }
497
498                 sorted_handles [i] = handles [i];
499                 _wapi_handle_ops_prewait (handles[i]);
500         }
501
502         qsort (sorted_handles, numobjects, sizeof (gpointer), g_direct_equal);
503         for (i = 1; i < numobjects; i++) {
504                 if (sorted_handles [i - 1] == sorted_handles [i]) {
505                         duplicate = TRUE;
506                         break;
507                 }
508         }
509
510         if (duplicate == TRUE) {
511                 DEBUG ("%s: Returning due to duplicates", __func__);
512
513                 return(WAIT_FAILED);
514         }
515
516         if (bogustype == TRUE) {
517                 DEBUG ("%s: Returning due to bogus type", __func__);
518
519                 return(WAIT_FAILED);
520         }
521
522         poll = FALSE;
523         for (i = 0; i < numobjects; ++i)
524                 if (_wapi_handle_type (handles [i]) == WAPI_HANDLE_PROCESS || _WAPI_SHARED_HANDLE (_wapi_handle_type (handles[i]))) 
525                         /* Can't wait for a process handle + another handle without polling */
526                         poll = TRUE;
527
528         done = test_and_own (numobjects, handles, waitall, &count, &lowest);
529         if (done == TRUE) {
530                 return(WAIT_OBJECT_0+lowest);
531         }
532         
533         if (timeout == 0) {
534                 return WAIT_TIMEOUT;
535         }
536         /* Have to wait for some or all handles to become signalled
537          */
538
539         for (i = 0; i < numobjects; i++) {
540                 /* Add a reference, as we need to ensure the handle wont
541                  * disappear from under us while we're waiting in the loop
542                  * (not lock, as we don't want exclusive access here)
543                  */
544                 _wapi_handle_ref (handles[i]);
545         }
546
547         while(1) {
548                 /* Prod all handles with prewait methods and
549                  * special-wait handles that aren't already signalled
550                  */
551                 for (i = 0; i < numobjects; i++) {
552                         _wapi_handle_ops_prewait (handles[i]);
553                 
554                         if (_wapi_handle_test_capabilities (handles[i], WAPI_HANDLE_CAP_SPECIAL_WAIT) == TRUE && _wapi_handle_issignalled (handles[i]) == FALSE) {
555                                 _wapi_handle_ops_special_wait (handles[i], 0, alertable);
556                         }
557                 }
558                 
559                 DEBUG ("%s: locking signal mutex", __func__);
560
561                 thr_ret = _wapi_handle_lock_signal_mutex ();
562                 g_assert (thr_ret == 0);
563
564                 /* Check the signalled state of handles inside the critical section */
565                 if (waitall) {
566                         done = TRUE;
567                         for (i = 0; i < numobjects; i++)
568                                 if (!_wapi_handle_issignalled (handles [i]))
569                                         done = FALSE;
570                 } else {
571                         done = FALSE;
572                         for (i = 0; i < numobjects; i++)
573                                 if (_wapi_handle_issignalled (handles [i]))
574                                         done = TRUE;
575                 }
576                 
577                 if (!done) {
578                         /* Enter the wait */
579                         ret = _wapi_handle_timedwait_signal (timeout, poll, &apc_pending);
580                 } else {
581                         /* No need to wait */
582                         ret = 0;
583                 }
584
585                 DEBUG ("%s: unlocking signal mutex", __func__);
586
587                 thr_ret = _wapi_handle_unlock_signal_mutex (NULL);
588                 g_assert (thr_ret == 0);
589                 
590                 if (alertable && apc_pending) {
591                         retval = WAIT_IO_COMPLETION;
592                         break;
593                 }
594         
595                 /* Check if everything is signalled, as we can't
596                  * guarantee to notice a shared signal even if the
597                  * wait timed out
598                  */
599                 done = test_and_own (numobjects, handles, waitall,
600                                      &count, &lowest);
601                 if (done == TRUE) {
602                         retval = WAIT_OBJECT_0+lowest;
603                         break;
604                 } else if (ret != 0) {
605                         /* Didn't get all handles, and there was a
606                          * timeout or other error
607                          */
608                         DEBUG ("%s: wait returned error: %s", __func__,
609                                    strerror (ret));
610
611                         if(ret==ETIMEDOUT) {
612                                 retval = WAIT_TIMEOUT;
613                         } else {
614                                 retval = WAIT_FAILED;
615                         }
616                         break;
617                 }
618         }
619
620         for (i = 0; i < numobjects; i++) {
621                 /* Unref everything we reffed above */
622                 _wapi_handle_unref (handles[i]);
623         }
624
625         return retval;
626 }
627
628 guint32 WaitForMultipleObjects(guint32 numobjects, gpointer *handles,
629                                gboolean waitall, guint32 timeout)
630 {
631         return WaitForMultipleObjectsEx(numobjects, handles, waitall, timeout, FALSE);
632 }
633
634 /**
635  * WaitForInputIdle:
636  * @handle: a handle to the process to wait for
637  * @timeout: the maximum time in milliseconds to wait for
638  *
639  * This function returns when either @handle process is waiting
640  * for input, or @timeout ms elapses.  If @timeout is zero, the
641  * process state is tested and the function returns immediately.
642  * If @timeout is %INFINITE, the function waits forever.
643  *
644  * Return value: 0 - @handle process is waiting for input.
645  * %WAIT_TIMEOUT - The @timeout interval elapsed and
646  * @handle process is not waiting for input.  %WAIT_FAILED - an error
647  * occurred. 
648  */
649 guint32 WaitForInputIdle(gpointer handle, guint32 timeout)
650 {
651         /*TODO: Not implemented*/
652         return WAIT_TIMEOUT;
653 }
654