+ 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