2010-02-06 Zoltan Varga <vargaz@gmail.com>
[mono.git] / mono / io-layer / wait.c
index c9a5936f99a724fd6587f5744eb625b568ad04f3..db008cc1f87a0b910254bd82997650ddc1196bb7 100644 (file)
@@ -12,7 +12,7 @@
 #include <string.h>
 #include <errno.h>
 
-#include <mono/os/gc_wrapper.h>
+#include <mono/utils/gc_wrapper.h>
 
 #include <mono/io-layer/wapi.h>
 #include <mono/io-layer/handles-private.h>
@@ -106,6 +106,11 @@ guint32 WaitForSingleObjectEx(gpointer handle, guint32 timeout,
                        return(WAIT_FAILED);
                }
        }
+
+       if ((GPOINTER_TO_UINT (handle) & _WAPI_PROCESS_UNHANDLED) == _WAPI_PROCESS_UNHANDLED) {
+               SetLastError (ERROR_INVALID_HANDLE);
+               return(WAIT_FAILED);
+       }
        
        if (_wapi_handle_test_capabilities (handle,
                                            WAPI_HANDLE_CAP_WAIT) == FALSE) {
@@ -197,9 +202,9 @@ guint32 WaitForSingleObjectEx(gpointer handle, guint32 timeout,
                }
                        
                if (timeout == INFINITE) {
-                       waited = _wapi_handle_wait_signal_handle (handle);
+                       waited = _wapi_handle_wait_signal_handle (handle, alertable);
                } else {
-                       waited = _wapi_handle_timedwait_signal_handle (handle, &abstime);
+                       waited = _wapi_handle_timedwait_signal_handle (handle, &abstime, alertable, FALSE);
                }
        
                if (alertable)
@@ -321,6 +326,16 @@ guint32 SignalObjectAndWait(gpointer signal_handle, gpointer wait,
                        return(WAIT_FAILED);
                }
        }
+
+       if ((GPOINTER_TO_UINT (signal_handle) & _WAPI_PROCESS_UNHANDLED) == _WAPI_PROCESS_UNHANDLED) {
+               SetLastError (ERROR_INVALID_HANDLE);
+               return(WAIT_FAILED);
+       }
+
+       if ((GPOINTER_TO_UINT (wait) & _WAPI_PROCESS_UNHANDLED) == _WAPI_PROCESS_UNHANDLED) {
+               SetLastError (ERROR_INVALID_HANDLE);
+               return(WAIT_FAILED);
+       }
        
        if (_wapi_handle_test_capabilities (signal_handle,
                                            WAPI_HANDLE_CAP_SIGNAL)==FALSE) {
@@ -398,9 +413,9 @@ guint32 SignalObjectAndWait(gpointer signal_handle, gpointer wait,
                }
                
                if (timeout == INFINITE) {
-                       waited = _wapi_handle_wait_signal_handle (wait);
+                       waited = _wapi_handle_wait_signal_handle (wait, alertable);
                } else {
-                       waited = _wapi_handle_timedwait_signal_handle (wait, &abstime);
+                       waited = _wapi_handle_timedwait_signal_handle (wait, &abstime, alertable, FALSE);
                }
 
                if (alertable) {
@@ -546,6 +561,8 @@ guint32 WaitForMultipleObjectsEx(guint32 numobjects, gpointer *handles,
        guint32 ret;
        int thr_ret;
        gpointer current_thread = _wapi_thread_handle_from_id (pthread_self ());
+       guint32 retval;
+       gboolean poll;
        
        if (current_thread == NULL) {
                SetLastError (ERROR_INVALID_HANDLE);
@@ -581,6 +598,16 @@ guint32 WaitForMultipleObjectsEx(guint32 numobjects, gpointer *handles,
                                break;
                        }
                }
+
+               if ((GPOINTER_TO_UINT (handles[i]) & _WAPI_PROCESS_UNHANDLED) == _WAPI_PROCESS_UNHANDLED) {
+#ifdef DEBUG
+                       g_message ("%s: Handle %d pseudo process", __func__,
+                                  i);
+#endif
+
+                       bogustype = TRUE;
+                       break;
+               }
                
                exists = g_hash_table_lookup (dups, handles[i]);
                if (exists != NULL) {
@@ -600,6 +627,7 @@ guint32 WaitForMultipleObjectsEx(guint32 numobjects, gpointer *handles,
 #endif
 
                        bogustype = TRUE;
+                       break;
                }
 
                g_hash_table_insert (dups, handles[i], handles[i]);
@@ -623,6 +651,12 @@ guint32 WaitForMultipleObjectsEx(guint32 numobjects, gpointer *handles,
                return(WAIT_FAILED);
        }
 
+       poll = FALSE;
+       for (i = 0; i < numobjects; ++i)
+               if (_wapi_handle_type (handles [i]) == WAPI_HANDLE_PROCESS)
+                       /* Can't wait for a process handle + another handle without polling */
+                       poll = TRUE;
+
        done = test_and_own (numobjects, handles, waitall, &count, &lowest);
        if (done == TRUE) {
                return(WAIT_OBJECT_0+lowest);
@@ -643,6 +677,14 @@ guint32 WaitForMultipleObjectsEx(guint32 numobjects, gpointer *handles,
                return WAIT_IO_COMPLETION;
        }
        
+       for (i = 0; i < numobjects; i++) {
+               /* Add a reference, as we need to ensure the handle wont
+                * disappear from under us while we're waiting in the loop
+                * (not lock, as we don't want exclusive access here)
+                */
+               _wapi_handle_ref (handles[i]);
+       }
+
        while(1) {
                /* Prod all handles with prewait methods and
                 * special-wait handles that aren't already signalled
@@ -654,14 +696,6 @@ guint32 WaitForMultipleObjectsEx(guint32 numobjects, gpointer *handles,
                                _wapi_handle_ops_special_wait (handles[i], 0);
                        }
                }
-
-               /* Check before waiting on the condition, just in case
-                */
-               done = test_and_own (numobjects, handles, waitall,
-                                    &count, &lowest);
-               if (done == TRUE) {
-                       return(WAIT_OBJECT_0 + lowest);
-               }
                
 #ifdef DEBUG
                g_message ("%s: locking signal mutex", __func__);
@@ -670,11 +704,30 @@ guint32 WaitForMultipleObjectsEx(guint32 numobjects, gpointer *handles,
                pthread_cleanup_push ((void(*)(void *))_wapi_handle_unlock_signal_mutex, NULL);
                thr_ret = _wapi_handle_lock_signal_mutex ();
                g_assert (thr_ret == 0);
+
+               /* Check the signalled state of handles inside the critical section */
+               if (waitall) {
+                       done = TRUE;
+                       for (i = 0; i < numobjects; i++)
+                               if (!_wapi_handle_issignalled (handles [i]))
+                                       done = FALSE;
+               } else {
+                       done = FALSE;
+                       for (i = 0; i < numobjects; i++)
+                               if (_wapi_handle_issignalled (handles [i]))
+                                       done = TRUE;
+               }
                
-               if (timeout == INFINITE) {
-                       ret = _wapi_handle_wait_signal ();
+               if (!done) {
+                       /* Enter the wait */
+                       if (timeout == INFINITE) {
+                               ret = _wapi_handle_wait_signal (poll);
+                       } else {
+                               ret = _wapi_handle_timedwait_signal (&abstime, poll);
+                       }
                } else {
-                       ret = _wapi_handle_timedwait_signal (&abstime);
+                       /* No need to wait */
+                       ret = 0;
                }
 
 #ifdef DEBUG
@@ -687,7 +740,8 @@ guint32 WaitForMultipleObjectsEx(guint32 numobjects, gpointer *handles,
                
                if (alertable && _wapi_thread_apc_pending (current_thread)) {
                        _wapi_thread_dispatch_apc_queue (current_thread);
-                       return WAIT_IO_COMPLETION;
+                       retval = WAIT_IO_COMPLETION;
+                       break;
                }
        
                /* Check if everything is signalled, as we can't
@@ -697,7 +751,8 @@ guint32 WaitForMultipleObjectsEx(guint32 numobjects, gpointer *handles,
                done = test_and_own (numobjects, handles, waitall,
                                     &count, &lowest);
                if (done == TRUE) {
-                       return(WAIT_OBJECT_0+lowest);
+                       retval = WAIT_OBJECT_0+lowest;
+                       break;
                } else if (ret != 0) {
                        /* Didn't get all handles, and there was a
                         * timeout or other error
@@ -708,12 +763,20 @@ guint32 WaitForMultipleObjectsEx(guint32 numobjects, gpointer *handles,
 #endif
 
                        if(ret==ETIMEDOUT) {
-                               return(WAIT_TIMEOUT);
+                               retval = WAIT_TIMEOUT;
                        } else {
-                               return(WAIT_FAILED);
+                               retval = WAIT_FAILED;
                        }
+                       break;
                }
        }
+
+       for (i = 0; i < numobjects; i++) {
+               /* Unref everything we reffed above */
+               _wapi_handle_unref (handles[i]);
+       }
+
+       return retval;
 }
 
 guint32 WaitForMultipleObjects(guint32 numobjects, gpointer *handles,
@@ -721,3 +784,25 @@ guint32 WaitForMultipleObjects(guint32 numobjects, gpointer *handles,
 {
        return WaitForMultipleObjectsEx(numobjects, handles, waitall, timeout, FALSE);
 }
+
+/**
+ * WaitForInputIdle:
+ * @handle: a handle to the process to wait for
+ * @timeout: the maximum time in milliseconds to wait for
+ *
+ * This function returns when either @handle process is waiting
+ * for input, or @timeout ms elapses.  If @timeout is zero, the
+ * process state is tested and the function returns immediately.
+ * If @timeout is %INFINITE, the function waits forever.
+ *
+ * Return value: 0 - @handle process is waiting for input.
+ * %WAIT_TIMEOUT - The @timeout interval elapsed and
+ * @handle process is not waiting for input.  %WAIT_FAILED - an error
+ * occurred. 
+ */
+guint32 WaitForInputIdle(gpointer handle, guint32 timeout)
+{
+       /*TODO: Not implemented*/
+       return WAIT_TIMEOUT;
+}
+