* 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 <config.h>
#include <mono/metadata/debug-helpers.h>
#include <mono/metadata/tabledefs.h>
#include <mono/metadata/marshal.h>
+#include <mono/metadata/profiler-private.h>
#include <mono/utils/mono-time.h>
/*
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;
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;
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;
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 */
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_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));
+ mono_profiler_monitor_event (obj, MONO_PROFILER_MONITOR_FAIL);
+
if (ret == WAIT_IO_COMPLETION)
return -1;
else
}
}
+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;
+}
+
static void
emit_obj_syncp_check (MonoMethodBuilder *mb, int syncp_loc, int *obj_null_branch, int *syncp_true_false_branch,
gboolean branch_on_true)
return NULL;
}
- mb = mono_mb_new (mono_defaults.monitor_class, "FastMonitorEnter", MONO_WRAPPER_MONITOR_FAST_ENTER);
+ mb = mono_mb_new (mono_defaults.monitor_class, "FastMonitorEnter", MONO_WRAPPER_UNKNOWN);
mb->method->slot = -1;
mb->method->flags = METHOD_ATTRIBUTE_PUBLIC | METHOD_ATTRIBUTE_STATIC |
if (fast_monitor_exit)
return fast_monitor_exit;
- mb = mono_mb_new (mono_defaults.monitor_class, "FastMonitorExit", MONO_WRAPPER_MONITOR_FAST_EXIT);
+ mb = mono_mb_new (mono_defaults.monitor_class, "FastMonitorExit", MONO_WRAPPER_UNKNOWN);
mb->method->slot = -1;
mb->method->flags = METHOD_ATTRIBUTE_PUBLIC | METHOD_ATTRIBUTE_STATIC |
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)
{