Exemple #1
0
/**
 * WaitForSingleObjectEx:
 * @handle: an object to wait for
 * @timeout: the maximum time in milliseconds to wait for
 * @alertable: if TRUE, the wait can be interrupted by an APC call
 *
 * This function returns when either @handle is signalled, or @timeout
 * ms elapses.  If @timeout is zero, the object's state is tested and
 * the function returns immediately.  If @timeout is %INFINITE, the
 * function waits forever.
 *
 * Return value: %WAIT_ABANDONED - @handle is a mutex that was not
 * released by the owning thread when it exited.  Ownership of the
 * mutex object is granted to the calling thread and the mutex is set
 * to nonsignalled.  %WAIT_OBJECT_0 - The state of @handle is
 * signalled.  %WAIT_TIMEOUT - The @timeout interval elapsed and
 * @handle's state is still not signalled.  %WAIT_FAILED - an error
 * occurred. %WAIT_IO_COMPLETION - the wait was ended by an APC.
 */
guint32 WaitForSingleObjectEx(gpointer handle, guint32 timeout,
			      gboolean alertable)
{
	guint32 ret, waited;
	struct timespec abstime;
	int thr_ret;
	gboolean apc_pending = FALSE;
	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) {
#ifdef DEBUG
		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 ("%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,
			      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 (own_if_owned (handle) == TRUE) {
#ifdef DEBUG
			g_message ("%s: handle %p already owned", __func__,
				   handle);
#endif
			ret = WAIT_OBJECT_0;
			goto done;
		}
	}
	
	if (alertable && _wapi_thread_apc_pending (current_thread)) {
		apc_pending = TRUE;
		ret = WAIT_IO_COMPLETION;
		goto done;
	}
	
	if (own_if_signalled (handle) == TRUE) {
#ifdef DEBUG
		g_message ("%s: handle %p already signalled", __func__,
			   handle);
#endif

		ret=WAIT_OBJECT_0;
		goto done;
	}

	if (timeout == 0) {
		ret = WAIT_TIMEOUT;
		goto done;
	}
	/* Have to wait for it */
	if (timeout != INFINITE) {
		_wapi_calc_timeout (&abstime, timeout);
	}
	
	do {
		/* 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, alertable, FALSE);
		}
	
		if (alertable)
			apc_pending = _wapi_thread_apc_pending (current_thread);

		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 (own_if_signalled (handle)) {
#ifdef DEBUG
				g_message ("%s: handle %p signalled", __func__,
					   handle);
#endif

				ret=WAIT_OBJECT_0;
				goto done;
			}
		
			/* Better luck next time */
		}
	} while(waited == 0 && !apc_pending);

	/* Timeout or other error */
#ifdef DEBUG
	g_message ("%s: wait on handle %p error: %s", __func__, handle,
		   strerror (waited));
#endif

	ret = WAIT_TIMEOUT;
	
done:

#ifdef DEBUG
	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;
	}
		
	return(ret);
}
Exemple #2
0
/**
 * WaitForSingleObjectEx:
 * @handle: an object to wait for
 * @timeout: the maximum time in milliseconds to wait for
 * @alertable: if TRUE, the wait can be interrupted by an APC call
 *
 * This function returns when either @handle is signalled, or @timeout
 * ms elapses.  If @timeout is zero, the object's state is tested and
 * the function returns immediately.  If @timeout is %INFINITE, the
 * function waits forever.
 *
 * Return value: %WAIT_ABANDONED - @handle is a mutex that was not
 * released by the owning thread when it exited.  Ownership of the
 * mutex object is granted to the calling thread and the mutex is set
 * to nonsignalled.  %WAIT_OBJECT_0 - The state of @handle is
 * signalled.  %WAIT_TIMEOUT - The @timeout interval elapsed and
 * @handle's state is still not signalled.  %WAIT_FAILED - an error
 * occurred. %WAIT_IO_COMPLETION - the wait was ended by an APC.
 */
guint32 WaitForSingleObjectEx(gpointer handle, guint32 timeout,
			      gboolean alertable)
{
	guint32 ret, waited;
	int thr_ret;
	gboolean apc_pending = FALSE;
	gpointer current_thread = wapi_get_current_thread_handle ();
	gint64 now, end;
	
	if (current_thread == NULL) {
		SetLastError (ERROR_INVALID_HANDLE);
		return(WAIT_FAILED);
	}

	if (handle == _WAPI_THREAD_CURRENT) {
		handle = wapi_get_current_thread_handle ();
		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) {
		MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: handle %p can't be waited for", __func__,
			   handle);

		return(WAIT_FAILED);
	}

	_wapi_handle_ops_prewait (handle);
	
	if (_wapi_handle_test_capabilities (handle, WAPI_HANDLE_CAP_SPECIAL_WAIT) == TRUE) {
		MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: handle %p has special wait", __func__, handle);

		ret = _wapi_handle_ops_special_wait (handle, timeout, alertable);
	
		if (alertable && _wapi_thread_cur_apc_pending ())
			ret = WAIT_IO_COMPLETION;

		return ret;
	}
	
	
	MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: locking handle %p", __func__, 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 (own_if_owned (handle) == TRUE) {
			MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: handle %p already owned", __func__,
				   handle);
			ret = WAIT_OBJECT_0;
			goto done;
		}
	}

	if (own_if_signalled (handle) == TRUE) {
		MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: handle %p already signalled", __func__,
			   handle);

		ret=WAIT_OBJECT_0;
		goto done;
	}

	if (timeout == 0) {
		ret = WAIT_TIMEOUT;
		goto done;
	}
	
	if (timeout != INFINITE)
		end = mono_100ns_ticks () + timeout * 1000 * 10;

	do {
		/* Check before waiting on the condition, just in case
		 */
		_wapi_handle_ops_prewait (handle);

		if (own_if_signalled (handle)) {
			MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: handle %p signalled", __func__,
				   handle);

			ret = WAIT_OBJECT_0;
			goto done;
		}

		if (timeout == INFINITE) {
			waited = _wapi_handle_timedwait_signal_handle (handle, INFINITE, alertable, FALSE, &apc_pending);
		} else {
			now = mono_100ns_ticks ();
			if (end < now) {
				ret = WAIT_TIMEOUT;
				goto done;
			}

			waited = _wapi_handle_timedwait_signal_handle (handle, (end - now) / 10 / 1000, alertable, FALSE, &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 (own_if_signalled (handle)) {
				MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: handle %p signalled", __func__,
					   handle);

				ret=WAIT_OBJECT_0;
				goto done;
			}
		
			/* Better luck next time */
		}
	} while(waited == 0 && !apc_pending);

	/* Timeout or other error */
	MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: wait on handle %p error: %s", __func__, handle,
		   strerror (waited));

	ret = apc_pending ? WAIT_IO_COMPLETION : WAIT_TIMEOUT;

done:

	MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: unlocking handle %p", __func__, handle);
	
	thr_ret = _wapi_handle_unlock_handle (handle);
	g_assert (thr_ret == 0);

	return(ret);
}
Exemple #3
0
/**
 * SignalObjectAndWait:
 * @signal_handle: An object to signal
 * @wait: An object to wait for
 * @timeout: The maximum time in milliseconds to wait for
 * @alertable: Specifies whether the function returnes when the system
 * queues an I/O completion routine or an APC for the calling thread.
 *
 * Atomically signals @signal and waits for @wait to become signalled,
 * or @timeout ms elapses.  If @timeout is zero, the object's state is
 * tested and the function returns immediately.  If @timeout is
 * %INFINITE, the function waits forever.
 *
 * @signal can be a semaphore, mutex or event object.
 *
 * If @alertable is %TRUE and the system queues an I/O completion
 * routine or an APC for the calling thread, the function returns and
 * the thread calls the completion routine or APC function.  If
 * %FALSE, the function does not return, and the thread does not call
 * the completion routine or APC function.  A completion routine is
 * queued when the ReadFileEx() or WriteFileEx() function in which it
 * was specified has completed.  The calling thread is the thread that
 * initiated the read or write operation.  An APC is queued when
 * QueueUserAPC() is called.  Currently completion routines and APC
 * functions are not supported.
 *
 * Return value: %WAIT_ABANDONED - @wait is a mutex that was not
 * released by the owning thread when it exited.  Ownershop of the
 * mutex object is granted to the calling thread and the mutex is set
 * to nonsignalled.  %WAIT_IO_COMPLETION - the wait was ended by one
 * or more user-mode asynchronous procedure calls queued to the
 * thread.  %WAIT_OBJECT_0 - The state of @wait is signalled.
 * %WAIT_TIMEOUT - The @timeout interval elapsed and @wait's state is
 * still not signalled.  %WAIT_FAILED - an error occurred.
 */
guint32 SignalObjectAndWait(gpointer signal_handle, gpointer wait,
			    guint32 timeout, gboolean alertable)
{
	guint32 ret, waited;
	struct timespec abstime;
	int thr_ret;
	gboolean apc_pending = FALSE;
	gpointer current_thread = GetCurrentThread ();
	
	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);
	}

	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 ("%s: locking handle %p", __func__, wait);
#endif

	pthread_cleanup_push ((void(*)(void *))_wapi_handle_unlock_handle,
			      wait);
	thr_ret = _wapi_handle_lock_handle (wait);
	g_assert (thr_ret == 0);

	_wapi_handle_ops_signal (signal_handle);

	if (_wapi_handle_test_capabilities (wait, WAPI_HANDLE_CAP_OWN)==TRUE) {
		if (own_if_owned (wait)) {
#ifdef DEBUG
			g_message ("%s: handle %p already owned", __func__,
				   wait);
#endif
			ret = WAIT_OBJECT_0;
			goto done;
		}
	}
	
	if (alertable && _wapi_thread_apc_pending (current_thread)) {
		apc_pending = TRUE;
		ret = WAIT_IO_COMPLETION;
		goto done;
	}
	
	if (own_if_signalled (wait)) {
#ifdef DEBUG
		g_message ("%s: handle %p already signalled", __func__, wait);
#endif

		ret = WAIT_OBJECT_0;
		goto done;
	}

	/* Have to wait for it */
	if (timeout != INFINITE) {
		_wapi_calc_timeout (&abstime, timeout);
	}
	
	do {
		/* Check before waiting on the condition, just in case
		 */
		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);
		} else {
			waited = _wapi_handle_timedwait_signal_handle (wait, &abstime);
		}

		if (alertable) {
			apc_pending = _wapi_thread_apc_pending (current_thread);
		}

		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 (own_if_signalled (wait)) {
#ifdef DEBUG
				g_message ("%s: handle %p signalled", __func__,
					   wait);
#endif

				ret = WAIT_OBJECT_0;
				goto done;
			}
		
			/* Better luck next time */
		}
	} while(waited == 0 && !apc_pending);

	/* Timeout or other error */
#ifdef DEBUG
	g_message ("%s: wait on handle %p error: %s", __func__, wait,
		   strerror (ret));
#endif

	ret = WAIT_TIMEOUT;
	
done:

#ifdef DEBUG
	g_message ("%s: unlocking handle %p", __func__, wait);
#endif

	thr_ret = _wapi_handle_unlock_handle (wait);
	g_assert (thr_ret == 0);
	pthread_cleanup_pop (0);

	if (apc_pending) {
		_wapi_thread_dispatch_apc_queue (current_thread);
		ret = WAIT_IO_COMPLETION;
	}
	
	return(ret);
}