2008-12-08 Rodrigo Kumpera <rkumpera@novell.com>
[mono.git] / mono / io-layer / wait.c
index e3d07b3a25555494c04e494d9e5da65786c9d6ca..50a8b5038f8eded92d34499e60fadc8d3ecd1388 100644 (file)
@@ -4,7 +4,7 @@
  * Author:
  *     Dick Porter (dick@ximian.com)
  *
- * (C) 2002 Ximian, Inc.
+ * (C) 2002-2006 Novell, Inc.
  */
 
 #include <config.h>
 
 #undef DEBUG
 
+static gboolean own_if_signalled(gpointer handle)
+{
+       gboolean ret = FALSE;
+       
+       if (_WAPI_SHARED_HANDLE (_wapi_handle_type (handle))) {
+               if (_wapi_handle_trylock_shared_handles () == EBUSY) {
+                       return (FALSE);
+               }
+       }
+       
+       if (_wapi_handle_issignalled (handle)) {
+               _wapi_handle_ops_own (handle);
+               ret = TRUE;
+       }
+
+       if (_WAPI_SHARED_HANDLE (_wapi_handle_type (handle))) {
+               _wapi_handle_unlock_shared_handles ();
+       }
+
+       return(ret);
+}
+
+static gboolean own_if_owned(gpointer handle)
+{
+       gboolean ret = FALSE;
+       
+       if (_WAPI_SHARED_HANDLE (_wapi_handle_type (handle))) {
+               if (_wapi_handle_trylock_shared_handles () == EBUSY) {
+                       return (FALSE);
+               }
+       }
+       
+       if (_wapi_handle_ops_isowned (handle)) {
+               _wapi_handle_ops_own (handle);
+               ret = TRUE;
+       }
+
+       if (_WAPI_SHARED_HANDLE (_wapi_handle_type (handle))) {
+               _wapi_handle_unlock_shared_handles ();
+       }
+
+       return(ret);
+}
+
 /**
  * WaitForSingleObjectEx:
  * @handle: an object to wait for
  * occurred. %WAIT_IO_COMPLETION - the wait was ended by an APC.
  */
 guint32 WaitForSingleObjectEx(gpointer handle, guint32 timeout,
-                                               gboolean alertable)
+                             gboolean alertable)
 {
        guint32 ret, waited;
        struct timespec abstime;
        int thr_ret;
        gboolean apc_pending = FALSE;
-       gpointer current_thread = GetCurrentThread ();
+       gpointer current_thread = _wapi_thread_handle_from_id (pthread_self ());
+       
+       if (current_thread == NULL) {
+               SetLastError (ERROR_INVALID_HANDLE);
+               return(WAIT_FAILED);
+       }
+
+       if (handle == _WAPI_THREAD_CURRENT) {
+               handle = _wapi_thread_handle_from_id (pthread_self ());
+               if (handle == NULL) {
+                       SetLastError (ERROR_INVALID_HANDLE);
+                       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) {
+       if (_wapi_handle_test_capabilities (handle,
+                                           WAPI_HANDLE_CAP_WAIT) == FALSE) {
 #ifdef DEBUG
-               g_message (G_GNUC_PRETTY_FUNCTION
-                          ": handle %p can't be waited for", handle);
+               g_message ("%s: handle %p can't be waited for", __func__,
+                          handle);
 #endif
 
                return(WAIT_FAILED);
        }
+
+       _wapi_handle_ops_prewait (handle);
        
+       if (_wapi_handle_test_capabilities (handle, WAPI_HANDLE_CAP_SPECIAL_WAIT) == TRUE) {
 #ifdef DEBUG
-       g_message (G_GNUC_PRETTY_FUNCTION ": locking handle %p", handle);
+               g_message ("%s: handle %p has special wait", __func__, handle);
+#endif
+
+               ret = _wapi_handle_ops_special_wait (handle, timeout);
+       
+               if (alertable && _wapi_thread_apc_pending (current_thread)) {
+                       apc_pending = TRUE;
+                       ret = WAIT_IO_COMPLETION;
+               }
+
+               goto check_pending;
+       }
+       
+       
+#ifdef DEBUG
+       g_message ("%s: locking handle %p", __func__, handle);
 #endif
 
        pthread_cleanup_push ((void(*)(void *))_wapi_handle_unlock_handle,
@@ -69,15 +149,14 @@ guint32 WaitForSingleObjectEx(gpointer handle, guint32 timeout,
        thr_ret = _wapi_handle_lock_handle (handle);
        g_assert (thr_ret == 0);
 
-       if(_wapi_handle_test_capabilities (handle,
-                                          WAPI_HANDLE_CAP_OWN)==TRUE) {
-               if(_wapi_handle_ops_isowned (handle)==TRUE) {
+       if (_wapi_handle_test_capabilities (handle,
+                                           WAPI_HANDLE_CAP_OWN) == TRUE) {
+               if (own_if_owned (handle) == TRUE) {
 #ifdef DEBUG
-                       g_message (G_GNUC_PRETTY_FUNCTION
-                                  ": handle %p already owned", handle);
+                       g_message ("%s: handle %p already owned", __func__,
+                                  handle);
 #endif
-                       _wapi_handle_ops_own (handle);
-                       ret=WAIT_OBJECT_0;
+                       ret = WAIT_OBJECT_0;
                        goto done;
                }
        }
@@ -88,28 +167,44 @@ guint32 WaitForSingleObjectEx(gpointer handle, guint32 timeout,
                goto done;
        }
        
-       if(_wapi_handle_issignalled (handle)) {
+       if (own_if_signalled (handle) == TRUE) {
 #ifdef DEBUG
-               g_message (G_GNUC_PRETTY_FUNCTION
-                          ": handle %p already signalled", handle);
+               g_message ("%s: handle %p already signalled", __func__,
+                          handle);
 #endif
 
-               _wapi_handle_ops_own (handle);
                ret=WAIT_OBJECT_0;
                goto done;
        }
 
+       if (timeout == 0) {
+               ret = WAIT_TIMEOUT;
+               goto done;
+       }
        /* Have to wait for it */
-       if(timeout!=INFINITE) {
+       if (timeout != INFINITE) {
                _wapi_calc_timeout (&abstime, timeout);
        }
        
        do {
-               if(timeout==INFINITE) {
-                       waited=_wapi_handle_wait_signal_handle (handle);
+               /* Check before waiting on the condition, just in case
+                */
+               _wapi_handle_ops_prewait (handle);
+
+               if (own_if_signalled (handle)) {
+#ifdef DEBUG
+                       g_message ("%s: handle %p signalled", __func__,
+                                  handle);
+#endif
+
+                       ret = WAIT_OBJECT_0;
+                       goto done;
+               }
+                       
+               if (timeout == INFINITE) {
+                       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);
                }
        
                if (alertable)
@@ -120,39 +215,39 @@ guint32 WaitForSingleObjectEx(gpointer handle, guint32 timeout,
                         * handle is signalled now.  (It might not be
                         * if someone else got in before us.)
                         */
-                       if(_wapi_handle_issignalled (handle)) {
+                       if (own_if_signalled (handle)) {
 #ifdef DEBUG
-                               g_message (G_GNUC_PRETTY_FUNCTION
-                                          ": handle %p signalled", handle);
+                               g_message ("%s: handle %p signalled", __func__,
+                                          handle);
 #endif
 
-                               _wapi_handle_ops_own (handle);
                                ret=WAIT_OBJECT_0;
                                goto done;
                        }
                
                        /* Better luck next time */
                }
-       } while(waited==0 && !apc_pending);
+       } while(waited == 0 && !apc_pending);
 
        /* Timeout or other error */
 #ifdef DEBUG
-       g_message (G_GNUC_PRETTY_FUNCTION ": wait on handle %p error: %s",
-                  handle, strerror (ret));
+       g_message ("%s: wait on handle %p error: %s", __func__, handle,
+                  strerror (waited));
 #endif
 
-       ret=WAIT_TIMEOUT;
+       ret = WAIT_TIMEOUT;
        
 done:
 
 #ifdef DEBUG
-       g_message (G_GNUC_PRETTY_FUNCTION ": unlocking handle %p", handle);
+       g_message ("%s: unlocking handle %p", __func__, handle);
 #endif
        
        thr_ret = _wapi_handle_unlock_handle (handle);
        g_assert (thr_ret == 0);
        pthread_cleanup_pop (0);
        
+check_pending:
        if (apc_pending) {
                _wapi_thread_dispatch_apc_queue (current_thread);
                ret = WAIT_IO_COMPLETION;
@@ -209,20 +304,60 @@ guint32 SignalObjectAndWait(gpointer signal_handle, gpointer wait,
        struct timespec abstime;
        int thr_ret;
        gboolean apc_pending = FALSE;
-       gpointer current_thread = GetCurrentThread ();
+       gpointer current_thread = _wapi_thread_handle_from_id (pthread_self ());
        
-       if(_wapi_handle_test_capabilities (signal_handle,
-                                          WAPI_HANDLE_CAP_SIGNAL)==FALSE) {
+       if (current_thread == NULL) {
+               SetLastError (ERROR_INVALID_HANDLE);
+               return(WAIT_FAILED);
+       }
+
+       if (signal_handle == _WAPI_THREAD_CURRENT) {
+               signal_handle = _wapi_thread_handle_from_id (pthread_self ());
+               if (signal_handle == NULL) {
+                       SetLastError (ERROR_INVALID_HANDLE);
+                       return(WAIT_FAILED);
+               }
+       }
+
+       if (wait == _WAPI_THREAD_CURRENT) {
+               wait = _wapi_thread_handle_from_id (pthread_self ());
+               if (wait == NULL) {
+                       SetLastError (ERROR_INVALID_HANDLE);
+                       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 (wait,
-                                          WAPI_HANDLE_CAP_WAIT)==FALSE) {
+       if (_wapi_handle_test_capabilities (signal_handle,
+                                           WAPI_HANDLE_CAP_SIGNAL)==FALSE) {
+               return(WAIT_FAILED);
+       }
+       
+       if (_wapi_handle_test_capabilities (wait,
+                                           WAPI_HANDLE_CAP_WAIT)==FALSE) {
                return(WAIT_FAILED);
        }
 
+       _wapi_handle_ops_prewait (wait);
+       
+       if (_wapi_handle_test_capabilities (wait, WAPI_HANDLE_CAP_SPECIAL_WAIT) == TRUE) {
+               g_warning ("%s: handle %p has special wait, implement me!!",
+                          __func__, wait);
+
+               return (WAIT_FAILED);
+       }
+
 #ifdef DEBUG
-       g_message (G_GNUC_PRETTY_FUNCTION ": locking handle %p", wait);
+       g_message ("%s: locking handle %p", __func__, wait);
 #endif
 
        pthread_cleanup_push ((void(*)(void *))_wapi_handle_unlock_handle,
@@ -232,14 +367,13 @@ guint32 SignalObjectAndWait(gpointer signal_handle, gpointer wait,
 
        _wapi_handle_ops_signal (signal_handle);
 
-       if(_wapi_handle_test_capabilities (wait, WAPI_HANDLE_CAP_OWN)==TRUE) {
-               if(_wapi_handle_ops_isowned (wait)==TRUE) {
+       if (_wapi_handle_test_capabilities (wait, WAPI_HANDLE_CAP_OWN)==TRUE) {
+               if (own_if_owned (wait)) {
 #ifdef DEBUG
-                       g_message (G_GNUC_PRETTY_FUNCTION
-                                  ": handle %p already owned", wait);
+                       g_message ("%s: handle %p already owned", __func__,
+                                  wait);
 #endif
-                       _wapi_handle_ops_own (wait);
-                       ret=WAIT_OBJECT_0;
+                       ret = WAIT_OBJECT_0;
                        goto done;
                }
        }
@@ -250,65 +384,75 @@ guint32 SignalObjectAndWait(gpointer signal_handle, gpointer wait,
                goto done;
        }
        
-       if(_wapi_handle_issignalled (wait)) {
+       if (own_if_signalled (wait)) {
 #ifdef DEBUG
-               g_message (G_GNUC_PRETTY_FUNCTION
-                          ": handle %p already signalled", wait);
+               g_message ("%s: handle %p already signalled", __func__, wait);
 #endif
 
-               _wapi_handle_ops_own (wait);
-               ret=WAIT_OBJECT_0;
+               ret = WAIT_OBJECT_0;
                goto done;
        }
 
        /* Have to wait for it */
-       if(timeout!=INFINITE) {
+       if (timeout != INFINITE) {
                _wapi_calc_timeout (&abstime, timeout);
        }
        
        do {
-               if(timeout==INFINITE) {
-                       waited=_wapi_handle_wait_signal_handle (wait);
+               /* Check before waiting on the condition, just in case
+                */
+               _wapi_handle_ops_prewait (wait);
+       
+               if (own_if_signalled (wait)) {
+#ifdef DEBUG
+                       g_message ("%s: handle %p signalled", __func__, wait);
+#endif
+
+                       ret = WAIT_OBJECT_0;
+                       goto done;
+               }
+               
+               if (timeout == INFINITE) {
+                       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);
                }
 
-               if (alertable)
+               if (alertable) {
                        apc_pending = _wapi_thread_apc_pending (current_thread);
+               }
 
-               if(waited==0 && !apc_pending) {
+               if (waited==0 && !apc_pending) {
                        /* Condition was signalled, so hopefully
                         * handle is signalled now.  (It might not be
                         * if someone else got in before us.)
                         */
-                       if(_wapi_handle_issignalled (wait)) {
+                       if (own_if_signalled (wait)) {
 #ifdef DEBUG
-                               g_message (G_GNUC_PRETTY_FUNCTION
-                                          ": handle %p signalled", wait);
+                               g_message ("%s: handle %p signalled", __func__,
+                                          wait);
 #endif
 
-                               _wapi_handle_ops_own (wait);
-                               ret=WAIT_OBJECT_0;
+                               ret = WAIT_OBJECT_0;
                                goto done;
                        }
                
                        /* Better luck next time */
                }
-       } while(waited==0 && !apc_pending);
+       } while(waited == 0 && !apc_pending);
 
        /* Timeout or other error */
 #ifdef DEBUG
-       g_message (G_GNUC_PRETTY_FUNCTION ": wait on handle %p error: %s",
-                  wait, strerror (ret));
+       g_message ("%s: wait on handle %p error: %s", __func__, wait,
+                  strerror (ret));
 #endif
 
-       ret=WAIT_TIMEOUT;
+       ret = WAIT_TIMEOUT;
        
 done:
 
 #ifdef DEBUG
-       g_message (G_GNUC_PRETTY_FUNCTION ": unlocking handle %p", wait);
+       g_message ("%s: unlocking handle %p", __func__, wait);
 #endif
 
        thr_ret = _wapi_handle_unlock_handle (wait);
@@ -345,7 +489,7 @@ static gboolean test_and_own (guint32 numobjects, gpointer *handles,
        int i;
        
 #ifdef DEBUG
-       g_message (G_GNUC_PRETTY_FUNCTION ": locking handles");
+       g_message ("%s: locking handles", __func__);
 #endif
        cleanup_data.numobjects = numobjects;
        cleanup_data.handles = handles;
@@ -354,15 +498,17 @@ static gboolean test_and_own (guint32 numobjects, gpointer *handles,
        done = _wapi_handle_count_signalled_handles (numobjects, handles,
                                                     waitall, count, lowest);
        if (done == TRUE) {
-               for (i = 0; i < numobjects; i++) {
-                       if (_wapi_handle_issignalled (handles[i])) {
-                               _wapi_handle_ops_own (handles[i]);
+               if (waitall == TRUE) {
+                       for (i = 0; i < numobjects; i++) {
+                               own_if_signalled (handles[i]);
                        }
+               } else {
+                       own_if_signalled (handles[*lowest]);
                }
        }
        
 #ifdef DEBUG
-       g_message (G_GNUC_PRETTY_FUNCTION ": unlocking handles");
+       g_message ("%s: unlocking handles", __func__);
 #endif
 
        /* calls the unlock function */
@@ -404,21 +550,27 @@ static gboolean test_and_own (guint32 numobjects, gpointer *handles,
  * %WAIT_IO_COMPLETION - the wait was ended by an APC.
  */
 guint32 WaitForMultipleObjectsEx(guint32 numobjects, gpointer *handles,
-                              gboolean waitall, guint32 timeout, gboolean alertable)
+                                gboolean waitall, guint32 timeout,
+                                gboolean alertable)
 {
        GHashTable *dups;
-       gboolean duplicate=FALSE, bogustype=FALSE, done;
+       gboolean duplicate = FALSE, bogustype = FALSE, done;
        guint32 count, lowest;
        struct timespec abstime;
        guint i;
        guint32 ret;
        int thr_ret;
-       gpointer current_thread = GetCurrentThread ();
+       gpointer current_thread = _wapi_thread_handle_from_id (pthread_self ());
+       guint32 retval;
        
-       if(numobjects>MAXIMUM_WAIT_OBJECTS) {
+       if (current_thread == NULL) {
+               SetLastError (ERROR_INVALID_HANDLE);
+               return(WAIT_FAILED);
+       }
+       
+       if (numobjects > MAXIMUM_WAIT_OBJECTS) {
 #ifdef DEBUG
-               g_message(G_GNUC_PRETTY_FUNCTION ": Too many handles: %d",
-                         numobjects);
+               g_message ("%s: Too many handles: %d", __func__, numobjects);
 #endif
 
                return(WAIT_FAILED);
@@ -429,56 +581,82 @@ guint32 WaitForMultipleObjectsEx(guint32 numobjects, gpointer *handles,
        }
 
        /* Check for duplicates */
-       dups=g_hash_table_new(g_direct_hash, g_direct_equal);
-       for(i=0; i<numobjects; i++) {
-               gpointer exists=g_hash_table_lookup(dups, handles[i]);
-               if(exists!=NULL) {
+       dups = g_hash_table_new (g_direct_hash, g_direct_equal);
+       for (i = 0; i < numobjects; i++) {
+               gpointer exists;
+
+               if (handles[i] == _WAPI_THREAD_CURRENT) {
+                       handles[i] = _wapi_thread_handle_from_id (pthread_self ());
+                       
+                       if (handles[i] == NULL) {
 #ifdef DEBUG
-                       g_message(G_GNUC_PRETTY_FUNCTION
-                                 ": Handle %p duplicated", handles[i]);
+                               g_message ("%s: Handle %d bogus", __func__, i);
 #endif
 
-                       duplicate=TRUE;
-                       break;
+                               bogustype = TRUE;
+                               break;
+                       }
                }
 
-               if(_wapi_handle_test_capabilities (handles[i], WAPI_HANDLE_CAP_WAIT)==FALSE) {
+               if ((GPOINTER_TO_UINT (handles[i]) & _WAPI_PROCESS_UNHANDLED) == _WAPI_PROCESS_UNHANDLED) {
 #ifdef DEBUG
-                       g_message (G_GNUC_PRETTY_FUNCTION
-                                  ": Handle %p can't be waited for",
+                       g_message ("%s: Handle %d pseudo process", __func__,
+                                  i);
+#endif
+
+                       bogustype = TRUE;
+                       break;
+               }
+               
+               exists = g_hash_table_lookup (dups, handles[i]);
+               if (exists != NULL) {
+#ifdef DEBUG
+                       g_message ("%s: Handle %p duplicated", __func__,
                                   handles[i]);
 #endif
 
-                       bogustype=TRUE;
+                       duplicate = TRUE;
+                       break;
+               }
+
+               if (_wapi_handle_test_capabilities (handles[i], WAPI_HANDLE_CAP_WAIT) == FALSE) {
+#ifdef DEBUG
+                       g_message ("%s: Handle %p can't be waited for",
+                                  __func__, handles[i]);
+#endif
+
+                       bogustype = TRUE;
                }
 
-               g_hash_table_insert(dups, handles[i], handles[i]);
+               g_hash_table_insert (dups, handles[i], handles[i]);
+               _wapi_handle_ops_prewait (handles[i]);
        }
-       g_hash_table_destroy(dups);
+       g_hash_table_destroy (dups);
 
-       if(duplicate==TRUE) {
+       if (duplicate == TRUE) {
 #ifdef DEBUG
-               g_message(G_GNUC_PRETTY_FUNCTION
-                         ": Returning due to duplicates");
+               g_message ("%s: Returning due to duplicates", __func__);
 #endif
 
                return(WAIT_FAILED);
        }
 
-       if(bogustype==TRUE) {
+       if (bogustype == TRUE) {
 #ifdef DEBUG
-               g_message(G_GNUC_PRETTY_FUNCTION
-                         ": Returning due to bogus type");
+               g_message ("%s: Returning due to bogus type", __func__);
 #endif
 
                return(WAIT_FAILED);
        }
 
-       done=test_and_own (numobjects, handles, waitall, &count, &lowest);
-       if(done==TRUE) {
+       done = test_and_own (numobjects, handles, waitall, &count, &lowest);
+       if (done == TRUE) {
                return(WAIT_OBJECT_0+lowest);
        }
        
+       if (timeout == 0) {
+               return WAIT_TIMEOUT;
+       }
        /* Have to wait for some or all handles to become signalled
         */
 
@@ -491,23 +669,51 @@ 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
+                */
+               for (i = 0; i < numobjects; i++) {
+                       _wapi_handle_ops_prewait (handles[i]);
+               
+                       if (_wapi_handle_test_capabilities (handles[i], WAPI_HANDLE_CAP_SPECIAL_WAIT) == TRUE && _wapi_handle_issignalled (handles[i]) == FALSE) {
+                               _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) {
+                       retval = WAIT_OBJECT_0 + lowest;
+                       break;
+               }
+               
 #ifdef DEBUG
-               g_message (G_GNUC_PRETTY_FUNCTION ": locking signal mutex");
+               g_message ("%s: locking signal mutex", __func__);
 #endif
 
                pthread_cleanup_push ((void(*)(void *))_wapi_handle_unlock_signal_mutex, NULL);
                thr_ret = _wapi_handle_lock_signal_mutex ();
                g_assert (thr_ret == 0);
                
-               if(timeout==INFINITE) {
-                       ret=_wapi_handle_wait_signal ();
+               if (timeout == INFINITE) {
+                       ret = _wapi_handle_wait_signal ();
                } else {
-                       ret=_wapi_handle_timedwait_signal (&abstime);
+                       ret = _wapi_handle_timedwait_signal (&abstime);
                }
 
 #ifdef DEBUG
-               g_message (G_GNUC_PRETTY_FUNCTION ": unlocking signal mutex");
+               g_message ("%s: unlocking signal mutex", __func__);
 #endif
 
                thr_ret = _wapi_handle_unlock_signal_mutex (NULL);
@@ -516,29 +722,43 @@ 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;
                }
        
-               if(ret==0) {
-                       /* Something was signalled ... */
-                       done = test_and_own (numobjects, handles, waitall,
-                                            &count, &lowest);
-                       if(done==TRUE) {
-                               return(WAIT_OBJECT_0+lowest);
-                       }
-               } else {
-                       /* Timeout or other error */
+               /* Check if everything is signalled, as we can't
+                * guarantee to notice a shared signal even if the
+                * wait timed out
+                */
+               done = test_and_own (numobjects, handles, waitall,
+                                    &count, &lowest);
+               if (done == TRUE) {
+                       retval = WAIT_OBJECT_0+lowest;
+                       break;
+               } else if (ret != 0) {
+                       /* Didn't get all handles, and there was a
+                        * timeout or other error
+                        */
 #ifdef DEBUG
-                       g_message (G_GNUC_PRETTY_FUNCTION ": wait returned error: %s", strerror (ret));
+                       g_message ("%s: wait returned error: %s", __func__,
+                                  strerror (ret));
 #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,
@@ -546,3 +766,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;
+}
+