예제 #1
0
gboolean
sgen_suspend_thread (SgenThreadInfo *info)
{
	mach_msg_type_number_t num_state;
	thread_state_t state;
	kern_return_t ret;
	ucontext_t ctx;
	mcontext_t mctx;

	gpointer stack_start;

	state = (thread_state_t) alloca (mono_mach_arch_get_thread_state_size ());
	mctx = (mcontext_t) alloca (mono_mach_arch_get_mcontext_size ());

	do {
		ret = thread_suspend (info->client_info.info.native_handle);
	} while (ret == KERN_ABORTED);
	if (ret != KERN_SUCCESS)
		return FALSE;

	do {
		ret = mono_mach_arch_get_thread_state (info->client_info.info.native_handle, state, &num_state);
	} while (ret == KERN_ABORTED);
	if (ret != KERN_SUCCESS)
		return FALSE;

	mono_mach_arch_thread_state_to_mcontext (state, mctx);
	ctx.uc_mcontext = mctx;

	info->client_info.stopped_domain = mono_thread_info_tls_get (info, TLS_KEY_DOMAIN);
	info->client_info.stopped_ip = (gpointer) mono_mach_arch_get_ip (state);
	info->client_info.stack_start = NULL;
	stack_start = (char*) mono_mach_arch_get_sp (state) - REDZONE_SIZE;
	/* If stack_start is not within the limits, then don't set it in info and we will be restarted. */
	if (stack_start >= info->client_info.stack_start_limit && stack_start <= info->client_info.stack_end) {
		info->client_info.stack_start = stack_start;

#ifdef USE_MONO_CTX
		mono_sigctx_to_monoctx (&ctx, &info->client_info.ctx);
#else
		ARCH_COPY_SIGCTX_REGS (&info->client_info.regs, &ctx);
#endif
	} else {
		g_assert (!info->client_info.stack_start);
	}

	/* Notify the JIT */
	if (mono_gc_get_gc_callbacks ()->thread_suspend_func)
		mono_gc_get_gc_callbacks ()->thread_suspend_func (info->client_info.runtime_data, &ctx, NULL);

	SGEN_LOG (2, "thread %p stopped at %p stack_start=%p", (void*)(gsize)info->client_info.info.native_handle, info->client_info.stopped_ip, info->client_info.stack_start);
	binary_protocol_thread_suspend ((gpointer)mono_thread_info_get_tid (info), info->client_info.stopped_ip);

	return TRUE;
}
예제 #2
0
gboolean
sgen_suspend_thread (SgenThreadInfo *info)
{
	DWORD id = mono_thread_info_get_tid (info);
	HANDLE handle = OpenThread (THREAD_ALL_ACCESS, FALSE, id);
	CONTEXT context;
	DWORD result;

	g_assert (id != GetCurrentThreadId ());

	g_assert (handle);

	result = SuspendThread (handle);
	if (result == (DWORD)-1) {
		fprintf (stderr, "could not suspend thread %x (handle %p): %d\n", id, handle, GetLastError ()); fflush (stderr);
		CloseHandle (handle);
		return FALSE;
	}

	context.ContextFlags = CONTEXT_INTEGER | CONTEXT_CONTROL;

	if (!GetThreadContext (handle, &context)) {
		g_assert_not_reached ();
		ResumeThread (handle);
		CloseHandle (handle);
		return FALSE;
	}

	g_assert (context.ContextFlags & CONTEXT_INTEGER);
	g_assert (context.ContextFlags & CONTEXT_CONTROL);

	CloseHandle (handle);

	info->stopped_ip = (gpointer)context.Eip;
	info->stack_start = (char*)context.Esp - REDZONE_SIZE;

	info->regs [0] = context.Edi;
	info->regs [1] = context.Esi;
	info->regs [2] = context.Ebx;
	info->regs [3] = context.Edx;
	info->regs [4] = context.Ecx;
	info->regs [5] = context.Eax;
	info->regs [6] = context.Ebp;
	info->regs [7] = context.Esp;
	info->stopped_regs = &info->regs;

	/* Notify the JIT */
	if (mono_gc_get_gc_callbacks ()->thread_suspend_func)
		mono_gc_get_gc_callbacks ()->thread_suspend_func (info->runtime_data, NULL);

	return TRUE;
}
예제 #3
0
gboolean
mono_sgen_suspend_thread (SgenThreadInfo *info)
{
	DWORD id = mono_thread_info_get_tid (info);
	HANDLE handle = OpenThread (THREAD_ALL_ACCESS, FALSE, id);
	CONTEXT context;
	DWORD result;

	g_assert (handle);

	result = SuspendThread (handle);
	g_assert (result != (DWORD)-1);
	if (result == (DWORD)-1) {
		CloseHandle (handle);
		return FALSE;
	}

	context.ContextFlags = CONTEXT_INTEGER | CONTEXT_CONTROL;

	if (!GetThreadContext (handle, &context)) {
		g_assert_not_reached ();
		ResumeThread (handle);
		CloseHandle (handle);
		return FALSE;
	}

	g_assert (context.ContextFlags & CONTEXT_INTEGER);
	g_assert (context.ContextFlags & CONTEXT_CONTROL);

	CloseHandle (handle);

	info->stopped_domain = NULL; /* FIXME: implement! */
	info->stopped_ip = (gpointer)context.Eip;
	info->stack_start = (char*)context.Esp - REDZONE_SIZE;

	info->regs [0] = context.Edi;
	info->regs [1] = context.Esi;
	info->regs [2] = context.Ebx;
	info->regs [3] = context.Edx;
	info->regs [4] = context.Ecx;
	info->regs [5] = context.Eax;
	info->regs [6] = context.Ebp;
	info->regs [7] = context.Esp;
	info->stopped_regs = &info->regs;

	/* Notify the JIT */
	if (mono_gc_get_gc_callbacks ()->thread_suspend_func)
		mono_gc_get_gc_callbacks ()->thread_suspend_func (info->runtime_data, NULL);

	return TRUE;
}
예제 #4
0
파일: sgen-os-mach.c 프로젝트: mantasp/mono
gboolean
mono_sgen_suspend_thread (SgenThreadInfo *info)
{
	mach_msg_type_number_t num_state;
	thread_state_t state;
	kern_return_t ret;
	ucontext_t ctx;
	mcontext_t mctx;

	gpointer stack_start;

	state = (thread_state_t) alloca (mono_mach_arch_get_thread_state_size ());
	mctx = (mcontext_t) alloca (mono_mach_arch_get_mcontext_size ());

	ret = thread_suspend (info->mach_port);
	if (ret != KERN_SUCCESS)
		return FALSE;

	ret = mono_mach_arch_get_thread_state (info->mach_port, state, &num_state);
	if (ret != KERN_SUCCESS)
		return FALSE;

	mono_mach_arch_thread_state_to_mcontext (state, mctx);
	ctx.uc_mcontext = mctx;

	info->stopped_domain = mono_mach_arch_get_tls_value_from_thread ((pthread_t)info->id, mono_domain_get_tls_offset ());
	info->stopped_ip = (gpointer) mono_mach_arch_get_ip (state);
	stack_start = (char*) mono_mach_arch_get_sp (state) - REDZONE_SIZE;
	/* If stack_start is not within the limits, then don't set it in info and we will be restarted. */
	if (stack_start >= info->stack_start_limit && info->stack_start <= info->stack_end) {
		info->stack_start = stack_start;

#ifdef USE_MONO_CTX
		mono_sigctx_to_monoctx (&ctx, &info->ctx);
		info->monoctx = &info->ctx;
#else
		ARCH_COPY_SIGCTX_REGS (&info->regs, &ctx);
		info->stopped_regs = &info->regs;
#endif
	} else {
		g_assert (!info->stack_start);
	}

	/* Notify the JIT */
	if (mono_gc_get_gc_callbacks ()->thread_suspend_func)
		mono_gc_get_gc_callbacks ()->thread_suspend_func (info->runtime_data, &ctx);
	return TRUE;
}
예제 #5
0
static void
update_current_thread_stack (void *start)
{
	int stack_guard = 0;
	SgenThreadInfo *info = mono_thread_info_current ();

	info->client_info.stack_start = align_pointer (&stack_guard);
	g_assert (info->client_info.stack_start);
	g_assert (info->client_info.stack_start >= info->client_info.stack_start_limit && info->client_info.stack_start < info->client_info.stack_end);

#if !defined(MONO_CROSS_COMPILE) && MONO_ARCH_HAS_MONO_CONTEXT
	MONO_CONTEXT_GET_CURRENT (info->client_info.ctx);
#else
	g_error ("Sgen STW requires a working mono-context");
#endif

	if (mono_gc_get_gc_callbacks ()->thread_suspend_func)
		mono_gc_get_gc_callbacks ()->thread_suspend_func (info->client_info.runtime_data, NULL, &info->client_info.ctx);
}
예제 #6
0
파일: sgen-stw.c 프로젝트: Adamcbrz/mono
static void
update_current_thread_stack (void *start)
{
	int stack_guard = 0;
#if !defined(USE_MONO_CTX)
	void *reg_ptr = cur_thread_regs;
#endif
	SgenThreadInfo *info = mono_thread_info_current ();
	
	info->stack_start = align_pointer (&stack_guard);
	g_assert (info->stack_start >= info->stack_start_limit && info->stack_start < info->stack_end);
#ifdef USE_MONO_CTX
	MONO_CONTEXT_GET_CURRENT (cur_thread_ctx);
	memcpy (&info->ctx, &cur_thread_ctx, sizeof (MonoContext));
	if (mono_gc_get_gc_callbacks ()->thread_suspend_func)
		mono_gc_get_gc_callbacks ()->thread_suspend_func (info->runtime_data, NULL, &info->ctx);
#else
	ARCH_STORE_REGS (reg_ptr);
	memcpy (&info->regs, reg_ptr, sizeof (info->regs));
	if (mono_gc_get_gc_callbacks ()->thread_suspend_func)
		mono_gc_get_gc_callbacks ()->thread_suspend_func (info->runtime_data, NULL, NULL);
#endif
}
예제 #7
0
gboolean
sgen_suspend_thread (SgenThreadInfo *info)
{
	DWORD id = mono_thread_info_get_tid (info);
	HANDLE handle = OpenThread (THREAD_ALL_ACCESS, FALSE, id);
	CONTEXT context;
	DWORD result;

	g_assert (id != GetCurrentThreadId ());

	g_assert (handle);

	result = SuspendThread (handle);
	if (result == (DWORD)-1) {
		fprintf (stderr, "could not suspend thread %x (handle %p): %d\n", id, handle, GetLastError ()); fflush (stderr);
		CloseHandle (handle);
		return FALSE;
	}

	context.ContextFlags = CONTEXT_INTEGER | CONTEXT_CONTROL;

	if (!GetThreadContext (handle, &context)) {
		g_assert_not_reached ();
		ResumeThread (handle);
		CloseHandle (handle);
		return FALSE;
	}

	g_assert (context.ContextFlags & CONTEXT_INTEGER);
	g_assert (context.ContextFlags & CONTEXT_CONTROL);

	CloseHandle (handle);

#if !defined(MONO_CROSS_COMPILE)
#ifdef USE_MONO_CTX
	memset (&info->ctx, 0, sizeof (MonoContext));
#ifdef TARGET_AMD64
	info->ctx.rip = context.Rip;
	info->ctx.rax = context.Rax;
	info->ctx.rcx = context.Rcx;
	info->ctx.rdx = context.Rdx;
	info->ctx.rbx = context.Rbx;
	info->ctx.rsp = context.Rsp;
	info->ctx.rbp = context.Rbp;
	info->ctx.rsi = context.Rsi;
	info->ctx.rdi = context.Rdi;
	info->ctx.r8 = context.R8;
	info->ctx.r9 = context.R9;
	info->ctx.r10 = context.R10;
	info->ctx.r11 = context.R11;
	info->ctx.r12 = context.R12;
	info->ctx.r13 = context.R13;
	info->ctx.r14 = context.R14;
	info->ctx.r15 = context.R15;
	info->stopped_ip = info->ctx.rip;
	info->stack_start = (char*)info->ctx.rsp - REDZONE_SIZE;
#else
	info->ctx.edi = context.Edi;
	info->ctx.esi = context.Esi;
	info->ctx.ebx = context.Ebx;
	info->ctx.edx = context.Edx;
	info->ctx.ecx = context.Ecx;
	info->ctx.eax = context.Eax;
	info->ctx.ebp = context.Ebp;
	info->ctx.esp = context.Esp;
	info->stopped_ip = (gpointer)context.Eip;
	info->stack_start = (char*)context.Esp - REDZONE_SIZE;
#endif

#else
	info->regs [0] = context.Edi;
	info->regs [1] = context.Esi;
	info->regs [2] = context.Ebx;
	info->regs [3] = context.Edx;
	info->regs [4] = context.Ecx;
	info->regs [5] = context.Eax;
	info->regs [6] = context.Ebp;
	info->regs [7] = context.Esp;
	info->stopped_ip = (gpointer)context.Eip;
	info->stack_start = (char*)context.Esp - REDZONE_SIZE;
#endif
#endif

	/* Notify the JIT */
	if (mono_gc_get_gc_callbacks ()->thread_suspend_func)
		mono_gc_get_gc_callbacks ()->thread_suspend_func (info->runtime_data, NULL, NULL);

	return TRUE;
}
예제 #8
0
static void
suspend_thread (SgenThreadInfo *info, void *context)
{
	int stop_count;
#ifndef USE_MONO_CTX
	gpointer regs [ARCH_NUM_REGS];
#endif
	MonoContext ctx;
	gpointer stack_start;

	info->client_info.stopped_domain = mono_domain_get ();
	info->client_info.signal = 0;
	stop_count = sgen_global_stop_count;
	/* duplicate signal */
	if (0 && info->client_info.stop_count == stop_count)
		return;

#ifdef USE_MONO_CTX
	if (context) {
		mono_sigctx_to_monoctx (context, &ctx);
		info->client_info.stopped_ip = MONO_CONTEXT_GET_IP (&ctx);
		stack_start = (((guint8 *) MONO_CONTEXT_GET_SP (&ctx)) - REDZONE_SIZE);
	} else {
		info->client_info.stopped_ip = NULL;
		stack_start = NULL;
	}
#else
	info->client_info.stopped_ip = context ? (gpointer) ARCH_SIGCTX_IP (context) : NULL;
	stack_start = context ? (char*) ARCH_SIGCTX_SP (context) - REDZONE_SIZE : NULL;
#endif

	/* If stack_start is not within the limits, then don't set it
	   in info and we will be restarted. */
	if (stack_start >= info->client_info.stack_start_limit && stack_start <= info->client_info.stack_end) {
		info->client_info.stack_start = stack_start;

#ifdef USE_MONO_CTX
		if (context) {
			memcpy (&info->client_info.ctx, &ctx, sizeof (MonoContext));
		} else {
			memset (&info->client_info.ctx, 0, sizeof (MonoContext));
		}
#else
		if (context) {
			ARCH_COPY_SIGCTX_REGS (regs, context);
			memcpy (&info->client_info.regs, regs, sizeof (info->client_info.regs));
		} else {
			memset (&info->client_info.regs, 0, sizeof (info->client_info.regs));
		}
#endif
	} else {
		g_assert (!info->client_info.stack_start);
	}

	/* Notify the JIT */
	if (mono_gc_get_gc_callbacks ()->thread_suspend_func)
		mono_gc_get_gc_callbacks ()->thread_suspend_func (info->client_info.runtime_data, context, NULL);

	SGEN_LOG (4, "Posting suspend_ack_semaphore for suspend from %p %p", info, (gpointer) (gsize) mono_native_thread_id_get ());

	/*
	Block the restart signal. 
	We need to block the restart signal while posting to the suspend_ack semaphore or we race to sigsuspend,
	which might miss the signal and get stuck.
	*/
	pthread_sigmask (SIG_BLOCK, &suspend_ack_signal_mask, NULL);

	/* notify the waiting thread */
	SGEN_SEMAPHORE_POST (suspend_ack_semaphore_ptr);
	info->client_info.stop_count = stop_count;

	/* wait until we receive the restart signal */
	do {
		info->client_info.signal = 0;
		sigsuspend (&suspend_signal_mask);
	} while (info->client_info.signal != restart_signal_num);

	/* Unblock the restart signal. */
	pthread_sigmask (SIG_UNBLOCK, &suspend_ack_signal_mask, NULL);

	SGEN_LOG (4, "Posting suspend_ack_semaphore for resume from %p %p\n", info, (gpointer) (gsize) mono_native_thread_id_get ());
	/* notify the waiting thread */
	SGEN_SEMAPHORE_POST (suspend_ack_semaphore_ptr);
}
예제 #9
0
static void
suspend_thread (SgenThreadInfo *info, void *context)
{
	int stop_count;
#ifdef USE_MONO_CTX
	MonoContext monoctx;
#else
	gpointer regs [ARCH_NUM_REGS];
#endif
	gpointer stack_start;

	g_assert (info->doing_handshake);

	info->stopped_domain = mono_domain_get ();
	info->stopped_ip = context ? (gpointer) ARCH_SIGCTX_IP (context) : NULL;
	stop_count = sgen_global_stop_count;
	/* duplicate signal */
	if (0 && info->stop_count == stop_count)
		return;

	sgen_fill_thread_info_for_suspend (info);

	stack_start = context ? (char*) ARCH_SIGCTX_SP (context) - REDZONE_SIZE : NULL;
	/* If stack_start is not within the limits, then don't set it
	   in info and we will be restarted. */
	if (stack_start >= info->stack_start_limit && info->stack_start <= info->stack_end) {
		info->stack_start = stack_start;

#ifdef USE_MONO_CTX
		if (context) {
			mono_sigctx_to_monoctx (context, &monoctx);
			info->monoctx = &monoctx;
		} else {
			info->monoctx = NULL;
		}
#else
		if (context) {
			ARCH_COPY_SIGCTX_REGS (regs, context);
			info->stopped_regs = regs;
		} else {
			info->stopped_regs = NULL;
		}
#endif
	} else {
		g_assert (!info->stack_start);
	}

	/* Notify the JIT */
	if (mono_gc_get_gc_callbacks ()->thread_suspend_func)
		mono_gc_get_gc_callbacks ()->thread_suspend_func (info->runtime_data, context);

	DEBUG (4, fprintf (gc_debug_file, "Posting suspend_ack_semaphore for suspend from %p %p\n", info, (gpointer)mono_native_thread_id_get ()));

	/*
	Block the restart signal. 
	We need to block the restart signal while posting to the suspend_ack semaphore or we race to sigsuspend,
	which might miss the signal and get stuck.
	*/
	pthread_sigmask (SIG_BLOCK, &suspend_ack_signal_mask, NULL);

	/* notify the waiting thread */
	MONO_SEM_POST (suspend_ack_semaphore_ptr);
	info->stop_count = stop_count;

	/* wait until we receive the restart signal */
	do {
		info->signal = 0;
		sigsuspend (&suspend_signal_mask);
	} while (info->signal != restart_signal_num && info->doing_handshake);

	/* Unblock the restart signal. */
	pthread_sigmask (SIG_UNBLOCK, &suspend_ack_signal_mask, NULL);

	DEBUG (4, fprintf (gc_debug_file, "Posting suspend_ack_semaphore for resume from %p %p\n", info, (gpointer)mono_native_thread_id_get ()));
	/* notify the waiting thread */
	MONO_SEM_POST (suspend_ack_semaphore_ptr);
}
예제 #10
0
int
mono_sgen_thread_handshake (int signum)
{
	task_t task = current_task ();
	thread_port_t cur_thread = mach_thread_self ();
	thread_act_array_t thread_list;
	mach_msg_type_number_t num_threads;
	mach_msg_type_number_t num_state;
	thread_state_t state;
	kern_return_t ret;
	ucontext_t ctx;
	mcontext_t mctx;
	pthread_t exception_thread = mono_gc_get_mach_exception_thread ();

	SgenThreadInfo *info;
	gpointer regs [ARCH_NUM_REGS];
	gpointer stack_start;

	int count, i;

	mono_mach_get_threads (&thread_list, &num_threads);

	for (i = 0, count = 0; i < num_threads; i++) {
		thread_port_t t = thread_list [i];
		pthread_t pt = pthread_from_mach_thread_np (t);
		if (t != cur_thread && pt != exception_thread && !mono_sgen_is_worker_thread (pt)) {
			if (signum == suspend_signal_num) {
				ret = thread_suspend (t);
				if (ret != KERN_SUCCESS) {
					mach_port_deallocate (task, t);
					continue;
				}

				state = (thread_state_t) alloca (mono_mach_arch_get_thread_state_size ());
				ret = mono_mach_arch_get_thread_state (t, state, &num_state);
				if (ret != KERN_SUCCESS) {
					mach_port_deallocate (task, t);
					continue;
				}


				info = mono_sgen_thread_info_lookup (pt);

				/* Ensure that the runtime is aware of this thread */
				if (info != NULL) {
					mctx = (mcontext_t) alloca (mono_mach_arch_get_mcontext_size ());
					mono_mach_arch_thread_state_to_mcontext (state, mctx);
					ctx.uc_mcontext = mctx;

					info->stopped_domain = mono_mach_arch_get_tls_value_from_thread (t, mono_pthread_key_for_tls (mono_domain_get_tls_key ()));
					info->stopped_ip = (gpointer) mono_mach_arch_get_ip (state);
					stack_start = (char*) mono_mach_arch_get_sp (state) - REDZONE_SIZE;
					/* If stack_start is not within the limits, then don't set it in info and we will be restarted. */
					if (stack_start >= info->stack_start_limit && info->stack_start <= info->stack_end) {
						info->stack_start = stack_start;

						ARCH_COPY_SIGCTX_REGS (regs, &ctx);
						info->stopped_regs = regs;
					} else {
						g_assert (!info->stack_start);
					}

					/* Notify the JIT */
					if (mono_gc_get_gc_callbacks ()->thread_suspend_func)
						mono_gc_get_gc_callbacks ()->thread_suspend_func (info->runtime_data, &ctx);
				}
			} else {
				ret = thread_resume (t);
				if (ret != KERN_SUCCESS) {
					mach_port_deallocate (task, t);
					continue;
				}
			}
			count ++;

			mach_port_deallocate (task, t);
		}
	}

	mach_port_deallocate (task, cur_thread);

	return count;
}
예제 #11
0
파일: sgen-os-mach.c 프로젝트: saga/mono
int
mono_sgen_thread_handshake (int signum)
{
	SgenThreadInfo *cur_thread = mono_sgen_thread_info_current ();
	mach_msg_type_number_t num_state;
	thread_state_t state;
	kern_return_t ret;
	ucontext_t ctx;
	mcontext_t mctx;

	SgenThreadInfo *info;
	gpointer stack_start;

	int count = 0;

	state = (thread_state_t) alloca (mono_mach_arch_get_thread_state_size ());
	mctx = (mcontext_t) alloca (mono_mach_arch_get_mcontext_size ());

	FOREACH_THREAD (info) {
		if (info == cur_thread || mono_sgen_is_worker_thread (info->id))
			continue;

		if (signum == suspend_signal_num) {
			ret = thread_suspend (info->mach_port);
			if (ret != KERN_SUCCESS)
				continue;

			ret = mono_mach_arch_get_thread_state (info->mach_port, state, &num_state);
			if (ret != KERN_SUCCESS)
				continue;

			mono_mach_arch_thread_state_to_mcontext (state, mctx);
			ctx.uc_mcontext = mctx;

			info->stopped_domain = mono_mach_arch_get_tls_value_from_thread ((pthread_t)info->id, mono_pthread_key_for_tls (mono_domain_get_tls_key ()));
			info->stopped_ip = (gpointer) mono_mach_arch_get_ip (state);
			stack_start = (char*) mono_mach_arch_get_sp (state) - REDZONE_SIZE;
			/* If stack_start is not within the limits, then don't set it in info and we will be restarted. */
			if (stack_start >= info->stack_start_limit && info->stack_start <= info->stack_end) {
				info->stack_start = stack_start;

#ifdef USE_MONO_CTX
				mono_sigctx_to_monoctx (&ctx, &info->ctx);
				info->monoctx = &info->ctx;
#else
				ARCH_COPY_SIGCTX_REGS (&info->regs, &ctx);
				info->stopped_regs = &info->regs;
#endif
			} else {
				g_assert (!info->stack_start);
			}

			/* Notify the JIT */
			if (mono_gc_get_gc_callbacks ()->thread_suspend_func)
				mono_gc_get_gc_callbacks ()->thread_suspend_func (info->runtime_data, &ctx);
		} else {
			ret = thread_resume (info->mach_port);
			if (ret != KERN_SUCCESS)
				continue;
		}
		count ++;
	} END_FOREACH_THREAD
	return count;
}