X-Git-Url: http://wien.tomnetworks.com/gitweb/?a=blobdiff_plain;f=mono%2Fmetadata%2Fmonitor.c;h=9933f1dd48730ba5f4d5ae377a67752543063a85;hb=157cb97206f627685c15410953d2767146f6e426;hp=78aa3961027ff5684b3666231e6d94ba3d417a0a;hpb=168d07f15c2713e05d27d7bf1987e09d1db1cfed;p=mono.git diff --git a/mono/metadata/monitor.c b/mono/metadata/monitor.c index 78aa3961027..9933f1dd487 100644 --- a/mono/metadata/monitor.c +++ b/mono/metadata/monitor.c @@ -4,7 +4,8 @@ * Author: * Dick Porter (dick@ximian.com) * - * (C) 2003 Ximian, Inc. + * Copyright 2003 Ximian, Inc (http://www.ximian.com) + * Copyright 2004-2009 Novell, Inc (http://www.novell.com) */ #include @@ -23,7 +24,9 @@ #include #include #include +#include #include +#include /* * Pull the list of opcodes @@ -102,7 +105,7 @@ static int array_size = 16; static __thread gsize tls_pthread_self MONO_TLS_FAST; #endif -#ifndef PLATFORM_WIN32 +#ifndef HOST_WIN32 #ifdef HAVE_KW_THREAD #define GetCurrentThreadId() tls_pthread_self #else @@ -123,7 +126,30 @@ mono_monitor_init (void) void mono_monitor_cleanup (void) { + MonoThreadsSync *mon; + /* MonitorArray *marray, *next = NULL; */ + /*DeleteCriticalSection (&monitor_mutex);*/ + + /* The monitors on the freelist don't have weak links - mark them */ + for (mon = monitor_freelist; mon; mon = mon->data) + mon->wait_list = (gpointer)-1; + + /* FIXME: This still crashes with sgen (async_read.exe) */ + /* + for (marray = monitor_allocated; marray; marray = next) { + int i; + + for (i = 0; i < marray->num_monitors; ++i) { + mon = &marray->monitors [i]; + if (mon->wait_list != (gpointer)-1) + mono_gc_weak_link_remove (&mon->data); + } + + next = marray->next; + g_free (marray); + } + */ } /* @@ -134,7 +160,7 @@ mono_monitor_cleanup (void) void mono_monitor_init_tls (void) { -#if !defined(PLATFORM_WIN32) && defined(HAVE_KW_THREAD) +#if !defined(HOST_WIN32) && defined(HAVE_KW_THREAD) tls_pthread_self = pthread_self (); #endif } @@ -200,7 +226,7 @@ mono_locks_dump (gboolean include_untaken) static void mon_finalize (MonoThreadsSync *mon) { - LOCK_DEBUG (g_message (G_GNUC_PRETTY_FUNCTION ": Finalizing sync %p", mon)); + LOCK_DEBUG (g_message ("%s: Finalizing sync %p", __func__, mon)); if (mon->entry_sem != NULL) { CloseHandle (mon->entry_sem); @@ -217,7 +243,9 @@ mon_finalize (MonoThreadsSync *mon) mon->data = monitor_freelist; monitor_freelist = mon; +#ifndef DISABLE_PERFCOUNTERS mono_perfcounters->gc_sync_blocks--; +#endif } /* LOCKING: this is called with monitor_mutex held */ @@ -235,6 +263,15 @@ mon_new (gsize id) for (i = 0; i < marray->num_monitors; ++i) { if (marray->monitors [i].data == NULL) { new = &marray->monitors [i]; + if (new->wait_list) { + /* Orphaned events left by aborted threads */ + while (new->wait_list) { + LOCK_DEBUG (g_message (G_GNUC_PRETTY_FUNCTION ": (%d): Closing orphaned event %d", GetCurrentThreadId (), new->wait_list->data)); + CloseHandle (new->wait_list->data); + new->wait_list = g_slist_remove (new->wait_list, new->wait_list->data); + } + } + mono_gc_weak_link_remove (&new->data, FALSE); new->data = monitor_freelist; monitor_freelist = new; } @@ -246,7 +283,7 @@ mon_new (gsize id) /* need to allocate a new array of monitors */ if (!monitor_freelist) { MonitorArray *last; - LOCK_DEBUG (g_message (G_GNUC_PRETTY_FUNCTION ": allocating more monitors: %d", array_size)); + LOCK_DEBUG (g_message ("%s: allocating more monitors: %d", __func__, array_size)); marray = g_malloc0 (sizeof (MonoArray) + array_size * sizeof (MonoThreadsSync)); marray->num_monitors = array_size; array_size *= 2; @@ -275,8 +312,11 @@ mon_new (gsize id) new->owner = id; new->nest = 1; + new->data = NULL; +#ifndef DISABLE_PERFCOUNTERS mono_perfcounters->gc_sync_blocks++; +#endif return new; } @@ -382,10 +422,9 @@ mono_monitor_try_enter_internal (MonoObject *obj, guint32 ms, gboolean allow_int guint32 then = 0, now, delta; guint32 waitms; guint32 ret; - MonoThread *thread; + MonoInternalThread *thread; - LOCK_DEBUG (g_message(G_GNUC_PRETTY_FUNCTION - ": (%d) Trying to lock object %p (%d ms)", id, obj, ms)); + LOCK_DEBUG (g_message("%s: (%d) Trying to lock object %p (%d ms)", __func__, id, obj, ms)); if (G_UNLIKELY (!obj)) { mono_raise_exception (mono_get_exception_argument_null ("obj")); @@ -400,7 +439,7 @@ retry: mono_monitor_allocator_lock (); mon = mon_new (id); if (InterlockedCompareExchangePointer ((gpointer*)&obj->synchronisation, mon, NULL) == NULL) { - mono_gc_weak_link_add (&mon->data, obj); + mono_gc_weak_link_add (&mon->data, obj, FALSE); mono_monitor_allocator_unlock (); /* Successfully locked */ return 1; @@ -415,7 +454,7 @@ retry: lw.sync = mon; lw.lock_word |= LOCK_WORD_FAT_HASH; if (InterlockedCompareExchangePointer ((gpointer*)&obj->synchronisation, lw.sync, oldlw) == oldlw) { - mono_gc_weak_link_add (&mon->data, obj); + mono_gc_weak_link_add (&mon->data, obj, FALSE); mono_monitor_allocator_unlock (); /* Successfully locked */ return 1; @@ -454,7 +493,7 @@ retry: lw.sync = mon; lw.lock_word |= LOCK_WORD_FAT_HASH; if (InterlockedCompareExchangePointer ((gpointer*)&obj->synchronisation, lw.sync, oldlw) == oldlw) { - mono_gc_weak_link_add (&mon->data, obj); + mono_gc_weak_link_add (&mon->data, obj, TRUE); mono_monitor_allocator_unlock (); /* Successfully locked */ return 1; @@ -503,17 +542,50 @@ retry: } /* The object must be locked by someone else... */ +#ifndef DISABLE_PERFCOUNTERS mono_perfcounters->thread_contentions++; +#endif /* If ms is 0 we don't block, but just fail straight away */ if (ms == 0) { - LOCK_DEBUG (g_message (G_GNUC_PRETTY_FUNCTION ": (%d) timed out, returning FALSE", id)); + LOCK_DEBUG (g_message ("%s: (%d) timed out, returning FALSE", __func__, id)); return 0; } - /* The slow path begins here. We need to make sure theres a - * semaphore handle (creating it if necessary), and block on - * it + mono_profiler_monitor_event (obj, MONO_PROFILER_MONITOR_CONTENTION); + + /* The slow path begins here. */ +retry_contended: + /* a small amount of duplicated code, but it allows us to insert the profiler + * callbacks without impacting the fast path: from here on we don't need to go back to the + * retry label, but to retry_contended. At this point mon is already installed in the object + * header. + */ + /* This case differs from Dice's case 3 because we don't + * deflate locks or cache unused lock records + */ + if (G_LIKELY (mon->owner == 0)) { + /* Try to install our ID in the owner field, nest + * should have been left at 1 by the previous unlock + * operation + */ + if (G_LIKELY (InterlockedCompareExchangePointer ((gpointer *)&mon->owner, (gpointer)id, 0) == 0)) { + /* Success */ + g_assert (mon->nest == 1); + mono_profiler_monitor_event (obj, MONO_PROFILER_MONITOR_DONE); + return 1; + } + } + + /* If the object is currently locked by this thread... */ + if (mon->owner == id) { + mon->nest++; + mono_profiler_monitor_event (obj, MONO_PROFILER_MONITOR_DONE); + return 1; + } + + /* We need to make sure there's a semaphore handle (creating it if + * necessary), and block on it */ if (mon->entry_sem == NULL) { /* Create the semaphore */ @@ -548,9 +620,11 @@ retry: InterlockedIncrement (&mon->entry_count); +#ifndef DISABLE_PERFCOUNTERS mono_perfcounters->thread_queue_len++; mono_perfcounters->thread_queue_max++; - thread = mono_thread_current (); +#endif + thread = mono_thread_internal_current (); mono_thread_set_state (thread, ThreadState_WaitSleepJoin); @@ -563,20 +637,21 @@ retry: mono_thread_clr_state (thread, ThreadState_WaitSleepJoin); InterlockedDecrement (&mon->entry_count); +#ifndef DISABLE_PERFCOUNTERS mono_perfcounters->thread_queue_len--; +#endif if (ms != INFINITE) { now = mono_msec_ticks (); if (now < then) { /* The counter must have wrapped around */ - LOCK_DEBUG (g_message (G_GNUC_PRETTY_FUNCTION - ": wrapped around! now=0x%x then=0x%x", now, then)); + LOCK_DEBUG (g_message ("%s: wrapped around! now=0x%x then=0x%x", __func__, now, then)); now += (0xffffffff - then); then = 0; - LOCK_DEBUG (g_message (G_GNUC_PRETTY_FUNCTION ": wrap rejig: now=0x%x then=0x%x delta=0x%x", now, then, now-then)); + LOCK_DEBUG (g_message ("%s: wrap rejig: now=0x%x then=0x%x delta=0x%x", __func__, now, then, now-then)); } delta = now - then; @@ -588,29 +663,32 @@ retry: if ((ret == WAIT_TIMEOUT || (ret == WAIT_IO_COMPLETION && !allow_interruption)) && ms > 0) { /* More time left */ - goto retry; + goto retry_contended; } } else { if (ret == WAIT_TIMEOUT || (ret == WAIT_IO_COMPLETION && !allow_interruption)) { - if (ret == WAIT_IO_COMPLETION && mono_thread_test_state (mono_thread_current (), ThreadState_StopRequested)) { + if (ret == WAIT_IO_COMPLETION && (mono_thread_test_state (mono_thread_internal_current (), (ThreadState_StopRequested|ThreadState_SuspendRequested)))) { /* - * We have to obey a stop request even if allow_interruption is - * FALSE to avoid hangs at shutdown. + * We have to obey a stop/suspend request even if + * allow_interruption is FALSE to avoid hangs at shutdown. */ + mono_profiler_monitor_event (obj, MONO_PROFILER_MONITOR_FAIL); return -1; } /* Infinite wait, so just try again */ - goto retry; + goto retry_contended; } } if (ret == WAIT_OBJECT_0) { /* retry from the top */ - goto retry; + goto retry_contended; } - + /* We must have timed out */ - LOCK_DEBUG (g_message (G_GNUC_PRETTY_FUNCTION ": (%d) timed out waiting, returning FALSE", id)); + LOCK_DEBUG (g_message ("%s: (%d) timed out waiting, returning FALSE", __func__, id)); + + mono_profiler_monitor_event (obj, MONO_PROFILER_MONITOR_FAIL); if (ret == WAIT_IO_COMPLETION) return -1; @@ -636,7 +714,7 @@ mono_monitor_exit (MonoObject *obj) MonoThreadsSync *mon; guint32 nest; - LOCK_DEBUG (g_message (G_GNUC_PRETTY_FUNCTION ": (%d) Unlocking %p", GetCurrentThreadId (), obj)); + LOCK_DEBUG (g_message ("%s: (%d) Unlocking %p", __func__, GetCurrentThreadId (), obj)); if (G_UNLIKELY (!obj)) { mono_raise_exception (mono_get_exception_argument_null ("obj")); @@ -665,8 +743,7 @@ mono_monitor_exit (MonoObject *obj) nest = mon->nest - 1; if (nest == 0) { - LOCK_DEBUG (g_message (G_GNUC_PRETTY_FUNCTION - ": (%d) Object %p is now unlocked", GetCurrentThreadId (), obj)); + LOCK_DEBUG (g_message ("%s: (%d) Object %p is now unlocked", __func__, GetCurrentThreadId (), obj)); /* object is now unlocked, leave nest==1 so we don't * need to set it when the lock is reacquired @@ -684,15 +761,35 @@ mono_monitor_exit (MonoObject *obj) ReleaseSemaphore (mon->entry_sem, 1, NULL); } } else { - LOCK_DEBUG (g_message (G_GNUC_PRETTY_FUNCTION - ": (%d) Object %p is now locked %d times", GetCurrentThreadId (), obj, nest)); + LOCK_DEBUG (g_message ("%s: (%d) Object %p is now locked %d times", __func__, GetCurrentThreadId (), obj, nest)); mon->nest = nest; } } +void** +mono_monitor_get_object_monitor_weak_link (MonoObject *object) +{ + LockWord lw; + MonoThreadsSync *sync = NULL; + + lw.sync = object->synchronisation; + if (lw.lock_word & LOCK_WORD_FAT_HASH) { + lw.lock_word &= ~LOCK_WORD_BITS_MASK; + sync = lw.sync; + } else if (!(lw.lock_word & LOCK_WORD_THIN_HASH)) { + sync = lw.sync; + } + + if (sync && sync->data) + return &sync->data; + return NULL; +} + +#ifndef DISABLE_JIT + static void -emit_obj_syncp_check (MonoMethodBuilder *mb, int syncp_loc, int *obj_null_branch, int *syncp_true_false_branch, - gboolean branch_on_true) +emit_obj_syncp_check (MonoMethodBuilder *mb, int syncp_loc, int *obj_null_branch, int *true_locktaken_branch, int *syncp_true_false_branch, + int *thin_hash_branch, gboolean branch_on_true) { /* ldarg 0 obj @@ -702,6 +799,17 @@ emit_obj_syncp_check (MonoMethodBuilder *mb, int syncp_loc, int *obj_null_branch mono_mb_emit_byte (mb, CEE_LDARG_0); *obj_null_branch = mono_mb_emit_short_branch (mb, CEE_BRFALSE_S); + /* + ldarg.1 + ldind.i1 + brtrue.s true_locktaken + */ + if (true_locktaken_branch) { + mono_mb_emit_byte (mb, CEE_LDARG_1); + mono_mb_emit_byte (mb, CEE_LDIND_I1); + *true_locktaken_branch = mono_mb_emit_short_branch (mb, CEE_BRTRUE_S); + } + /* ldarg 0 obj conv.i objp @@ -719,31 +827,82 @@ emit_obj_syncp_check (MonoMethodBuilder *mb, int syncp_loc, int *obj_null_branch mono_mb_emit_byte (mb, CEE_ADD); mono_mb_emit_byte (mb, CEE_LDIND_I); mono_mb_emit_stloc (mb, syncp_loc); + + + if (mono_gc_is_moving ()) { + /*check for a thin hash*/ + mono_mb_emit_ldloc (mb, syncp_loc); + mono_mb_emit_icon (mb, 0x01); + mono_mb_emit_byte (mb, CEE_CONV_I); + mono_mb_emit_byte (mb, CEE_AND); + *thin_hash_branch = mono_mb_emit_short_branch (mb, CEE_BRTRUE_S); + + /*clear gc bits*/ + mono_mb_emit_ldloc (mb, syncp_loc); + mono_mb_emit_icon (mb, ~0x3); + mono_mb_emit_byte (mb, CEE_CONV_I); + mono_mb_emit_byte (mb, CEE_AND); + mono_mb_emit_stloc (mb, syncp_loc); + } else { + *thin_hash_branch = 0; + } + mono_mb_emit_ldloc (mb, syncp_loc); *syncp_true_false_branch = mono_mb_emit_short_branch (mb, branch_on_true ? CEE_BRTRUE_S : CEE_BRFALSE_S); } +#endif + +static MonoMethod* monitor_il_fastpaths[3]; + +gboolean +mono_monitor_is_il_fastpath_wrapper (MonoMethod *method) +{ + int i; + for (i = 0; i < 3; ++i) { + if (monitor_il_fastpaths [i] == method) + return TRUE; + } + return FALSE; +} + +enum { + FASTPATH_ENTER, + FASTPATH_ENTERV4, + FASTPATH_EXIT +}; + + +static MonoMethod* +register_fastpath (MonoMethod *method, int idx) +{ + mono_memory_barrier (); + monitor_il_fastpaths [idx] = method; + return method; +} + static MonoMethod* mono_monitor_get_fast_enter_method (MonoMethod *monitor_enter_method) { - static MonoMethod *fast_monitor_enter; - static MonoMethod *compare_exchange_method; - MonoMethodBuilder *mb; - int obj_null_branch, syncp_null_branch, has_owner_branch, other_owner_branch, tid_branch; + MonoMethod *res; + static MonoMethod *compare_exchange_method; + int obj_null_branch, true_locktaken_branch = 0, syncp_null_branch, has_owner_branch, other_owner_branch, tid_branch, thin_hash_branch; int tid_loc, syncp_loc, owner_loc; int thread_tls_offset; + gboolean is_v4 = mono_method_signature (monitor_enter_method)->param_count == 2; + int fast_path_idx = is_v4 ? FASTPATH_ENTERV4 : FASTPATH_ENTER; + WrapperInfo *info; -#ifdef HAVE_MOVING_COLLECTOR - return NULL; -#endif + /* The !is_v4 version is not used/tested */ + g_assert (is_v4); thread_tls_offset = mono_thread_get_tls_offset (); if (thread_tls_offset == -1) return NULL; - if (fast_monitor_enter) - return fast_monitor_enter; + if (monitor_il_fastpaths [fast_path_idx]) + return monitor_il_fastpaths [fast_path_idx]; if (!compare_exchange_method) { MonoMethodDesc *desc; @@ -758,17 +917,18 @@ mono_monitor_get_fast_enter_method (MonoMethod *monitor_enter_method) return NULL; } - mb = mono_mb_new (mono_defaults.monitor_class, "FastMonitorEnter", MONO_WRAPPER_UNKNOWN); + mb = mono_mb_new (mono_defaults.monitor_class, is_v4 ? "FastMonitorEnterV4" : "FastMonitorEnter", MONO_WRAPPER_UNKNOWN); mb->method->slot = -1; mb->method->flags = METHOD_ATTRIBUTE_PUBLIC | METHOD_ATTRIBUTE_STATIC | METHOD_ATTRIBUTE_HIDE_BY_SIG | METHOD_ATTRIBUTE_FINAL; +#ifndef DISABLE_JIT tid_loc = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg); syncp_loc = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg); owner_loc = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg); - emit_obj_syncp_check (mb, syncp_loc, &obj_null_branch, &syncp_null_branch, FALSE); + emit_obj_syncp_check (mb, syncp_loc, &obj_null_branch, is_v4 ? &true_locktaken_branch : NULL, &syncp_null_branch, &thin_hash_branch, FALSE); /* mono. tls thread_tls_offset threadp @@ -788,7 +948,7 @@ mono_monitor_get_fast_enter_method (MonoMethod *monitor_enter_method) mono_mb_emit_byte (mb, MONO_CUSTOM_PREFIX); mono_mb_emit_byte (mb, CEE_MONO_TLS); mono_mb_emit_i4 (mb, thread_tls_offset); - mono_mb_emit_icon (mb, G_STRUCT_OFFSET (MonoThread, tid)); + mono_mb_emit_icon (mb, G_STRUCT_OFFSET (MonoInternalThread, tid)); mono_mb_emit_byte (mb, CEE_ADD); mono_mb_emit_byte (mb, CEE_LDIND_I); mono_mb_emit_stloc (mb, tid_loc); @@ -818,6 +978,12 @@ mono_monitor_get_fast_enter_method (MonoMethod *monitor_enter_method) mono_mb_emit_byte (mb, CEE_LDC_I4_0); mono_mb_emit_managed_call (mb, compare_exchange_method, NULL); has_owner_branch = mono_mb_emit_short_branch (mb, CEE_BRTRUE_S); + + if (is_v4) { + mono_mb_emit_byte (mb, CEE_LDARG_1); + mono_mb_emit_byte (mb, CEE_LDC_I4_1); + mono_mb_emit_byte (mb, CEE_STIND_I1); + } mono_mb_emit_byte (mb, CEE_RET); /* @@ -848,6 +1014,13 @@ mono_monitor_get_fast_enter_method (MonoMethod *monitor_enter_method) mono_mb_emit_byte (mb, CEE_LDC_I4_1); mono_mb_emit_byte (mb, CEE_ADD); mono_mb_emit_byte (mb, CEE_STIND_I4); + + if (is_v4) { + mono_mb_emit_byte (mb, CEE_LDARG_1); + mono_mb_emit_byte (mb, CEE_LDC_I4_1); + mono_mb_emit_byte (mb, CEE_STIND_I1); + } + mono_mb_emit_byte (mb, CEE_RET); /* @@ -857,40 +1030,47 @@ mono_monitor_get_fast_enter_method (MonoMethod *monitor_enter_method) ret */ + if (thin_hash_branch) + mono_mb_patch_short_branch (mb, thin_hash_branch); mono_mb_patch_short_branch (mb, obj_null_branch); mono_mb_patch_short_branch (mb, syncp_null_branch); mono_mb_patch_short_branch (mb, has_owner_branch); mono_mb_patch_short_branch (mb, other_owner_branch); + if (true_locktaken_branch) + mono_mb_patch_short_branch (mb, true_locktaken_branch); mono_mb_emit_byte (mb, CEE_LDARG_0); + if (is_v4) + mono_mb_emit_byte (mb, CEE_LDARG_1); mono_mb_emit_managed_call (mb, monitor_enter_method, NULL); mono_mb_emit_byte (mb, CEE_RET); +#endif - fast_monitor_enter = mono_mb_create_method (mb, mono_signature_no_pinvoke (monitor_enter_method), 5); - mono_mb_free (mb); + res = register_fastpath (mono_mb_create_method (mb, mono_signature_no_pinvoke (monitor_enter_method), 5), fast_path_idx); + + info = mono_image_alloc0 (mono_defaults.corlib, sizeof (WrapperInfo)); + info->subtype = is_v4 ? WRAPPER_SUBTYPE_FAST_MONITOR_ENTER_V4 : WRAPPER_SUBTYPE_FAST_MONITOR_ENTER; + mono_marshal_set_wrapper_info (res, info); - return fast_monitor_enter; + mono_mb_free (mb); + return res; } static MonoMethod* mono_monitor_get_fast_exit_method (MonoMethod *monitor_exit_method) { - static MonoMethod *fast_monitor_exit; - MonoMethodBuilder *mb; - int obj_null_branch, has_waiting_branch, has_syncp_branch, owned_branch, nested_branch; + MonoMethod *res; + int obj_null_branch, has_waiting_branch, has_syncp_branch, owned_branch, nested_branch, thin_hash_branch; int thread_tls_offset; int syncp_loc; - -#ifdef HAVE_MOVING_COLLECTOR - return NULL; -#endif + WrapperInfo *info; thread_tls_offset = mono_thread_get_tls_offset (); if (thread_tls_offset == -1) return NULL; - if (fast_monitor_exit) - return fast_monitor_exit; + if (monitor_il_fastpaths [FASTPATH_EXIT]) + return monitor_il_fastpaths [FASTPATH_EXIT]; mb = mono_mb_new (mono_defaults.monitor_class, "FastMonitorExit", MONO_WRAPPER_UNKNOWN); @@ -898,9 +1078,10 @@ mono_monitor_get_fast_exit_method (MonoMethod *monitor_exit_method) mb->method->flags = METHOD_ATTRIBUTE_PUBLIC | METHOD_ATTRIBUTE_STATIC | METHOD_ATTRIBUTE_HIDE_BY_SIG | METHOD_ATTRIBUTE_FINAL; +#ifndef DISABLE_JIT syncp_loc = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg); - emit_obj_syncp_check (mb, syncp_loc, &obj_null_branch, &has_syncp_branch, TRUE); + emit_obj_syncp_check (mb, syncp_loc, &obj_null_branch, NULL, &has_syncp_branch, &thin_hash_branch, TRUE); /* ret @@ -929,7 +1110,7 @@ mono_monitor_get_fast_exit_method (MonoMethod *monitor_exit_method) mono_mb_emit_byte (mb, MONO_CUSTOM_PREFIX); mono_mb_emit_byte (mb, CEE_MONO_TLS); mono_mb_emit_i4 (mb, thread_tls_offset); - mono_mb_emit_icon (mb, G_STRUCT_OFFSET (MonoThread, tid)); + mono_mb_emit_icon (mb, G_STRUCT_OFFSET (MonoInternalThread, tid)); mono_mb_emit_byte (mb, CEE_ADD); mono_mb_emit_byte (mb, CEE_LDIND_I); owned_branch = mono_mb_emit_short_branch (mb, CEE_BEQ_S); @@ -1017,16 +1198,23 @@ mono_monitor_get_fast_exit_method (MonoMethod *monitor_exit_method) ret */ + if (thin_hash_branch) + mono_mb_patch_short_branch (mb, thin_hash_branch); mono_mb_patch_short_branch (mb, obj_null_branch); mono_mb_patch_short_branch (mb, has_waiting_branch); mono_mb_emit_byte (mb, CEE_LDARG_0); mono_mb_emit_managed_call (mb, monitor_exit_method, NULL); mono_mb_emit_byte (mb, CEE_RET); +#endif - fast_monitor_exit = mono_mb_create_method (mb, mono_signature_no_pinvoke (monitor_exit_method), 5); + res = register_fastpath (mono_mb_create_method (mb, mono_signature_no_pinvoke (monitor_exit_method), 5), FASTPATH_EXIT); mono_mb_free (mb); - return fast_monitor_exit; + info = mono_image_alloc0 (mono_defaults.corlib, sizeof (WrapperInfo)); + info->subtype = WRAPPER_SUBTYPE_FAST_MONITOR_EXIT; + mono_marshal_set_wrapper_info (res, info); + + return res; } MonoMethod* @@ -1040,6 +1228,27 @@ mono_monitor_get_fast_path (MonoMethod *enter_or_exit) return NULL; } +/* + * mono_monitor_threads_sync_member_offset: + * @owner_offset: returns size and offset of the "owner" member + * @nest_offset: returns size and offset of the "nest" member + * @entry_count_offset: returns size and offset of the "entry_count" member + * + * Returns the offsets and sizes of three members of the + * MonoThreadsSync struct. The Monitor ASM fastpaths need this. + */ +void +mono_monitor_threads_sync_members_offset (int *owner_offset, int *nest_offset, int *entry_count_offset) +{ + MonoThreadsSync ts; + +#define ENCODE_OFF_SIZE(o,s) (((o) << 8) | ((s) & 0xff)) + + *owner_offset = ENCODE_OFF_SIZE (G_STRUCT_OFFSET (MonoThreadsSync, owner), sizeof (ts.owner)); + *nest_offset = ENCODE_OFF_SIZE (G_STRUCT_OFFSET (MonoThreadsSync, nest), sizeof (ts.nest)); + *entry_count_offset = ENCODE_OFF_SIZE (G_STRUCT_OFFSET (MonoThreadsSync, entry_count), sizeof (ts.entry_count)); +} + gboolean ves_icall_System_Threading_Monitor_Monitor_try_enter (MonoObject *obj, guint32 ms) { @@ -1054,13 +1263,26 @@ ves_icall_System_Threading_Monitor_Monitor_try_enter (MonoObject *obj, guint32 m return res == 1; } +void +ves_icall_System_Threading_Monitor_Monitor_try_enter_with_atomic_var (MonoObject *obj, guint32 ms, char *lockTaken) +{ + gint32 res; + do { + res = mono_monitor_try_enter_internal (obj, ms, TRUE); + /*This means we got interrupted during the wait and didn't got the monitor.*/ + if (res == -1) + mono_thread_interruption_checkpoint (); + } while (res == -1); + /*It's safe to do it from here since interruption would happen only on the wrapper.*/ + *lockTaken = res == 1; +} + gboolean ves_icall_System_Threading_Monitor_Monitor_test_owner (MonoObject *obj) { MonoThreadsSync *mon; - LOCK_DEBUG (g_message (G_GNUC_PRETTY_FUNCTION - ": Testing if %p is owned by thread %d", obj, GetCurrentThreadId())); + LOCK_DEBUG (g_message ("%s: Testing if %p is owned by thread %d", __func__, obj, GetCurrentThreadId())); mon = obj->synchronisation; #ifdef HAVE_MOVING_COLLECTOR @@ -1089,8 +1311,7 @@ ves_icall_System_Threading_Monitor_Monitor_test_synchronised (MonoObject *obj) { MonoThreadsSync *mon; - LOCK_DEBUG (g_message(G_GNUC_PRETTY_FUNCTION - ": (%d) Testing if %p is owned by any thread", GetCurrentThreadId (), obj)); + LOCK_DEBUG (g_message("%s: (%d) Testing if %p is owned by any thread", __func__, GetCurrentThreadId (), obj)); mon = obj->synchronisation; #ifdef HAVE_MOVING_COLLECTOR @@ -1124,8 +1345,7 @@ ves_icall_System_Threading_Monitor_Monitor_pulse (MonoObject *obj) { MonoThreadsSync *mon; - LOCK_DEBUG (g_message (G_GNUC_PRETTY_FUNCTION ": (%d) Pulsing %p", - GetCurrentThreadId (), obj)); + LOCK_DEBUG (g_message ("%s: (%d) Pulsing %p", __func__, GetCurrentThreadId (), obj)); mon = obj->synchronisation; #ifdef HAVE_MOVING_COLLECTOR @@ -1149,13 +1369,10 @@ ves_icall_System_Threading_Monitor_Monitor_pulse (MonoObject *obj) return; } - LOCK_DEBUG (g_message (G_GNUC_PRETTY_FUNCTION ": (%d) %d threads waiting", - GetCurrentThreadId (), g_slist_length (mon->wait_list))); + LOCK_DEBUG (g_message ("%s: (%d) %d threads waiting", __func__, GetCurrentThreadId (), g_slist_length (mon->wait_list))); if (mon->wait_list != NULL) { - LOCK_DEBUG (g_message (G_GNUC_PRETTY_FUNCTION - ": (%d) signalling and dequeuing handle %p", - GetCurrentThreadId (), mon->wait_list->data)); + LOCK_DEBUG (g_message ("%s: (%d) signalling and dequeuing handle %p", __func__, GetCurrentThreadId (), mon->wait_list->data)); SetEvent (mon->wait_list->data); mon->wait_list = g_slist_remove (mon->wait_list, mon->wait_list->data); @@ -1167,8 +1384,7 @@ ves_icall_System_Threading_Monitor_Monitor_pulse_all (MonoObject *obj) { MonoThreadsSync *mon; - LOCK_DEBUG (g_message(G_GNUC_PRETTY_FUNCTION ": (%d) Pulsing all %p", - GetCurrentThreadId (), obj)); + LOCK_DEBUG (g_message("%s: (%d) Pulsing all %p", __func__, GetCurrentThreadId (), obj)); mon = obj->synchronisation; #ifdef HAVE_MOVING_COLLECTOR @@ -1192,13 +1408,10 @@ ves_icall_System_Threading_Monitor_Monitor_pulse_all (MonoObject *obj) return; } - LOCK_DEBUG (g_message (G_GNUC_PRETTY_FUNCTION ": (%d) %d threads waiting", - GetCurrentThreadId (), g_slist_length (mon->wait_list))); + LOCK_DEBUG (g_message ("%s: (%d) %d threads waiting", __func__, GetCurrentThreadId (), g_slist_length (mon->wait_list))); while (mon->wait_list != NULL) { - LOCK_DEBUG (g_message (G_GNUC_PRETTY_FUNCTION - ": (%d) signalling and dequeuing handle %p", - GetCurrentThreadId (), mon->wait_list->data)); + LOCK_DEBUG (g_message ("%s: (%d) signalling and dequeuing handle %p", __func__, GetCurrentThreadId (), mon->wait_list->data)); SetEvent (mon->wait_list->data); mon->wait_list = g_slist_remove (mon->wait_list, mon->wait_list->data); @@ -1214,11 +1427,9 @@ ves_icall_System_Threading_Monitor_Monitor_wait (MonoObject *obj, guint32 ms) guint32 ret; gboolean success = FALSE; gint32 regain; - MonoThread *thread = mono_thread_current (); + MonoInternalThread *thread = mono_thread_internal_current (); - LOCK_DEBUG (g_message (G_GNUC_PRETTY_FUNCTION - ": (%d) Trying to wait for %p with timeout %dms", - GetCurrentThreadId (), obj, ms)); + LOCK_DEBUG (g_message ("%s: (%d) Trying to wait for %p with timeout %dms", __func__, GetCurrentThreadId (), obj, ms)); mon = obj->synchronisation; #ifdef HAVE_MOVING_COLLECTOR @@ -1251,8 +1462,7 @@ ves_icall_System_Threading_Monitor_Monitor_wait (MonoObject *obj, guint32 ms) return FALSE; } - LOCK_DEBUG (g_message (G_GNUC_PRETTY_FUNCTION ": (%d) queuing handle %p", - GetCurrentThreadId (), event)); + LOCK_DEBUG (g_message ("%s: (%d) queuing handle %p", __func__, GetCurrentThreadId (), event)); mono_thread_current_check_pending_interrupt (); @@ -1265,8 +1475,7 @@ ves_icall_System_Threading_Monitor_Monitor_wait (MonoObject *obj, guint32 ms) mon->nest = 1; mono_monitor_exit (obj); - LOCK_DEBUG (g_message (G_GNUC_PRETTY_FUNCTION ": (%d) Unlocked %p lock %p", - GetCurrentThreadId (), obj, mon)); + LOCK_DEBUG (g_message ("%s: (%d) Unlocked %p lock %p", __func__, GetCurrentThreadId (), obj, mon)); /* There's no race between unlocking mon and waiting for the * event, because auto reset events are sticky, and this event @@ -1281,7 +1490,14 @@ ves_icall_System_Threading_Monitor_Monitor_wait (MonoObject *obj, guint32 ms) mono_thread_clr_state (thread, ThreadState_WaitSleepJoin); if (mono_thread_interruption_requested ()) { - CloseHandle (event); + /* + * Can't remove the event from wait_list, since the monitor is not locked by + * us. So leave it there, mon_new () will delete it when the mon structure + * is placed on the free list. + * FIXME: The caller expects to hold the lock after the wait returns, but it + * doesn't happen in this case: + * http://connect.microsoft.com/VisualStudio/feedback/ViewFeedback.aspx?FeedbackID=97268 + */ return FALSE; } @@ -1303,8 +1519,7 @@ ves_icall_System_Threading_Monitor_Monitor_wait (MonoObject *obj, guint32 ms) mon->nest = nest; - LOCK_DEBUG (g_message (G_GNUC_PRETTY_FUNCTION ": (%d) Regained %p lock %p", - GetCurrentThreadId (), obj, mon)); + LOCK_DEBUG (g_message ("%s: (%d) Regained %p lock %p", __func__, GetCurrentThreadId (), obj, mon)); if (ret == WAIT_TIMEOUT) { /* Poll the event again, just in case it was signalled @@ -1324,12 +1539,10 @@ ves_icall_System_Threading_Monitor_Monitor_wait (MonoObject *obj, guint32 ms) */ if (ret == WAIT_OBJECT_0) { - LOCK_DEBUG (g_message (G_GNUC_PRETTY_FUNCTION ": (%d) Success", - GetCurrentThreadId ())); + LOCK_DEBUG (g_message ("%s: (%d) Success", __func__, GetCurrentThreadId ())); success = TRUE; } else { - LOCK_DEBUG (g_message (G_GNUC_PRETTY_FUNCTION ": (%d) Wait failed, dequeuing handle %p", - GetCurrentThreadId (), event)); + LOCK_DEBUG (g_message ("%s: (%d) Wait failed, dequeuing handle %p", __func__, GetCurrentThreadId (), event)); /* No pulse, so we have to remove ourself from the * wait queue */