[threading] Introduce the notion of try block to be used by recursive locks.
authorRodrigo Kumpera <kumpera@gmail.com>
Mon, 13 Apr 2015 22:36:46 +0000 (18:36 -0400)
committerRodrigo Kumpera <kumpera@gmail.com>
Mon, 13 Apr 2015 23:05:51 +0000 (19:05 -0400)
This allows a piece of code to handle the cases where it's called in running and blocker context
and must always be in blocking context.

This probably makes code more modular at the expense of an easy to follow and debug execution model.

Since we don't currently annotate all icalls with blocking sections we do it with locks but they can
nest and recurse which requires this support for try block.

mono/utils/mono-threads-coop.c
mono/utils/mono-threads-coop.h
mono/utils/mono-threads-state-machine.c
mono/utils/mono-threads.h

index 29a3527711f5eb12df1d52832db8c89b8d4201f3..f19021b5a564aeeec71f2d61e939a1bb1ed4768e 100644 (file)
@@ -151,6 +151,41 @@ mono_threads_reset_blocking_end (void *cookie)
        mono_threads_prepare_blocking ();
 }
 
+void*
+mono_threads_try_prepare_blocking (void)
+{
+       MonoThreadInfo *info;
+
+       info = mono_thread_info_current_unchecked ();
+       /* If the thread is not attached, it doesn't make sense prepare for suspend. */
+       if (!info || !mono_thread_info_is_live (info) || mono_thread_info_current_state (info) == STATE_BLOCKING) {
+               THREADS_SUSPEND_DEBUG ("PREPARE-TRY-BLOCKING failed %p\n", mono_thread_info_get_tid (info));
+               return NULL;
+       }
+
+retry:
+       /*The JIT might not be able to save*/
+       if (!mono_threads_get_runtime_callbacks ()->thread_state_init_from_sigctx (&info->thread_saved_state [SELF_SUSPEND_STATE_INDEX], NULL)) {
+               THREADS_SUSPEND_DEBUG ("PREPARE-TRY-BLOCKING failed %p to save thread state\n", mono_thread_info_get_tid (info));
+               return NULL;
+       }
+
+       switch (mono_threads_transition_do_blocking (info)) {
+       case DoBlockingContinue:
+               break;
+       case DoBlockingPollAndRetry:
+               mono_threads_state_poll ();
+               goto retry;
+       }
+
+       return info;
+}
+
+void
+mono_threads_finish_try_blocking (void* cookie)
+{
+       mono_threads_finish_blocking (cookie);
+}
 
 void
 mono_threads_core_abort_syscall (MonoThreadInfo *info)
index 6d90c2af1e080758344e03eb640e7a9967fed8c5..8626288f3538cb7a0e5d2bf40287d702395ee90c 100644 (file)
 #define MONO_FINISH_RESET_BLOCKING \
        mono_threads_reset_blocking_end (__reset_cookie);       \
 }
+
+#define MONO_TRY_BLOCKING      \
+{      \
+       void *__try_block_cookie = mono_threads_try_prepare_blocking ();
+
+#define MONO_FINISH_TRY_BLOCKING \
+       mono_threads_finish_try_blocking (__try_block_cookie);  \
+}
+
 /* Internal API */
 
 extern volatile size_t mono_threads_polling_required;
@@ -46,6 +55,9 @@ void mono_threads_finish_blocking (void* cookie);
 void* mono_threads_reset_blocking_start (void);
 void mono_threads_reset_blocking_end (void* cookie);
 
+void* mono_threads_try_prepare_blocking (void);
+void mono_threads_finish_try_blocking (void* cookie);
+
 #else
 
 #define MONO_SUSPEND_CHECK do {        } while (0);
@@ -53,6 +65,8 @@ void mono_threads_reset_blocking_end (void* cookie);
 #define MONO_FINISH_BLOCKING }
 #define MONO_PREPARE_RESET_BLOCKING {
 #define MONO_FINISH_RESET_BLOCKING }
+#define MONO_TRY_BLOCKING {
+#define MONO_FINISH_TRY_BLOCKING }
 
 #endif /* USE_COOP_GC */
 
index c82ad1f9b195aaccd80a66986edda28cc8a580da..51d2e772f59763f46838f523d9416ed4a12047f0 100644 (file)
@@ -685,3 +685,9 @@ mono_thread_info_suspend_count (MonoThreadInfo *info)
 {
        return get_thread_suspend_count (info->thread_state);
 }
+
+int
+mono_thread_info_current_state (MonoThreadInfo *info)
+{
+       return get_thread_state (info->thread_state);
+}
index 17541149d623bc8771d56c67eb893acac7c93c0e..a9a7b914baa82467bcafba122db688970492cb8f 100644 (file)
@@ -621,6 +621,8 @@ void mono_thread_info_wait_for_resume (THREAD_INFO_TYPE *info);
 gboolean mono_thread_info_is_running (THREAD_INFO_TYPE *info);
 gboolean mono_thread_info_is_live (THREAD_INFO_TYPE *info);
 int mono_thread_info_suspend_count (THREAD_INFO_TYPE *info);
+int mono_thread_info_current_state (THREAD_INFO_TYPE *info);
+
 gboolean mono_thread_info_in_critical_location (THREAD_INFO_TYPE *info);
 gboolean mono_thread_info_begin_suspend (THREAD_INFO_TYPE *info, gboolean interrupt_kernel);
 gboolean mono_thread_info_begin_resume (THREAD_INFO_TYPE *info);