Beispiel #1
0
/* LOCKING: assumes the GC lock is held */
void
sgen_client_stop_world (int generation)
{
	TV_DECLARE (end_handshake);

	/* notify the profiler of the leftovers */
	/* FIXME this is the wrong spot at we can STW for non collection reasons. */
	if (G_UNLIKELY (mono_profiler_events & MONO_PROFILE_GC_MOVES))
		mono_sgen_gc_event_moves ();

	acquire_gc_locks ();

	mono_profiler_gc_event (MONO_GC_EVENT_PRE_STOP_WORLD_LOCKED, generation);

	/* We start to scan after locks are taking, this ensures we won't be interrupted. */
	sgen_process_togglerefs ();

	update_current_thread_stack (&generation);

	sgen_global_stop_count++;
	SGEN_LOG (3, "stopping world n %d from %p %p", sgen_global_stop_count, mono_thread_info_current (), (gpointer) (gsize) mono_native_thread_id_get ());
	TV_GETTIME (stop_world_time);

	sgen_unified_suspend_stop_world ();

	SGEN_LOG (3, "world stopped");

	TV_GETTIME (end_handshake);
	time_stop_world += TV_ELAPSED (stop_world_time, end_handshake);

	sgen_memgov_collection_start (generation);
	if (sgen_need_bridge_processing ())
		sgen_bridge_reset_data ();
}
Beispiel #2
0
int
mono_w32socket_sendto (SOCKET sock, const char *buf, int len, int flags, const struct sockaddr *to, int tolen, gboolean blocking)
{
	gpointer handle;
	int ret;
	MonoThreadInfo *info;

	handle = GUINT_TO_POINTER (sock);
	if (mono_w32handle_get_type (handle) != MONO_W32HANDLE_SOCKET) {
		mono_w32socket_set_last_error (WSAENOTSOCK);
		return SOCKET_ERROR;
	}

	info = mono_thread_info_current ();

	do {
		ret = sendto (sock, buf, len, flags, to, tolen);
	} while (ret == -1 && errno == EINTR &&  !mono_thread_info_is_interrupt_state (info));

	if (ret == -1) {
		gint errnum = errno;
		mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: send error: %s", __func__, g_strerror (errno));
		mono_w32socket_set_last_error (mono_w32socket_convert_error (errnum));
		return SOCKET_ERROR;
	}
	return ret;
}
Beispiel #3
0
void
mono_thread_info_self_suspend (void)
{
	gboolean ret;
	MonoThreadInfo *info = mono_thread_info_current ();
	if (!info)
		return;

	MONO_SEM_WAIT_UNITERRUPTIBLE (&info->suspend_semaphore);

	THREADS_DEBUG ("self suspend IN COUNT %d\n", info->suspend_count);

	g_assert (info->suspend_count == 0);
	++info->suspend_count;

	info->thread_state |= STATE_SELF_SUSPENDED;

	ret = mono_threads_get_runtime_callbacks ()->thread_state_init_from_sigctx (&info->suspend_state, NULL);
	g_assert (ret);

	MONO_SEM_POST (&info->suspend_semaphore);

	MONO_SEM_WAIT_UNITERRUPTIBLE (&info->resume_semaphore);

	g_assert (!info->async_target); /*FIXME this should happen normally for suspend. */
	MONO_SEM_POST (&info->finish_resume_semaphore);
}
int
sgen_thread_handshake (BOOL suspend)
{
	int count, result;
	SgenThreadInfo *info;
	int signum = suspend ? suspend_signal_num : restart_signal_num;

	MonoNativeThreadId me = mono_native_thread_id_get ();

	count = 0;
	mono_thread_info_current ()->client_info.suspend_done = TRUE;
	FOREACH_THREAD_SAFE (info) {
		if (mono_native_thread_id_equals (mono_thread_info_get_tid (info), me)) {
			continue;
		}
		info->client_info.suspend_done = FALSE;
		if (info->client_info.gc_disabled)
			continue;
		/*if (signum == suspend_signal_num && info->stop_count == global_stop_count)
			continue;*/
		result = mono_threads_pthread_kill (info, signum);
		if (result == 0) {
			count++;
		} else {
			info->client_info.skip = 1;
		}
	} END_FOREACH_THREAD_SAFE

	sgen_wait_for_suspend_ack (count);

	SGEN_LOG (4, "%s handshake for %d threads\n", suspend ? "suspend" : "resume", count);

	return count;
}
Beispiel #5
0
static void
socket_close (gpointer handle, gpointer data)
{
	int ret;
	MonoW32HandleSocket *socket_handle = (MonoW32HandleSocket *)data;
	MonoThreadInfo *info = mono_thread_info_current ();

	mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: closing socket handle %p", __func__, handle);

	/* Shutdown the socket for reading, to interrupt any potential
	 * receives that may be blocking for data.  See bug 75705. */
	shutdown (GPOINTER_TO_UINT (handle), SHUT_RD);

	do {
		ret = close (GPOINTER_TO_UINT(handle));
	} while (ret == -1 && errno == EINTR &&
		 !mono_thread_info_is_interrupt_state (info));

	if (ret == -1) {
		gint errnum = errno;
		mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: close error: %s", __func__, g_strerror (errno));
		if (!in_cleanup)
			mono_w32socket_set_last_error (mono_w32socket_convert_error (errnum));
	}

	if (!in_cleanup)
		socket_handle->saved_error = 0;
}
Beispiel #6
0
static int
_wapi_sendmsg(guint32 fd,  const struct msghdr *msg, int send_flags)
{
	gpointer handle = GUINT_TO_POINTER (fd);
	int ret;
	MonoThreadInfo *info = mono_thread_info_current ();
	
	if (mono_w32handle_get_type (handle) != MONO_W32HANDLE_SOCKET) {
		WSASetLastError (WSAENOTSOCK);
		return(SOCKET_ERROR);
	}
	
	do {
		ret = sendmsg (fd, msg, send_flags);
	} while (ret == -1 && errno == EINTR &&
		 !mono_thread_info_is_interrupt_state (info));

	if (ret == -1) {
		gint errnum = errno;
		MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: sendmsg error: %s", __func__, strerror (errno));

		errnum = errno_to_WSA (errnum, __func__);
		WSASetLastError (errnum);
		
		return(SOCKET_ERROR);
	}
	return(ret);
}
Beispiel #7
0
/* LOCKING: assumes the GC lock is held */
int
sgen_thread_handshake (BOOL suspend)
{
	SgenThreadInfo *cur_thread = mono_thread_info_current ();
	kern_return_t ret;
	SgenThreadInfo *info;

	int count = 0;

	FOREACH_THREAD_SAFE (info) {
		if (info == cur_thread || sgen_is_worker_thread (mono_thread_info_get_tid (info)))
			continue;
		if (info->gc_disabled)
			continue;

		if (suspend) {
			if (!sgen_suspend_thread (info))
				continue;
		} else {
			ret = thread_resume (info->info.native_handle);
			if (ret != KERN_SUCCESS)
				continue;
		}
		count ++;
	} END_FOREACH_THREAD_SAFE
	return count;
}
Beispiel #8
0
gboolean
mono_thread_info_resume (MonoNativeThreadId tid)
{
	gboolean result = TRUE;
	MonoThreadHazardPointers *hp = mono_hazard_pointer_get ();	
	MonoThreadInfo *info = mono_thread_info_lookup (tid); /*info on HP1*/
	if (!info)
		return FALSE;

	MONO_SEM_WAIT_UNITERRUPTIBLE (&info->suspend_semaphore);

	THREADS_DEBUG ("resume %x IN COUNT %d\n",tid, info->suspend_count);

	if (info->suspend_count <= 0) {
		MONO_SEM_POST (&info->suspend_semaphore);
		mono_hazard_pointer_clear (hp, 1);
		return FALSE;
	}

	/*
	 * The theory here is that if we manage to suspend the thread it means it did not
	 * start cleanup since it take the same lock. 
	*/
	g_assert (mono_thread_info_get_tid (info));

	if (--info->suspend_count == 0)
		result = mono_thread_info_resume_internal (info);

	MONO_SEM_POST (&info->suspend_semaphore);
	mono_hazard_pointer_clear (hp, 1);
	mono_atomic_store_release (&mono_thread_info_current ()->inside_critical_region, FALSE);

	return result;
}
Beispiel #9
0
static void
mono_sgen_ssb_wbarrier_object_copy (MonoObject* obj, MonoObject *src)
{
	int size;
	RememberedSet *rs;
	TLAB_ACCESS_INIT;

	size = mono_object_class (obj)->instance_size;

	rs = REMEMBERED_SET;
	DEBUG (6, fprintf (gc_debug_file, "Adding object remset for %p\n", obj));

	LOCK_GC;
	/* do not copy the sync state */
	mono_gc_memmove ((char*)obj + sizeof (MonoObject), (char*)src + sizeof (MonoObject),
			size - sizeof (MonoObject));

	if (rs->store_next < rs->end_set) {
		*(rs->store_next++) = (mword)obj | REMSET_OBJECT;
		UNLOCK_GC;
		return;
	}
	rs = mono_sgen_alloc_remset (rs->end_set - rs->data, (void*)1, FALSE);
	rs->next = REMEMBERED_SET;
	REMEMBERED_SET = rs;

	#ifdef HAVE_KW_THREAD
	mono_thread_info_current ()->remset = rs;
	#endif
	*(rs->store_next++) = (mword)obj | REMSET_OBJECT;
	UNLOCK_GC;
}
Beispiel #10
0
mono_handle_new_interior (gpointer rawptr, const char *owner)
#endif
{
	MonoThreadInfo *info = mono_thread_info_current ();
	HandleStack *handles = (HandleStack *)info->handle_stack;
	HandleChunk *top = handles->interior;
#ifdef MONO_HANDLE_TRACK_SP
	mono_handle_chunk_leak_check (handles);
#endif

	g_assert (top);

	/*
	 * Don't extend the chunk now, interior handles are
	 * only used for icall arguments, they shouldn't
	 * overflow.
	 */
	g_assert (top->size < OBJECTS_PER_HANDLES_CHUNK);
	int idx = top->size;
	gpointer *objslot = &top->elems [idx].o;
	*objslot = NULL;
	mono_memory_write_barrier ();
	top->size++;
	mono_memory_write_barrier ();
	*objslot = rawptr;
	SET_OWNER (top,idx);
	SET_SP (handles, top, idx);
	return objslot;
}
Beispiel #11
0
static void
mono_sgen_ssb_wbarrier_arrayref_copy (gpointer dest_ptr, gpointer src_ptr, int count)
{
	RememberedSet *rs;
	TLAB_ACCESS_INIT;
	LOCK_GC;
	mono_gc_memmove (dest_ptr, src_ptr, count * sizeof (gpointer));

	rs = REMEMBERED_SET;
	DEBUG (8, fprintf (gc_debug_file, "Adding remset at %p, %d\n", dest_ptr, count));
	if (rs->store_next + 1 < rs->end_set) {
		*(rs->store_next++) = (mword)dest_ptr | REMSET_RANGE;
		*(rs->store_next++) = count;
		UNLOCK_GC;
		return;
	}
	rs = mono_sgen_alloc_remset (rs->end_set - rs->data, (void*)1, FALSE);
	rs->next = REMEMBERED_SET;
	REMEMBERED_SET = rs;
#ifdef HAVE_KW_THREAD
	mono_thread_info_current ()->remset = rs;
#endif
	*(rs->store_next++) = (mword)dest_ptr | REMSET_RANGE;
	*(rs->store_next++) = count;

	UNLOCK_GC;
}
Beispiel #12
0
static void
mono_sgen_ssb_wbarrier_value_copy (gpointer dest, gpointer src, int count, MonoClass *klass)
{
	RememberedSet *rs;
	size_t element_size = mono_class_value_size (klass, NULL);
	size_t size = count * element_size;
	TLAB_ACCESS_INIT;

	g_assert (klass->gc_descr_inited);

	LOCK_GC;
	mono_gc_memmove (dest, src, size);
	rs = REMEMBERED_SET;

	if (rs->store_next + 4 < rs->end_set) {
		*(rs->store_next++) = (mword)dest | REMSET_VTYPE;
		*(rs->store_next++) = (mword)klass->gc_descr;
		*(rs->store_next++) = (mword)count;
		*(rs->store_next++) = (mword)element_size;
		UNLOCK_GC;
		return;
	}
	rs = mono_sgen_alloc_remset (rs->end_set - rs->data, (void*)1, FALSE);
	rs->next = REMEMBERED_SET;
	REMEMBERED_SET = rs;
#ifdef HAVE_KW_THREAD
	mono_thread_info_current ()->remset = rs;
#endif
	*(rs->store_next++) = (mword)dest | REMSET_VTYPE;
	*(rs->store_next++) = (mword)klass->gc_descr;
	*(rs->store_next++) = (mword)count;
	*(rs->store_next++) = (mword)element_size;
	UNLOCK_GC;
}	
Beispiel #13
0
static void
restart_handler (int sig)
{
	SgenThreadInfo *info;
	int old_errno = errno;

	info = mono_thread_info_current ();
	/*
	If the thread info is null is means we're currently in the process of cleaning up,
	the pthread destructor has already kicked in and it has explicitly invoked the suspend handler.
	
	This means this thread has been suspended, TLS is dead, so the only option we have is to
	rely on pthread_self () and seatch over the thread list.
	*/
	if (!info)
		info = (SgenThreadInfo*)mono_thread_info_lookup (pthread_self ());

	/*
	 * If a thread is dying there might be no thread info.  In
	 * that case we rely on info->doing_handshake.
	 */
	if (info) {
		info->signal = restart_signal_num;
		DEBUG (4, fprintf (gc_debug_file, "Restart handler in %p %p\n", info, (gpointer)mono_native_thread_id_get ()));
	}
	errno = old_errno;
}
Beispiel #14
0
void
mono_thread_info_self_suspend (void)
{
	gboolean ret;
	MonoThreadInfo *info = mono_thread_info_current ();
	if (!info)
		return;

	EnterCriticalSection (&info->suspend_lock);

	THREADS_DEBUG ("self suspend IN COUNT %d\n", info->suspend_count);

	g_assert (info->suspend_count == 0);
	++info->suspend_count;

	info->thread_state |= STATE_SELF_SUSPENDED;

	ret = mono_threads_get_runtime_callbacks ()->thread_state_init_from_sigctx (&info->suspend_state, NULL);
	g_assert (ret);

	LeaveCriticalSection (&info->suspend_lock);

	while (MONO_SEM_WAIT (&info->resume_semaphore) != 0) {
		/*if (EINTR != errno) ABORT("sem_wait failed"); */
	}

	g_assert (!info->async_target); /*FIXME this should happen normally for suspend. */
	MONO_SEM_POST (&info->finish_resume_semaphore);
}
Beispiel #15
0
int
sgen_thread_handshake (BOOL suspend)
{
	SgenThreadInfo *info;
	SgenThreadInfo *current = mono_thread_info_current ();
	int count = 0;

	current->client_info.suspend_done = TRUE;
	FOREACH_THREAD_SAFE (info) {
		if (info == current)
			continue;
		info->client_info.suspend_done = FALSE;
		if (info->client_info.gc_disabled)
			continue;
		if (suspend) {
			if (!sgen_suspend_thread (info))
				continue;
		} else {
			if (!sgen_resume_thread (info))
				continue;
		}
		++count;
	} END_FOREACH_THREAD_SAFE
	return count;
}
Beispiel #16
0
/* LOCKING: assumes the GC lock is held */
int
sgen_stop_world (int generation)
{
	int count, dead;

	mono_profiler_gc_event (MONO_GC_EVENT_PRE_STOP_WORLD, generation);
	MONO_GC_WORLD_STOP_BEGIN ();
	acquire_gc_locks ();

	/* We start to scan after locks are taking, this ensures we won't be interrupted. */
	sgen_process_togglerefs ();

	update_current_thread_stack (&count);

	sgen_global_stop_count++;
	SGEN_LOG (3, "stopping world n %d from %p %p", sgen_global_stop_count, mono_thread_info_current (), (gpointer)mono_native_thread_id_get ());
	TV_GETTIME (stop_world_time);
	count = sgen_thread_handshake (TRUE);
	dead = restart_threads_until_none_in_managed_allocator ();
	if (count < dead)
		g_error ("More threads have died (%d) that been initialy suspended %d", dead, count);
	count -= dead;

	SGEN_LOG (3, "world stopped %d thread(s)", count);
	mono_profiler_gc_event (MONO_GC_EVENT_POST_STOP_WORLD, generation);
	MONO_GC_WORLD_STOP_END ();

	sgen_memgov_collection_start (generation);
	sgen_bridge_reset_data ();

	return count;
}
/*
Check the current state of the thread and try to init a self suspend.
This must be called with self state saved.

Returns one of the following values:

- Resumed: Async resume happened and current thread should keep running
- Suspend: Caller should wait for a resume signal
- SelfSuspendNotifyAndWait: Notify the suspend initiator and wait for a resume signals
 suspend should start.

*/
MonoSelfSupendResult
mono_threads_transition_state_poll (MonoThreadInfo *info)
{
	int raw_state, cur_state, suspend_count;
	g_assert (info == mono_thread_info_current ());

retry_state_change:
	UNWRAP_THREAD_STATE (raw_state, cur_state, suspend_count, info);
	switch (cur_state) {
	case STATE_RUNNING:
		g_assert (suspend_count == 0);
		trace_state_change ("STATE_POLL", info, raw_state, cur_state, 0);
		return SelfSuspendResumed; //We're fine, don't suspend

	case STATE_ASYNC_SUSPEND_REQUESTED: //Async suspend requested, service it with a self suspend
	case STATE_SELF_SUSPEND_REQUESTED: //Start the self suspend process
		g_assert (suspend_count > 0);
		if (InterlockedCompareExchange (&info->thread_state, build_thread_state (STATE_SELF_SUSPENDED, suspend_count), raw_state) != raw_state)
			goto retry_state_change;
		trace_state_change ("STATE_POLL", info, raw_state, STATE_SELF_SUSPENDED, 0);
		if (cur_state == STATE_SELF_SUSPEND_REQUESTED)
			return SelfSuspendWait; //Caller should wait for resume
		else
			return SelfSuspendNotifyAndWait; //Caller should notify suspend initiator and wait for resume

/*
STATE_ASYNC_SUSPENDED: Code should not be running while suspended.
STATE_SELF_SUSPENDED: Code should not be running while suspended.
STATE_BLOCKING:
STATE_BLOCKING_AND_SUSPENDED: Pool is a local state transition. No VM activities are allowed while in blocking mode.
*/
	default:
		g_error ("Cannot transition thread %p from %s with STATE_POLL", info, state_name (cur_state));
	}
}
Beispiel #18
0
/* Actual handles implementation */
MonoRawHandle
mono_handle_new (MonoObject *object)
{
	MonoThreadInfo *info = mono_thread_info_current ();
	HandleStack *handles = (HandleStack *)info->handle_stack;
	HandleChunk *top = handles->top;

retry:
	if (G_LIKELY (top->size < OBJECTS_PER_HANDLES_CHUNK)) {
		MonoObject **h = &top->objects [top->size++];
		*h = object;
		return h;
	}
	if (G_LIKELY (top->next)) {
		top = top->next;
		top->size = 0;
		handles->top = top;
		goto retry;
	}
	HandleChunk *new_chunk = g_new (HandleChunk, 1);
	new_chunk->size = 0;
	new_chunk->prev = top;
	new_chunk->next = NULL;
	top->next = new_chunk;
	handles->top = new_chunk;
	goto retry;
}
Beispiel #19
0
static void
suspend_signal_handler (int _dummy, siginfo_t *info, void *context)
{
	MonoThreadInfo *current = mono_thread_info_current ();
	gboolean ret;
	
	if (current->syscall_break_signal) {
		current->syscall_break_signal = FALSE;
		return;
	}

	ret = mono_threads_get_runtime_callbacks ()->thread_state_init_from_sigctx (&current->suspend_state, context);

	g_assert (ret);

	MONO_SEM_POST (&current->suspend_semaphore);
		
	while (MONO_SEM_WAIT (&current->resume_semaphore) != 0) {
		/*if (EINTR != errno) ABORT("sem_wait failed"); */
	}

	if (current->async_target) {
#if MONO_ARCH_HAS_MONO_CONTEXT
		MonoContext tmp = current->suspend_state.ctx;
		mono_threads_get_runtime_callbacks ()->setup_async_callback (&tmp, current->async_target, current->user_data);
		current->async_target = current->user_data = NULL;
		mono_monoctx_to_sigctx (&tmp, context);
#else
		g_error ("The new interruption machinery requires a working mono-context");
#endif
	}

	MONO_SEM_POST (&current->finish_resume_semaphore);
}
Beispiel #20
0
void
mono_thread_info_end_self_suspend (void)
{
	MonoThreadInfo *info;

	info = mono_thread_info_current ();
	if (!info)
		return;
	THREADS_SUSPEND_DEBUG ("FINISH SELF SUSPEND OF %p\n", info);

	mono_threads_get_runtime_callbacks ()->thread_state_init (&info->thread_saved_state [SELF_SUSPEND_STATE_INDEX]);

	/* commit the saved state and notify others if needed */
	switch (mono_threads_transition_state_poll (info)) {
	case SelfSuspendResumed:
		return;
	case SelfSuspendWait:
		mono_thread_info_wait_for_resume (info);
		break;
	case SelfSuspendNotifyAndWait:
		mono_threads_notify_initiator_of_suspend (info);
		mono_thread_info_wait_for_resume (info);
		mono_threads_notify_initiator_of_resume (info);
		break;
	}
}
Beispiel #21
0
/* LOCKING: assumes the GC lock is held */
int
sgen_thread_handshake (BOOL suspend)
{
	SgenThreadInfo *cur_thread = mono_thread_info_current ();
	kern_return_t ret;

	int count = 0;

	cur_thread->client_info.suspend_done = TRUE;
	FOREACH_THREAD (info) {
		if (info == cur_thread || sgen_thread_pool_is_thread_pool_thread (mono_thread_info_get_tid (info)))
			continue;

		info->client_info.suspend_done = FALSE;
		if (info->client_info.gc_disabled)
			continue;

		if (suspend) {
			if (!sgen_suspend_thread (info))
				continue;
		} else {
			do {
				ret = thread_resume (info->client_info.info.native_handle);
			} while (ret == KERN_ABORTED);
			if (ret != KERN_SUCCESS)
				continue;
		}
		count ++;
	} FOREACH_THREAD_END
	return count;
}
Beispiel #22
0
static void
dump_threads (void)
{
	MonoThreadInfo *info;
	MonoThreadInfo *cur = mono_thread_info_current ();

	MOSTLY_ASYNC_SAFE_PRINTF ("STATE CUE CARD: (? means a positive number, usually 1 or 2, * means any number)\n");
	MOSTLY_ASYNC_SAFE_PRINTF ("\t0x0\t- starting (GOOD, unless the thread is running managed code)\n");
	MOSTLY_ASYNC_SAFE_PRINTF ("\t0x1\t- running (BAD, unless it's the gc thread)\n");
	MOSTLY_ASYNC_SAFE_PRINTF ("\t0x2\t- detached (GOOD, unless the thread is running managed code)\n");
	MOSTLY_ASYNC_SAFE_PRINTF ("\t0x?03\t- async suspended (GOOD)\n");
	MOSTLY_ASYNC_SAFE_PRINTF ("\t0x?04\t- self suspended (GOOD)\n");
	MOSTLY_ASYNC_SAFE_PRINTF ("\t0x?05\t- async suspend requested (BAD)\n");
	MOSTLY_ASYNC_SAFE_PRINTF ("\t0x?06\t- self suspend requested (BAD)\n");
	MOSTLY_ASYNC_SAFE_PRINTF ("\t0x*07\t- blocking (GOOD)\n");
	MOSTLY_ASYNC_SAFE_PRINTF ("\t0x?08\t- blocking with pending suspend (GOOD)\n");

	FOREACH_THREAD_SAFE (info) {
#ifdef TARGET_MACH
		char thread_name [256] = { 0 };
		pthread_getname_np (mono_thread_info_get_tid (info), thread_name, 255);

		MOSTLY_ASYNC_SAFE_PRINTF ("--thread %p id %p [%p] (%s) state %x  %s\n", info, (void *) mono_thread_info_get_tid (info), (void*)(size_t)info->native_handle, thread_name, info->thread_state, info == cur ? "GC INITIATOR" : "" );
#else
		MOSTLY_ASYNC_SAFE_PRINTF ("--thread %p id %p [%p] state %x  %s\n", info, (void *) mono_thread_info_get_tid (info), (void*)(size_t)info->native_handle, info->thread_state, info == cur ? "GC INITIATOR" : "" );
#endif

	} END_FOREACH_THREAD_SAFE
}
Beispiel #23
0
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");
}
Beispiel #24
0
int
sgen_thread_handshake (BOOL suspend)
{
	SgenThreadInfo *info;
	SgenThreadInfo *current = mono_thread_info_current ();
	int count = 0;

	FOREACH_THREAD_SAFE (info) {
		info->joined_stw = suspend;
		if (info == current)
			continue;
		if (info->gc_disabled)
			continue;
		if (suspend) {
			g_assert (!info->doing_handshake);
			info->doing_handshake = TRUE;

			if (!sgen_suspend_thread (info))
				continue;
		} else {
			g_assert (info->doing_handshake);
			info->doing_handshake = FALSE;

			if (!sgen_resume_thread (info))
				continue;
		}
		++count;
	} END_FOREACH_THREAD_SAFE
	return count;
}
Beispiel #25
0
/*
 * mono_thread_info_set_is_async_context:
 *
 *   Set whenever the current thread is in an async context. Some runtime functions might behave
 * differently while in an async context in order to be async safe.
 */
void
mono_thread_info_set_is_async_context (gboolean async_context)
{
	MonoThreadInfo *info = mono_thread_info_current ();

	if (info)
		info->is_async_context = async_context;
}
Beispiel #26
0
int _wapi_recvfrom(guint32 fd, void *buf, size_t len, int recv_flags,
		   struct sockaddr *from, socklen_t *fromlen)
{
	gpointer handle = GUINT_TO_POINTER (fd);
	struct _WapiHandle_socket *socket_handle;
	gboolean ok;
	int ret;
	MonoThreadInfo *info = mono_thread_info_current ();
	
	if (mono_w32handle_get_type (handle) != MONO_W32HANDLE_SOCKET) {
		WSASetLastError (WSAENOTSOCK);
		return(SOCKET_ERROR);
	}
	
	do {
		ret = recvfrom (fd, buf, len, recv_flags, from, fromlen);
	} while (ret == -1 && errno == EINTR &&
		 !mono_thread_info_is_interrupt_state (info));

	if (ret == 0 && len > 0) {
		/* According to the Linux man page, recvfrom only
		 * returns 0 when the socket has been shut down
		 * cleanly.  Turn this into an EINTR to simulate win32
		 * behaviour of returning EINTR when a socket is
		 * closed while the recvfrom is blocking (we use a
		 * shutdown() in socket_close() to trigger this.) See
		 * bug 75705.
		 */
		/* Distinguish between the socket being shut down at
		 * the local or remote ends, and reads that request 0
		 * bytes to be read
		 */

		/* If this returns FALSE, it means the socket has been
		 * closed locally.  If it returns TRUE, but
		 * still_readable != 1 then shutdown
		 * (SHUT_RD|SHUT_RDWR) has been called locally.
		 */
		ok = mono_w32handle_lookup (handle, MONO_W32HANDLE_SOCKET,
					  (gpointer *)&socket_handle);
		if (ok == FALSE || socket_handle->still_readable != 1) {
			ret = -1;
			errno = EINTR;
		}
	}
	
	if (ret == -1) {
		gint errnum = errno;
		MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: recv error: %s", __func__, strerror(errno));

		errnum = errno_to_WSA (errnum, __func__);
		WSASetLastError (errnum);
		
		return(SOCKET_ERROR);
	}
	return(ret);
}
Beispiel #27
0
static void
restart_signal_handler (int _dummy, siginfo_t *_info, void *context)
{
	MonoThreadInfo *info;
	int old_errno = errno;

	info = mono_thread_info_current ();
	info->signal = restart_signal_num;
	errno = old_errno;
}
Beispiel #28
0
gboolean
mono_thread_info_is_async_context (void)
{
	MonoThreadInfo *info = mono_thread_info_current ();

	if (info)
		return info->is_async_context;
	else
		return FALSE;
}
Beispiel #29
0
MONO_SIG_HANDLER_FUNC (static, restart_handler)
{
	SgenThreadInfo *info;
	int old_errno = errno;

	info = mono_thread_info_current ();
	info->client_info.signal = restart_signal_num;
	SGEN_LOG (4, "Restart handler in %p %p", info, (gpointer) (gsize) mono_native_thread_id_get ());
	errno = old_errno;
}
Beispiel #30
0
static gboolean
sgen_is_thread_in_current_stw (SgenThreadInfo *info, int *reason)
{
	/*
	A thread explicitly asked to be skiped because it holds no managed state.
	This is used by TP and finalizer threads.
	FIXME Use an atomic variable for this to avoid everyone taking the GC LOCK.
	*/
	if (info->client_info.gc_disabled) {
		if (reason)
			*reason = 1;
		return FALSE;
	}

	/*
	We have detected that this thread is failing/dying, ignore it.
	FIXME: can't we merge this with thread_is_dying?
	*/
	if (info->client_info.skip) {
		if (reason)
			*reason = 2;
		return FALSE;
	}

	/*
	Suspending the current thread will deadlock us, bad idea.
	*/
	if (info == mono_thread_info_current ()) {
		if (reason)
			*reason = 3;
		return FALSE;
	}

	/*
	We can't suspend the workers that will do all the heavy lifting.
	FIXME Use some state bit in SgenThreadInfo for this.
	*/
	if (sgen_thread_pool_is_thread_pool_thread (mono_thread_info_get_tid (info))) {
		if (reason)
			*reason = 4;
		return FALSE;
	}

	/*
	The thread has signaled that it started to detach, ignore it.
	FIXME: can't we merge this with skip
	*/
	if (!mono_thread_info_is_live (info)) {
		if (reason)
			*reason = 5;
		return FALSE;
	}

	return TRUE;
}