X-Git-Url: http://wien.tomnetworks.com/gitweb/?a=blobdiff_plain;f=mono%2Fmetadata%2Fmonitor.c;h=9933f1dd48730ba5f4d5ae377a67752543063a85;hb=157cb97206f627685c15410953d2767146f6e426;hp=fc7038490faebae35fb1763ed0bdbbde7eab8553;hpb=ccb6dff0536881b3861f1769078be3bd6b5055b7;p=mono.git diff --git a/mono/metadata/monitor.c b/mono/metadata/monitor.c index fc7038490fa..9933f1dd487 100644 --- a/mono/metadata/monitor.c +++ b/mono/metadata/monitor.c @@ -26,6 +26,7 @@ #include #include #include +#include /* * Pull the list of opcodes @@ -125,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); + } + */ } /* @@ -219,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 */ @@ -245,6 +271,7 @@ mon_new (gsize id) 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; } @@ -285,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; } @@ -512,7 +542,9 @@ 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) { @@ -588,8 +620,10 @@ retry_contended: InterlockedIncrement (&mon->entry_count); +#ifndef DISABLE_PERFCOUNTERS mono_perfcounters->thread_queue_len++; mono_perfcounters->thread_queue_max++; +#endif thread = mono_thread_internal_current (); mono_thread_set_state (thread, ThreadState_WaitSleepJoin); @@ -603,7 +637,9 @@ retry_contended: 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 (); @@ -749,9 +785,11 @@ mono_monitor_get_object_monitor_weak_link (MonoObject *object) 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 @@ -761,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 @@ -778,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* -mono_monitor_get_fast_enter_method (MonoMethod *monitor_enter_method) +register_fastpath (MonoMethod *method, int idx) { - static MonoMethod *fast_monitor_enter; - static MonoMethod *compare_exchange_method; + mono_memory_barrier (); + monitor_il_fastpaths [idx] = method; + return method; +} +static MonoMethod* +mono_monitor_get_fast_enter_method (MonoMethod *monitor_enter_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; @@ -817,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 @@ -877,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); /* @@ -907,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); /* @@ -916,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); @@ -957,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 @@ -1076,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* @@ -1134,6 +1263,20 @@ 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) {