コード例 #1
0
ファイル: mono-threads.c プロジェクト: ileonchik/mono
void
mono_thread_info_uninstall_interrupt (gboolean *interrupted)
{
	MonoThreadInfo *info;
	MonoThreadInfoInterruptToken *previous_token;

	g_assert (interrupted);
	*interrupted = FALSE;

	info = mono_thread_info_current ();
	g_assert (info);

	previous_token = (MonoThreadInfoInterruptToken *)InterlockedExchangePointer ((gpointer*) &info->interrupt_token, NULL);

	/* only the installer can uninstall the token */
	g_assert (previous_token);

	if (previous_token == INTERRUPT_STATE) {
		/* if it is interrupted, then it is going to be freed in finish interrupt */
		*interrupted = TRUE;
	} else {
		g_free (previous_token);
	}

	THREADS_INTERRUPT_DEBUG ("interrupt uninstall  tid %p previous_token %p interrupted %s\n",
		mono_thread_info_get_tid (info), previous_token, *interrupted ? "TRUE" : "FALSE");
}
コード例 #2
0
static inline void
request_interrupt (gpointer thread_info, HANDLE native_thread_handle, gint32 pending_apc_slot, PAPCFUNC apc_callback, DWORD tid)
{
	/*
	* On Windows platforms, an async interrupt/abort request queues an APC
	* that needs to be processed by target thread before it can return from an
	* alertable OS wait call and complete the mono interrupt/abort request.
	* Uncontrolled queuing of APC's could flood the APC queue preventing the target thread
	* to return from its alertable OS wait call, blocking the interrupt/abort requests to complete
	* This check makes sure that only one APC per type gets queued, preventing potential flooding
	* of the APC queue. NOTE, this code will execute regardless if targeted thread is currently in
	* an alertable wait or not. This is done to prevent races between interrupt/abort requests and
	* alertable wait calls. Threads already in an alertable wait should handle WAIT_IO_COMPLETION
	* return scenarios and restart the alertable wait operation if needed or take other actions
	* (like service the interrupt/abort request).
	*/
	MonoThreadInfo *info = (MonoThreadInfo *)thread_info;
	gint32 old_wait_info, new_wait_info;

	do {
		old_wait_info = mono_atomic_load_i32 (&info->thread_wait_info);
		if (old_wait_info & pending_apc_slot)
			return;

		new_wait_info = old_wait_info | pending_apc_slot;
	} while (mono_atomic_cas_i32 (&info->thread_wait_info, new_wait_info, old_wait_info) != old_wait_info);

	THREADS_INTERRUPT_DEBUG ("%06d - Interrupting/Aborting syscall in thread %06d", GetCurrentThreadId (), tid);
	QueueUserAPC (apc_callback, native_thread_handle, (ULONG_PTR)NULL);
}
コード例 #3
0
ファイル: mono-threads.c プロジェクト: ileonchik/mono
/*
 * mono_thread_info_prepare_interrupt:
 *
 * The state of the thread info interrupt token is set to 'interrupted' which means that :
 *  - if the thread calls one of the WaitFor functions, the function will return with
 *     WAIT_IO_COMPLETION instead of waiting
 *  - if the thread was waiting when this function was called, the wait will be broken
 *
 * It is possible that the wait functions return WAIT_IO_COMPLETION, but the target thread
 * didn't receive the interrupt signal yet, in this case it should call the wait function
 * again. This essentially means that the target thread will busy wait until it is ready to
 * process the interruption.
 */
MonoThreadInfoInterruptToken*
mono_thread_info_prepare_interrupt (MonoThreadInfo *info)
{
	MonoThreadInfoInterruptToken *token;

	token = set_interrupt_state (info);

	THREADS_INTERRUPT_DEBUG ("interrupt prepare    tid %p token %p\n",
		mono_thread_info_get_tid (info), token);

	return token;
}
コード例 #4
0
void
mono_threads_suspend_abort_syscall (MonoThreadInfo *info)
{
	DWORD id = mono_thread_info_get_tid (info);
	HANDLE handle;

	handle = OpenThread (THREAD_ALL_ACCESS, FALSE, id);
	g_assert (handle);

	THREADS_INTERRUPT_DEBUG ("%06d - Aborting syscall in thread %06d", GetCurrentThreadId (), id);
	QueueUserAPC ((PAPCFUNC)abort_apc, handle, (ULONG_PTR)NULL);

	CloseHandle (handle);
}
コード例 #5
0
ファイル: mono-threads.c プロジェクト: ileonchik/mono
/* Clear the interrupted flag of the current thread, set with
 * mono_thread_info_self_interrupt, so it can wait again */
void
mono_thread_info_clear_self_interrupt ()
{
	MonoThreadInfo *info;
	MonoThreadInfoInterruptToken *previous_token;

	info = mono_thread_info_current ();
	g_assert (info);

	previous_token = (MonoThreadInfoInterruptToken *)InterlockedCompareExchangePointer ((gpointer*) &info->interrupt_token, NULL, INTERRUPT_STATE);
	g_assert (previous_token == NULL || previous_token == INTERRUPT_STATE);

	THREADS_INTERRUPT_DEBUG ("interrupt clear self tid %p previous_token %p\n", mono_thread_info_get_tid (info), previous_token);
}
コード例 #6
0
ファイル: mono-threads.c プロジェクト: ileonchik/mono
void
mono_thread_info_finish_interrupt (MonoThreadInfoInterruptToken *token)
{
	THREADS_INTERRUPT_DEBUG ("interrupt finish     token %p\n", token);

	if (token == NULL)
		return;

	g_assert (token->callback);

	token->callback (token->data);

	g_free (token);
}
コード例 #7
0
ファイル: mono-threads.c プロジェクト: ileonchik/mono
void
mono_thread_info_self_interrupt (void)
{
	MonoThreadInfo *info;
	MonoThreadInfoInterruptToken *token;

	info = mono_thread_info_current ();
	g_assert (info);

	token = set_interrupt_state (info);
	g_assert (!token);

	THREADS_INTERRUPT_DEBUG ("interrupt self       tid %p\n",
		mono_thread_info_get_tid (info));
}
コード例 #8
0
ファイル: mono-threads.c プロジェクト: ileonchik/mono
/*
 * mono_thread_info_install_interrupt: install an interruption token for the current thread.
 *
 *  - @callback: must be able to be called from another thread and always cancel the wait
 *  - @data: passed to the callback
 *  - @interrupted: will be set to TRUE if a token is already installed, FALSE otherwise
 *     if set to TRUE, it must mean that the thread is in interrupted state
 */
void
mono_thread_info_install_interrupt (void (*callback) (gpointer data), gpointer data, gboolean *interrupted)
{
	MonoThreadInfo *info;
	MonoThreadInfoInterruptToken *previous_token, *token;

	g_assert (callback);

	g_assert (interrupted);
	*interrupted = FALSE;

	info = mono_thread_info_current ();
	g_assert (info);

	/* The memory of this token can be freed at 2 places:
	 *  - if the token is not interrupted: it will be freed in uninstall, as info->interrupt_token has not been replaced
	 *     by the INTERRUPT_STATE flag value, and it still contains the pointer to the memory location
	 *  - if the token is interrupted: it will be freed in finish, as the token is now owned by the prepare/finish
	 *     functions, and info->interrupt_token does not contains a pointer to the memory anymore */
	token = g_new0 (MonoThreadInfoInterruptToken, 1);
	token->callback = callback;
	token->data = data;

	previous_token = (MonoThreadInfoInterruptToken *)InterlockedCompareExchangePointer ((gpointer*) &info->interrupt_token, token, NULL);

	if (previous_token) {
		if (previous_token != INTERRUPT_STATE)
			g_error ("mono_thread_info_install_interrupt: previous_token should be INTERRUPT_STATE (%p), but it was %p", INTERRUPT_STATE, previous_token);

		g_free (token);

		*interrupted = TRUE;
	}

	THREADS_INTERRUPT_DEBUG ("interrupt install    tid %p token %p previous_token %p interrupted %s\n",
		mono_thread_info_get_tid (info), token, previous_token, *interrupted ? "TRUE" : "FALSE");
}
コード例 #9
0
static void CALLBACK
abort_apc (ULONG_PTR param)
{
	THREADS_INTERRUPT_DEBUG ("%06d - abort_apc () called", GetCurrentThreadId ());
}