Skip to content

Commit

Permalink
Implement MONO_ENTER_NO_SAFEPOINTS/MONO_EXIT_NO_SAFEPOINTS (mono/mono…
Browse files Browse the repository at this point in the history
…#11476)

* [threads] Add a no_safepoints bit to the thread state machine.

Only valid on RUNNING or ASYNC_SUSPEND_REQUESTED.
Currently no transitions set the bit, but the expectation is that it can only
be set/unset by the current thread on itself and only in RUNNING or
ASYNC_SUSPEND_REQUESTED.
Transitions to suspended states or to GC Safe states are forbidden if
wont_safept is set.

The intention is that this is used by a thread to mark a scope where it will
not safepoint (perhaps because it wants to manipulate a raw ptr to a managed
object).

The wont_safept bit only makes sense for cooperative suspension.  For async, we
have the critical regions (which should be much more rarely needed).

* [threads] Add state machine funcs to query/set/uniset wont_safept

* [threads] add MONO_ENTER_NO_SAFEPOINTS/MONO_EXIT_NO_SAFEPOINTS macros

A region between MONO_ENTER_NO_SAFEPOINTS/MONO_EXIT_NO_SAFEPOINTS must not call
any function that could: reach a safepoint (and suspend the current thread),
allocate memory from the managed heap, or transition to GC Safe.  In such a
region it is safe to dereference a pointer to managed memory and use read/write
from it (an alternative to avoid the no safepoints region is to pin the memory
with a global GC handle before manipulating it).  GC Write barriers still need
to be used.

The current design doesn't allow nesting - the underlying thread state
transitions check that the flag isn't already set - keep the regions short and simple.

* [sgen] Don't initiate STW from a thread in a NO_SAFEPOINTS region

In other words, if you were in
MONO_ENTER_NO_SAFEPOINTS/MONO_EXIT_NO_SAFEPOINTS, you shouldn't be calling
anything that would start the GC


Commit migrated from mono/mono@d28db36
  • Loading branch information
lambdageek authored Nov 1, 2018
1 parent 4564b0b commit 2dca8e9
Show file tree
Hide file tree
Showing 5 changed files with 299 additions and 71 deletions.
3 changes: 3 additions & 0 deletions src/mono/mono/metadata/sgen-stw.c
Original file line number Diff line number Diff line change
Expand Up @@ -253,6 +253,9 @@ sgen_unified_suspend_stop_world (void)
{
int sleep_duration = -1;

// we can't lead STW if we promised not to safepoint.
g_assert (!mono_thread_info_will_not_safepoint (mono_thread_info_current ()));

mono_threads_begin_global_suspend ();
THREADS_STW_DEBUG ("[GC-STW-BEGIN][%p] *** BEGIN SUSPEND *** \n", mono_thread_info_get_tid (mono_thread_info_current ()));

Expand Down
18 changes: 18 additions & 0 deletions src/mono/mono/utils/mono-threads-api.h
Original file line number Diff line number Diff line change
Expand Up @@ -140,6 +140,24 @@ For further explanation of what can and can't be done in GC unsafe mode:
mono_threads_exit_gc_safe_region_unbalanced_internal (__gc_safe_unbalanced_cookie, &__gc_safe_unbalanced_dummy); \
} while (0)

void
mono_threads_enter_no_safepoints_region (const char *func);

void
mono_threads_exit_no_safepoints_region (const char *func);

#define MONO_ENTER_NO_SAFEPOINTS \
do { \
do { \
if (mono_threads_are_safepoints_enabled ()) \
mono_threads_enter_no_safepoints_region (__func__); \
} while (0)

#define MONO_EXIT_NO_SAFEPOINTS \
if (mono_threads_are_safepoints_enabled ()) \
mono_threads_exit_no_safepoints_region (__func__); \
} while (0)

MONO_END_DECLS

#endif /* __MONO_LOGGER_H__ */
17 changes: 17 additions & 0 deletions src/mono/mono/utils/mono-threads-coop.c
Original file line number Diff line number Diff line change
Expand Up @@ -129,6 +129,9 @@ mono_threads_state_poll_with_info (MonoThreadInfo *info)

THREADS_SUSPEND_DEBUG ("FINISH SELF SUSPEND OF %p\n", mono_thread_info_get_tid (info));

/* Fast fail if no_safepoints is set */
g_assert (!(info->thread_state & THREAD_SUSPEND_NO_SAFEPOINTS_MASK));

/* Fast check for pending suspend requests */
if (!(info->thread_state & STATE_ASYNC_SUSPEND_REQUESTED))
return;
Expand Down Expand Up @@ -704,3 +707,17 @@ mono_threads_coop_end_global_suspend (void)
if (mono_threads_are_safepoints_enabled ())
mono_polling_required = 0;
}

void
mono_threads_enter_no_safepoints_region (const char *func)
{
MONO_REQ_GC_UNSAFE_MODE;
mono_threads_transition_begin_no_safepoints (mono_thread_info_current (), func);
}

void
mono_threads_exit_no_safepoints_region (const char *func)
{
MONO_REQ_GC_UNSAFE_MODE;
mono_threads_transition_end_no_safepoints (mono_thread_info_current (), func);
}
Loading

0 comments on commit 2dca8e9

Please sign in to comment.