diff options
author | Rodrigo Kumpera <kumpera@gmail.com> | 2015-10-12 16:25:01 +0300 |
---|---|---|
committer | Rodrigo Kumpera <kumpera@gmail.com> | 2015-10-12 16:25:01 +0300 |
commit | 030f9dd26d8a308bfde0a59b43357b707992ef6c (patch) | |
tree | ce6fdc46dc934f8cfc9bcc63200922701318e995 | |
parent | 35e42072a80a26341cd111344d022636d1cf051a (diff) | |
parent | 66b81e51548b464e8741412e03f503bf77f2930d (diff) |
Merge pull request #2101 from tritao/stack-coop-gc
Reworked coop GC stack handling in platforms with restricted access to register contexts.
-rw-r--r-- | eglib/src/gbytearray.c | 7 | ||||
-rw-r--r-- | eglib/src/glib.h | 1 | ||||
-rw-r--r-- | mono/metadata/sgen-mono.c | 9 | ||||
-rw-r--r-- | mono/utils/mono-stack-unwinding.h | 2 | ||||
-rw-r--r-- | mono/utils/mono-threads-api.h | 8 | ||||
-rw-r--r-- | mono/utils/mono-threads-coop.c | 72 | ||||
-rw-r--r-- | mono/utils/mono-threads-coop.h | 29 | ||||
-rw-r--r-- | mono/utils/mono-threads.c | 5 | ||||
-rw-r--r-- | mono/utils/mono-threads.h | 4 |
9 files changed, 106 insertions, 31 deletions
diff --git a/eglib/src/gbytearray.c b/eglib/src/gbytearray.c index 8702a4957a8..f8231b4834f 100644 --- a/eglib/src/gbytearray.c +++ b/eglib/src/gbytearray.c @@ -49,3 +49,10 @@ g_byte_array_append (GByteArray *array, { return (GByteArray *)g_array_append_vals ((GArray *)array, data, len); } + +void +g_byte_array_set_size (GByteArray *array, gint length) +{ + g_array_set_size ((GArray *)array, length); +} + diff --git a/eglib/src/glib.h b/eglib/src/glib.h index 4b2c6d659d4..f5473bd2a5c 100644 --- a/eglib/src/glib.h +++ b/eglib/src/glib.h @@ -486,6 +486,7 @@ struct _GByteArray { GByteArray *g_byte_array_new (void); GByteArray* g_byte_array_append (GByteArray *array, const guint8 *data, guint len); guint8* g_byte_array_free (GByteArray *array, gboolean free_segment); +void g_byte_array_set_size (GByteArray *array, gint length); /* * Array diff --git a/mono/metadata/sgen-mono.c b/mono/metadata/sgen-mono.c index bb06f7eec02..11ab789d422 100644 --- a/mono/metadata/sgen-mono.c +++ b/mono/metadata/sgen-mono.c @@ -2376,6 +2376,15 @@ sgen_client_scan_thread_data (void *start_nursery, void *end_nursery, gboolean p sgen_conservatively_pin_objects_from ((void**)&info->client_info.regs, (void**)&info->client_info.regs + ARCH_NUM_REGS, start_nursery, end_nursery, PIN_TYPE_STACK); #endif + { + // This is used on Coop GC for platforms where we cannot get the data for individual registers. + // We force a spill of all registers into the stack and pass a chunk of data into sgen. + MonoThreadUnwindState *state = mono_thread_info_get_suspend_state (info); + if (state && state->gc_stackdata) { + sgen_conservatively_pin_objects_from (state->gc_stackdata, (void**)((char*)state->gc_stackdata + state->gc_stackdata_size), + start_nursery, end_nursery, PIN_TYPE_STACK); + } + } } } END_FOREACH_THREAD } diff --git a/mono/utils/mono-stack-unwinding.h b/mono/utils/mono-stack-unwinding.h index cfeb19d31b9..35f7bd01411 100644 --- a/mono/utils/mono-stack-unwinding.h +++ b/mono/utils/mono-stack-unwinding.h @@ -94,6 +94,8 @@ typedef struct { MonoContext ctx; gpointer unwind_data [3]; /*right now: domain, lmf and jit_tls*/ gboolean valid; + void *gc_stackdata; + int gc_stackdata_size; } MonoThreadUnwindState; diff --git a/mono/utils/mono-threads-api.h b/mono/utils/mono-threads-api.h index f94fd66e35b..47e3454c3d9 100644 --- a/mono/utils/mono-threads-api.h +++ b/mono/utils/mono-threads-api.h @@ -20,8 +20,8 @@ This API is experimental. It will eventually be required to properly use the res */ /* Don't use those directly, use the MONO_(BEGIN|END)_EFRAME */ -MONO_API void* mono_threads_enter_gc_unsafe_region (void); -MONO_API void mono_threads_exit_gc_unsafe_region (void *region_cookie); +MONO_API void* mono_threads_enter_gc_unsafe_region (void* stackdata); +MONO_API void mono_threads_exit_gc_unsafe_region (void *region_cookie, void* stackdata); /* Use those macros to limit regions of code that interact with managed memory or use the embedding API. @@ -31,8 +31,8 @@ For further explanation of what can and can't be done in GC unsafe mode: http://www.mono-project.com/docs/advanced/runtime/docs/coop-suspend/#gc-unsafe-mode */ -#define MONO_BEGIN_EFRAME { void *__region_cookie = mono_threads_enter_gc_unsafe_region (); -#define MONO_END_EFRAME mono_threads_exit_gc_unsafe_region (__region_cookie); } +#define MONO_BEGIN_EFRAME { void *__dummy; void *__region_cookie = mono_threads_enter_gc_unsafe_region (__dummy); +#define MONO_END_EFRAME mono_threads_exit_gc_unsafe_region (__region_cookie, __dummy); } MONO_END_DECLS diff --git a/mono/utils/mono-threads-coop.c b/mono/utils/mono-threads-coop.c index c1a8cad7473..e7e6db381d8 100644 --- a/mono/utils/mono-threads-coop.c +++ b/mono/utils/mono-threads-coop.c @@ -14,6 +14,7 @@ #define _DARWIN_C_SOURCE #endif +#include <mono/metadata/mempool.h> #include <mono/utils/mono-compiler.h> #include <mono/utils/mono-semaphore.h> #include <mono/utils/mono-threads.h> @@ -29,6 +30,13 @@ #include <mono/utils/mach-support.h> #endif +#ifdef _MSC_VER +// TODO: Find MSVC replacement for __builtin_unwind_init +#define SAVE_REGS_ON_STACK g_assert_not_reached (); +#else +#define SAVE_REGS_ON_STACK __builtin_unwind_init (); +#endif + #ifdef USE_COOP_BACKEND volatile size_t mono_polling_required; @@ -67,8 +75,36 @@ mono_threads_state_poll (void) } } +static void * +return_stack_ptr () +{ + int i; + return &i; +} + +static void +copy_stack_data (MonoThreadInfo *info, void* stackdata_begin) +{ + MonoThreadUnwindState *state; + int stackdata_size; + void* stackdata_end = return_stack_ptr (); + + SAVE_REGS_ON_STACK; + + state = &info->thread_saved_state [SELF_SUSPEND_STATE_INDEX]; + + stackdata_size = (char*)stackdata_begin - (char*)stackdata_end; + g_assert (stackdata_size > 0); + + g_byte_array_set_size (info->stackdata, stackdata_size); + state->gc_stackdata = info->stackdata->data; + memcpy (state->gc_stackdata, stackdata_end, stackdata_size); + + state->gc_stackdata_size = stackdata_size; +} + void* -mono_threads_prepare_blocking (void) +mono_threads_prepare_blocking (void* stackdata) { MonoThreadInfo *info; ++coop_do_blocking_count; @@ -80,6 +116,8 @@ mono_threads_prepare_blocking (void) return NULL; } + copy_stack_data (info, stackdata); + retry: ++coop_save_count; mono_threads_get_runtime_callbacks ()->thread_state_init (&info->thread_saved_state [SELF_SUSPEND_STATE_INDEX]); @@ -96,7 +134,7 @@ retry: } void -mono_threads_finish_blocking (void *cookie) +mono_threads_finish_blocking (void *cookie, void* stackdata) { static gboolean warned_about_bad_transition; MonoThreadInfo *info = cookie; @@ -128,7 +166,7 @@ mono_threads_finish_blocking (void *cookie) void* -mono_threads_reset_blocking_start (void) +mono_threads_reset_blocking_start (void* stackdata) { MonoThreadInfo *info = mono_thread_info_current_unchecked (); ++coop_reset_blocking_count; @@ -137,6 +175,8 @@ mono_threads_reset_blocking_start (void) if (!info || !mono_thread_info_is_live (info)) return NULL; + copy_stack_data (info, stackdata); + switch (mono_threads_transition_abort_blocking (info)) { case AbortBlockingIgnore: info->thread_saved_state [SELF_SUSPEND_STATE_INDEX].valid = FALSE; @@ -156,7 +196,7 @@ mono_threads_reset_blocking_start (void) } void -mono_threads_reset_blocking_end (void *cookie) +mono_threads_reset_blocking_end (void *cookie, void* stackdata) { MonoThreadInfo *info = cookie; @@ -164,11 +204,11 @@ mono_threads_reset_blocking_end (void *cookie) return; g_assert (info == mono_thread_info_current_unchecked ()); - mono_threads_prepare_blocking (); + mono_threads_prepare_blocking (stackdata); } void* -mono_threads_try_prepare_blocking (void) +mono_threads_try_prepare_blocking (void* stackdata) { MonoThreadInfo *info; ++coop_try_blocking_count; @@ -180,6 +220,8 @@ mono_threads_try_prepare_blocking (void) return NULL; } + copy_stack_data (info, stackdata); + retry: ++coop_save_count; mono_threads_get_runtime_callbacks ()->thread_state_init (&info->thread_saved_state [SELF_SUSPEND_STATE_INDEX]); @@ -196,9 +238,9 @@ retry: } void -mono_threads_finish_try_blocking (void* cookie) +mono_threads_finish_try_blocking (void* cookie, void* stackdata) { - mono_threads_finish_blocking (cookie); + mono_threads_finish_blocking (cookie, stackdata); } gboolean @@ -210,7 +252,7 @@ mono_threads_core_begin_async_resume (MonoThreadInfo *info) gboolean mono_threads_core_begin_async_suspend (MonoThreadInfo *info, gboolean interrupt_kernel) -{ +{ mono_threads_add_to_pending_operation_set (info); /* There's nothing else to do after we async request the thread to suspend */ return TRUE; @@ -271,27 +313,27 @@ mono_threads_core_end_global_suspend (void) } void* -mono_threads_enter_gc_unsafe_region (void) +mono_threads_enter_gc_unsafe_region (void* stackdata) { - return mono_threads_reset_blocking_start (); + return mono_threads_reset_blocking_start (stackdata); } void -mono_threads_exit_gc_unsafe_region (void *regions_cookie) +mono_threads_exit_gc_unsafe_region (void *regions_cookie, void* stackdata) { - mono_threads_reset_blocking_end (regions_cookie); + mono_threads_reset_blocking_end (regions_cookie, stackdata); } #else void* -mono_threads_enter_gc_unsafe_region (void) +mono_threads_enter_gc_unsafe_region (void* stackdata) { return NULL; } void -mono_threads_exit_gc_unsafe_region (void *regions_cookie) +mono_threads_exit_gc_unsafe_region (void *regions_cookie, void* stackdata) { } diff --git a/mono/utils/mono-threads-coop.h b/mono/utils/mono-threads-coop.h index 88ae40aee87..d103f42a5bd 100644 --- a/mono/utils/mono-threads-coop.h +++ b/mono/utils/mono-threads-coop.h @@ -22,39 +22,44 @@ #define MONO_PREPARE_BLOCKING \ { \ - void *__blocking_cookie = mono_threads_prepare_blocking (); + void *__dummy; \ + void *__blocking_cookie = mono_threads_prepare_blocking (&__dummy); #define MONO_FINISH_BLOCKING \ - mono_threads_finish_blocking (__blocking_cookie); \ + mono_threads_finish_blocking (__blocking_cookie, &__dummy); \ } #define MONO_PREPARE_RESET_BLOCKING \ { \ - void *__reset_cookie = mono_threads_reset_blocking_start (); + void *__dummy; \ + void *__reset_cookie = mono_threads_reset_blocking_start (&__dummy); #define MONO_FINISH_RESET_BLOCKING \ - mono_threads_reset_blocking_end (__reset_cookie); \ + mono_threads_reset_blocking_end (__reset_cookie, &__dummy); \ } #define MONO_TRY_BLOCKING \ { \ - void *__try_block_cookie = mono_threads_try_prepare_blocking (); + void *__dummy; \ + void *__try_block_cookie = mono_threads_try_prepare_blocking (&__dummy); #define MONO_FINISH_TRY_BLOCKING \ - mono_threads_finish_try_blocking (__try_block_cookie); \ + mono_threads_finish_try_blocking (__try_block_cookie, &__dummy); \ } /* Internal API */ void mono_threads_state_poll (void); -void* mono_threads_prepare_blocking (void); -void mono_threads_finish_blocking (void* cookie); +void mono_threads_state_poll_stack_data (void* stackdata); -void* mono_threads_reset_blocking_start (void); -void mono_threads_reset_blocking_end (void* cookie); +void* mono_threads_prepare_blocking (void* stackdata); +void mono_threads_finish_blocking (void* cookie, void* stackdata); -void* mono_threads_try_prepare_blocking (void); -void mono_threads_finish_try_blocking (void* cookie); +void* mono_threads_reset_blocking_start (void* stackdata); +void mono_threads_reset_blocking_end (void* cookie, void* stackdata); + +void* mono_threads_try_prepare_blocking (void* stackdata); +void mono_threads_finish_try_blocking (void* cookie, void* stackdata); /* JIT specific interface */ extern volatile size_t mono_polling_required; diff --git a/mono/utils/mono-threads.c b/mono/utils/mono-threads.c index b1d5da9b917..b9526aa5fba 100644 --- a/mono/utils/mono-threads.c +++ b/mono/utils/mono-threads.c @@ -15,6 +15,7 @@ #define _DARWIN_C_SOURCE #endif +#include <mono/metadata/mempool.h> #include <mono/utils/mono-compiler.h> #include <mono/utils/mono-semaphore.h> #include <mono/utils/mono-threads.h> @@ -326,6 +327,8 @@ register_thread (MonoThreadInfo *info, gpointer baseptr) info->stack_start_limit = staddr; info->stack_end = staddr + stsize; + info->stackdata = g_byte_array_new (); + mono_threads_platform_register (info); /* @@ -387,6 +390,8 @@ unregister_thread (void *arg) mono_thread_info_suspend_unlock (); + g_byte_array_free (info->stackdata, /*free_segment=*/TRUE); + /*now it's safe to free the thread info.*/ mono_thread_hazardous_free_or_queue (info, free_thread_info, TRUE, FALSE); mono_thread_small_id_free (small_id); diff --git a/mono/utils/mono-threads.h b/mono/utils/mono-threads.h index d153ca83c4e..e0b979c0952 100644 --- a/mono/utils/mono-threads.h +++ b/mono/utils/mono-threads.h @@ -10,6 +10,7 @@ #ifndef __MONO_THREADS_H__ #define __MONO_THREADS_H__ +#include <mono/metadata/mempool.h> #include <mono/utils/mono-semaphore.h> #include <mono/utils/mono-stack-unwinding.h> #include <mono/utils/mono-linked-list-set.h> @@ -224,6 +225,9 @@ typedef struct { int signal; #endif + /* This memory pool is used by coop GC to save stack data roots between GC unsafe regions */ + GByteArray *stackdata; + /*In theory, only the posix backend needs this, but having it on mach/win32 simplifies things a lot.*/ MonoThreadUnwindState thread_saved_state [2]; //0 is self suspend, 1 is async suspend. |