Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/mono/mono.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRodrigo Kumpera <kumpera@gmail.com>2015-10-12 16:25:01 +0300
committerRodrigo Kumpera <kumpera@gmail.com>2015-10-12 16:25:01 +0300
commit030f9dd26d8a308bfde0a59b43357b707992ef6c (patch)
treece6fdc46dc934f8cfc9bcc63200922701318e995
parent35e42072a80a26341cd111344d022636d1cf051a (diff)
parent66b81e51548b464e8741412e03f503bf77f2930d (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.c7
-rw-r--r--eglib/src/glib.h1
-rw-r--r--mono/metadata/sgen-mono.c9
-rw-r--r--mono/utils/mono-stack-unwinding.h2
-rw-r--r--mono/utils/mono-threads-api.h8
-rw-r--r--mono/utils/mono-threads-coop.c72
-rw-r--r--mono/utils/mono-threads-coop.h29
-rw-r--r--mono/utils/mono-threads.c5
-rw-r--r--mono/utils/mono-threads.h4
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.