#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)