* 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,
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;
}
}
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)
* 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;
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,
_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;
}
}
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);
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;
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 */
* %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);
}
/* 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
*/
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);
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,
{
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;
+}
+