static void assertion_fail (const char *msg, ...) { int i; GString* err = g_string_sized_new (100); CheckState *state = get_state (); g_string_append_printf (err, "Assertion failure in thread %p due to: ", mono_native_thread_id_get ()); va_list args; va_start (args, msg); g_string_append_vprintf (err, msg, args); va_end (args); g_string_append_printf (err, "\nLast %d state transitions: (most recent first)\n", state->transitions->len); for (i = state->transitions->len - 1; i >= 0; --i) { ThreadTransition *t = state->transitions->pdata [i]; char *bt = translate_backtrace (t->backtrace, t->size); g_string_append_printf (err, "[%s] %s -> %s (%d) %s%d at:\n%s", t->name, mono_thread_state_name (t->from_state), mono_thread_state_name (t->next_state), t->suspend_count, t->suspend_count_delta > 0 ? "+" : "", //I'd like to see this sort of values: -1, 0, +1 t->suspend_count_delta, bt); g_free (bt); } g_error (err->str); g_string_free (err, TRUE); }
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; }
/* * This is a very specific function whose only purpose is to * break a given thread from socket syscalls. * * This only exists because linux won't fail a call to connect * if the underlying is closed. * * TODO We should cleanup and unify this with the other syscall abort * facility. */ void mono_thread_info_abort_socket_syscall_for_close (MonoNativeThreadId tid) { MonoThreadHazardPointers *hp; MonoThreadInfo *info; if (tid == mono_native_thread_id_get () || !mono_threads_core_needs_abort_syscall ()) return; hp = mono_hazard_pointer_get (); info = mono_thread_info_lookup (tid); if (!info) return; if (mono_thread_info_run_state (info) == STATE_DETACHED) { mono_hazard_pointer_clear (hp, 1); return; } mono_thread_info_suspend_lock (); mono_threads_begin_global_suspend (); mono_threads_core_abort_syscall (info); mono_threads_wait_pending_operations (); mono_hazard_pointer_clear (hp, 1); mono_threads_end_global_suspend (); mono_thread_info_suspend_unlock (); }
void mono_thread_info_safe_suspend_and_run (MonoNativeThreadId id, gboolean interrupt_kernel, MonoSuspendThreadCallback callback, gpointer user_data) { int result; MonoThreadInfo *info = NULL; MonoThreadHazardPointers *hp = mono_hazard_pointer_get (); THREADS_SUSPEND_DEBUG ("SUSPENDING tid %p\n", (void*)id); /*FIXME: unify this with self-suspend*/ g_assert (id != mono_native_thread_id_get ()); mono_thread_info_suspend_lock (); mono_threads_begin_global_suspend (); info = suspend_sync_nolock (id, interrupt_kernel); if (!info) goto done; switch (result = callback (info, user_data)) { case MonoResumeThread: mono_hazard_pointer_set (hp, 1, info); mono_thread_info_core_resume (info); mono_threads_wait_pending_operations (); break; case KeepSuspended: break; default: g_error ("Invalid suspend_and_run callback return value %d", result); } done: mono_hazard_pointer_clear (hp, 1); mono_threads_end_global_suspend (); mono_thread_info_suspend_unlock (); }
static void* register_thread (MonoThreadInfo *info, gpointer baseptr) { gboolean result; mono_thread_info_set_tid (info, mono_native_thread_id_get ()); info->small_id = mono_thread_small_id_alloc (); InitializeCriticalSection (&info->suspend_lock); /*set TLS early so SMR works */ mono_native_tls_set_value (thread_info_key, info); mono_native_tls_set_value (small_id_key, GUINT_TO_POINTER (info->small_id + 1)); THREADS_DEBUG ("registering info %p tid %p small id %x\n", info, mono_thread_info_get_tid (info), info->small_id); if (threads_callbacks.thread_register) { if (threads_callbacks.thread_register (info, baseptr) == NULL) { g_warning ("thread registation failed\n"); g_free (info); return NULL; } } mono_threads_platform_register (info); /*If this fail it means a given thread has been registered twice, which doesn't make sense. */ result = mono_thread_info_insert (info); g_assert (result); return info; }
static void* register_thread (MonoThreadInfo *info, gpointer baseptr) { int small_id = mono_thread_info_register_small_id (); gboolean result; mono_thread_info_set_tid (info, mono_native_thread_id_get ()); info->small_id = small_id; MONO_SEM_INIT (&info->suspend_semaphore, 1); MONO_SEM_INIT (&info->resume_semaphore, 0); MONO_SEM_INIT (&info->finish_resume_semaphore, 0); /*set TLS early so SMR works */ mono_native_tls_set_value (thread_info_key, info); THREADS_DEBUG ("registering info %p tid %p small id %x\n", info, mono_thread_info_get_tid (info), info->small_id); if (threads_callbacks.thread_register) { if (threads_callbacks.thread_register (info, baseptr) == NULL) { g_warning ("thread registation failed\n"); g_free (info); return NULL; } } mono_threads_platform_register (info); info->thread_state = STATE_RUNNING; mono_thread_info_suspend_lock (); /*If this fail it means a given thread has been registered twice, which doesn't make sense. */ result = mono_thread_info_insert (info); g_assert (result); mono_thread_info_suspend_unlock (); return info; }
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; }
int mono_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; FOREACH_THREAD_SAFE (info) { if (mono_native_thread_id_equals (mono_thread_info_get_tid (info), me)) { continue; } /*if (signum == suspend_signal_num && info->stop_count == global_stop_count) continue;*/ if (suspend) { g_assert (!info->doing_handshake); info->doing_handshake = TRUE; } else { g_assert (info->doing_handshake); info->doing_handshake = FALSE; } result = pthread_kill (mono_thread_info_get_tid (info), signum); if (result == 0) { count++; } else { info->skip = 1; } } END_FOREACH_THREAD_SAFE mono_sgen_wait_for_suspend_ack (count); return count; }
MonoThreadInfo* mono_thread_info_current (void) { MonoThreadInfo *info = (MonoThreadInfo*)mono_native_tls_get_value (thread_info_key); if (info) return info; info = mono_thread_info_lookup (mono_native_thread_id_get ()); /*info on HP1*/ /* We might be called during thread cleanup, but we cannot be called after cleanup as happened. The way to distinguish between before, during and after cleanup is the following: -If the TLS key is set, cleanup has not begun; -If the TLS key is clean, but the thread remains registered, cleanup is in progress; -If the thread is nowhere to be found, cleanup has finished. We cannot function after cleanup since there's no way to ensure what will happen. */ g_assert (info); /*We're looking up the current thread which will not be freed until we finish running, so no need to keep it on a HP */ mono_hazard_pointer_clear (mono_hazard_pointer_get (), 1); return info; }
/* * This is a very specific function whose only purpose is to * break a given thread from socket syscalls. * * This only exists because linux won't fail a call to connect * if the underlying is closed. * * TODO We should cleanup and unify this with the other syscall abort * facility. */ void mono_thread_info_abort_socket_syscall_for_close (MonoNativeThreadId tid) { MonoThreadHazardPointers *hp; MonoThreadInfo *info; if (tid == mono_native_thread_id_get () || !mono_threads_core_needs_abort_syscall ()) return; hp = mono_hazard_pointer_get (); info = mono_thread_info_lookup (tid); /*info on HP1*/ if (!info) return; if (mono_thread_info_run_state (info) > STATE_RUNNING) { mono_hazard_pointer_clear (hp, 1); return; } mono_thread_info_suspend_lock (); mono_threads_core_abort_syscall (info); mono_hazard_pointer_clear (hp, 1); mono_thread_info_suspend_unlock (); }
static void protocol_entry (unsigned char type, gpointer data, int size) { int index; BinaryProtocolBuffer *buffer; if (!binary_protocol_file) return; if (sgen_is_worker_thread (mono_native_thread_id_get ())) type |= 0x80; lock_recursive (); retry: buffer = binary_protocol_get_buffer (size + 1); retry_same_buffer: index = buffer->index; if (index + 1 + size > BINARY_PROTOCOL_BUFFER_SIZE) goto retry; if (InterlockedCompareExchange (&buffer->index, index + 1 + size, index) != index) goto retry_same_buffer; /* FIXME: if we're interrupted at this point, we have a buffer entry that contains random data. */ buffer->buffer [index++] = type; memcpy (buffer->buffer + index, data, size); index += size; g_assert (index <= BINARY_PROTOCOL_BUFFER_SIZE); unlock_recursive (); }
/** * Removes the current thread from the thread list. * This must be called from the thread unregister callback and nowhere else. * The current thread must be passed as TLS might have already been cleaned up. */ static void mono_threads_unregister_current_thread (MonoThreadInfo *info) { gboolean result; g_assert (mono_thread_info_get_tid (info) == mono_native_thread_id_get ()); result = mono_thread_info_remove (info); g_assert (result); }
static void indent (int diff) { if (diff < 0) indent_level += diff; if (start_time == 0) start_time = mono_100ns_ticks (); printf ("[%p: %.5f %d] ", (void*)mono_native_thread_id_get (), seconds_since_start (), indent_level); if (diff > 0) indent_level += diff; }
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; }
static void add_alloc_record (char *addr, size_t size, int reason) { int idx = InterlockedIncrement (&next_record) - 1; alloc_records [idx].address = addr; alloc_records [idx].size = size; alloc_records [idx].reason = reason; alloc_records [idx].seq = idx; alloc_records [idx].tid = mono_native_thread_id_get (); }
static void restart_handler (int sig) { SgenThreadInfo *info; int old_errno = errno; info = mono_thread_info_current (); info->signal = restart_signal_num; SGEN_LOG (4, "Restart handler in %p %p", info, (gpointer)mono_native_thread_id_get ()); errno = old_errno; }
static void* register_thread (MonoThreadInfo *info, gpointer baseptr) { size_t stsize = 0; guint8 *staddr = NULL; int small_id = mono_thread_info_register_small_id (); gboolean result; mono_thread_info_set_tid (info, mono_native_thread_id_get ()); info->small_id = small_id; info->handle = g_new0 (MonoThreadHandle, 1); mono_refcount_init (info->handle, thread_handle_destroy); mono_os_event_init (&info->handle->event, FALSE); mono_os_sem_init (&info->resume_semaphore, 0); /*set TLS early so SMR works */ mono_native_tls_set_value (thread_info_key, info); THREADS_DEBUG ("registering info %p tid %p small id %x\n", info, mono_thread_info_get_tid (info), info->small_id); if (threads_callbacks.thread_register) { if (threads_callbacks.thread_register (info, baseptr) == NULL) { // g_warning ("thread registation failed\n"); mono_native_tls_set_value (thread_info_key, NULL); g_free (info); return NULL; } } mono_thread_info_get_stack_bounds (&staddr, &stsize); g_assert (staddr); g_assert (stsize); info->stack_start_limit = staddr; info->stack_end = staddr + stsize; info->stackdata = g_byte_array_new (); mono_threads_suspend_register (info); /* Transition it before taking any locks or publishing itself to reduce the chance of others witnessing a detached thread. We can reasonably expect that until this thread gets published, no other thread will try to manipulate it. */ mono_threads_transition_attach (info); mono_thread_info_suspend_lock (); /*If this fail it means a given thread has been registered twice, which doesn't make sense. */ result = mono_thread_info_insert (info); g_assert (result); mono_thread_info_suspend_unlock (); return info; }
gboolean sgen_memgov_try_alloc_space (mword size, int space) { if (sgen_memgov_available_free_space () < size) { SGEN_ASSERT (4, !sgen_thread_pool_is_thread_pool_thread (mono_native_thread_id_get ()), "Memory shouldn't run out in worker thread"); return FALSE; } SGEN_ATOMIC_ADD_P (allocated_heap, size); sgen_client_total_allocated_heap_changed (allocated_heap); return TRUE; }
MonoThreadHazardPointers* mono_hazard_pointer_get (void) { int small_id = mono_thread_info_get_small_id (); if (small_id < 0) { static MonoThreadHazardPointers emerg_hazard_table; g_warning ("Thread %p may have been prematurely finalized", (gpointer) (gsize) mono_native_thread_id_get ()); return &emerg_hazard_table; } return &hazard_table [small_id]; }
static gboolean set_state (State old_state, State new_state) { SGEN_ASSERT (0, old_state != new_state, "Why are we transitioning to the same state?"); if (new_state == STATE_NOT_WORKING) SGEN_ASSERT (0, old_state == STATE_WORKING, "We can only transition to NOT WORKING from WORKING"); else if (new_state == STATE_WORKING) SGEN_ASSERT (0, old_state == STATE_WORK_ENQUEUED, "We can only transition to WORKING from WORK ENQUEUED"); if (new_state == STATE_NOT_WORKING || new_state == STATE_WORKING) SGEN_ASSERT (6, sgen_thread_pool_is_thread_pool_thread (mono_native_thread_id_get ()), "Only the worker thread is allowed to transition to NOT_WORKING or WORKING"); return InterlockedCompareExchange (&workers_state, new_state, old_state) == old_state; }
/* WARNING: If we are trying to suspend a target that is on a critical region and running a syscall we risk looping forever if @interrupt_kernel is FALSE. So, be VERY carefull in calling this with @interrupt_kernel == FALSE. Info is not put on a hazard pointer as a suspended thread cannot exit and be freed. This function MUST be matched with mono_thread_info_finish_suspend or mono_thread_info_finish_suspend_and_resume */ MonoThreadInfo* mono_thread_info_safe_suspend_sync (MonoNativeThreadId id, gboolean interrupt_kernel) { MonoThreadInfo *info = NULL; int sleep_duration = 0; /*FIXME: unify this with self-suspend*/ g_assert (id != mono_native_thread_id_get ()); mono_thread_info_suspend_lock (); for (;;) { const char *suspend_error = "Unknown error"; if (!(info = mono_thread_info_suspend_sync (id, interrupt_kernel, &suspend_error))) { g_warning ("failed to suspend thread %p due to %s, hopefully it is dead", (gpointer)id, suspend_error); mono_thread_info_suspend_unlock (); return NULL; } /*WARNING: We now are in interrupt context until we resume the thread. */ if (!is_thread_in_critical_region (info)) break; if (!mono_thread_info_core_resume (info)) { g_warning ("failed to resume thread %p, hopefully it is dead", (gpointer)id); mono_hazard_pointer_clear (mono_hazard_pointer_get (), 1); mono_thread_info_suspend_unlock (); return NULL; } THREADS_DEBUG ("restarted thread %p\n", (gpointer)id); if (!sleep_duration) { #ifdef HOST_WIN32 SwitchToThread (); #else sched_yield (); #endif } else { g_usleep (sleep_duration); } sleep_duration += 10; } /* XXX this clears HP 1, so we restated it again */ mono_atomic_store_release (&mono_thread_info_current ()->inside_critical_region, TRUE); mono_thread_info_suspend_unlock (); return info; }
/* WARNING: If we are trying to suspend a target that is on a critical region and running a syscall we risk looping forever if @interrupt_kernel is FALSE. So, be VERY carefull in calling this with @interrupt_kernel == FALSE. */ MonoThreadInfo* mono_thread_info_safe_suspend_sync (MonoNativeThreadId id, gboolean interrupt_kernel) { MonoThreadInfo *info = NULL; int sleep_duration = 0; /*FIXME: unify this with self-suspend*/ g_assert (id != mono_native_thread_id_get ()); mono_thread_info_suspend_lock (); for (;;) { if (!(info = mono_thread_info_suspend_sync (id, interrupt_kernel))) { g_warning ("failed to suspend thread %p, hopefully it is dead", (gpointer)id); mono_thread_info_suspend_unlock (); return NULL; } /*WARNING: We now are in interrupt context until we resume the thread. */ if (!is_thread_in_critical_region (info)) break; if (!mono_thread_info_resume (id)) { g_warning ("failed to result thread %p, hopefully it is dead", (gpointer)id); mono_thread_info_suspend_unlock (); return NULL; } THREADS_DEBUG ("restarted thread %p\n", (gpointer)id); if (!sleep_duration) { #ifdef HOST_WIN32 SwitchToThread (); #else sched_yield (); #endif } else { g_usleep (sleep_duration); } sleep_duration += 10; } mono_thread_info_suspend_unlock (); return info; }
static void restart_handler (int sig) { SgenThreadInfo *info; int old_errno = errno; info = mono_thread_info_current (); /* * 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; }
void mono_native_thread_set_name (MonoNativeThreadId tid, const char *name) { #ifdef __MACH__ /* * We can't set the thread name for other threads, but we can at least make * it work for threads that try to change their own name. */ if (tid != mono_native_thread_id_get ()) return; if (!name) { pthread_setname_np (""); } else { char n [63]; memcpy (n, name, sizeof (n) - 1); n [sizeof (n) - 1] = '\0'; pthread_setname_np (n); } #elif defined (__NetBSD__) if (!name) { pthread_setname_np (tid, "%s", (void*)""); } else { char n [PTHREAD_MAX_NAMELEN_NP]; memcpy (n, name, sizeof (n) - 1); n [sizeof (n) - 1] = '\0'; pthread_setname_np (tid, "%s", (void*)n); } #elif defined (HAVE_PTHREAD_SETNAME_NP) if (!name) { pthread_setname_np (tid, ""); } else { char n [16]; memcpy (n, name, sizeof (n) - 1); n [sizeof (n) - 1] = '\0'; pthread_setname_np (tid, n); } #endif }
MONO_SIG_HANDLER_FUNC (static, profiler_signal_handler) { int old_errno = errno; MONO_SIG_HANDLER_GET_CONTEXT; /* See the comment in mono_runtime_shutdown_stat_profiler (). */ if (mono_native_thread_id_get () == sampling_thread) { mono_atomic_inc_i32 (&profiler_interrupt_signals_received); return; } mono_atomic_inc_i32 (&profiler_signals_received); // Did a non-attached or detaching thread get the signal? if (mono_thread_info_get_small_id () == -1 || !mono_domain_get () || !mono_tls_get_jit_tls ()) { errno = old_errno; return; } // See the comment in sampling_thread_func (). mono_atomic_store_i32 (&mono_thread_info_current ()->profiler_signal_ack, 1); mono_atomic_inc_i32 (&profiler_signals_accepted); int hp_save_index = mono_hazard_pointer_save_for_signal_handler (); mono_thread_info_set_is_async_context (TRUE); MONO_PROFILER_RAISE (sample_hit, (mono_arch_ip_from_context (ctx), ctx)); mono_thread_info_set_is_async_context (FALSE); mono_hazard_pointer_restore_for_signal_handler (hp_save_index); errno = old_errno; mono_chain_signal (MONO_SIG_HANDLER_PARAMS); }
/* WARNING: If we are trying to suspend a target that is on a critical region and running a syscall we risk looping forever if @interrupt_kernel is FALSE. So, be VERY carefull in calling this with @interrupt_kernel == FALSE. Info is not put on a hazard pointer as a suspended thread cannot exit and be freed. This function MUST be matched with mono_thread_info_finish_suspend or mono_thread_info_finish_suspend_and_resume */ MonoThreadInfo* mono_thread_info_safe_suspend_sync (MonoNativeThreadId id, gboolean interrupt_kernel) { MonoThreadInfo *info = NULL; THREADS_SUSPEND_DEBUG ("SUSPENDING tid %p\n", (void*)id); /*FIXME: unify this with self-suspend*/ g_assert (id != mono_native_thread_id_get ()); mono_thread_info_suspend_lock (); mono_threads_begin_global_suspend (); info = suspend_sync_nolock (id, interrupt_kernel); /* XXX this clears HP 1, so we restated it again */ // mono_atomic_store_release (&mono_thread_info_current ()->inside_critical_region, TRUE); mono_threads_end_global_suspend (); mono_thread_info_suspend_unlock (); return info; }
static void add_record (RecordType record_kind, RuntimeLocks kind, gpointer lock) { int i = 0; const int no_frames = 6; gpointer frames[no_frames]; char *msg; if (!trace_file) return; memset (frames, 0, sizeof (gpointer) * no_frames); mono_backtrace (frames, no_frames); for (i = 0; i < no_frames; ++i) frames [i] = (gpointer)((size_t)frames[i] - base_address); /*We only dump 5 frames, which should be more than enough to most analysis.*/ msg = g_strdup_printf ("%x,%d,%d,%p,%p,%p,%p,%p,%p\n", (guint32)mono_native_thread_id_get (), record_kind, kind, lock, frames [1], frames [2], frames [3], frames [4], frames [5]); fwrite (msg, strlen (msg), 1, trace_file); fflush (trace_file); g_free (msg); }
static MonoException* continuation_mark_frame (MonoContinuation *cont) { MonoJitTlsData *jit_tls; MonoLMF *lmf; MonoContext ctx, new_ctx; MonoJitInfo *ji, rji; int endloop = FALSE; if (cont->domain) return mono_get_exception_argument ("cont", "Already marked"); jit_tls = (MonoJitTlsData *)mono_native_tls_get_value (mono_jit_tls_id); lmf = mono_get_lmf(); cont->domain = mono_domain_get (); cont->thread_id = mono_native_thread_id_get (); /* get to the frame that called Mark () */ memset (&rji, 0, sizeof (rji)); memset (&ctx, 0, sizeof (ctx)); do { ji = mono_find_jit_info (cont->domain, jit_tls, &rji, NULL, &ctx, &new_ctx, NULL, &lmf, NULL, NULL); if (!ji || ji == (gpointer)-1) { return mono_get_exception_not_supported ("Invalid stack frame"); } ctx = new_ctx; if (endloop) break; if (!ji->is_trampoline && strcmp (jinfo_get_method (ji)->name, "Mark") == 0) endloop = TRUE; } while (1); cont->top_sp = MONO_CONTEXT_GET_SP (&ctx); /*g_print ("method: %s, sp: %p\n", jinfo_get_method (ji)->name, cont->top_sp);*/ return NULL; }
/* LOCKING: assumes the GC lock is held */ int sgen_stop_world (int generation) { TV_DECLARE (end_handshake); int count, dead; mono_profiler_gc_event (MONO_GC_EVENT_PRE_STOP_WORLD, generation); MONO_GC_WORLD_STOP_BEGIN (); binary_protocol_world_stopping (sgen_timestamp ()); 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 (); if (binary_protocol_is_enabled ()) { long long major_total, major_marked, los_total, los_marked; count_cards (&major_total, &major_marked, &los_total, &los_marked); binary_protocol_world_stopped (sgen_timestamp (), major_total, major_marked, los_total, los_marked); } 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 (); return count; }
/* 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); if (mono_thread_info_unified_management_enabled ()) { sgen_unified_suspend_stop_world (); } else { int count, dead; 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); } 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 (); }