+static void
+mono_monitor_ensure_owned (LockWord lw, guint32 id)
+{
+ if (lock_word_is_flat (lw)) {
+ if (lock_word_get_owner (lw) == id)
+ return;
+ } else if (lock_word_is_inflated (lw)) {
+ if (mon_status_get_owner (lock_word_get_inflated_lock (lw)->status) == id)
+ return;
+ }
+
+ mono_set_pending_exception (mono_get_exception_synchronization_lock ("Object synchronization method was called from an unsynchronized block of code."));
+}
+
+/*
+ * When this function is called it has already been established that the
+ * current thread owns the monitor.
+ */
+static void
+mono_monitor_exit_inflated (MonoObject *obj)
+{
+ LockWord lw;
+ MonoThreadsSync *mon;
+ guint32 nest;
+
+ lw.sync = obj->synchronisation;
+ mon = lock_word_get_inflated_lock (lw);
+
+ nest = mon->nest - 1;
+ if (nest == 0) {
+ guint32 new_status, old_status, tmp_status;
+
+ old_status = mon->status;
+
+ /*
+ * Release lock and do the wakeup stuff. It's possible that
+ * the last blocking thread gave up waiting just before we
+ * release the semaphore resulting in a negative entry count
+ * and a futile wakeup next time there's contention for this
+ * object.
+ */
+ for (;;) {
+ gboolean have_waiters = mon_status_have_waiters (old_status);
+
+ new_status = mon_status_set_owner (old_status, 0);
+ if (have_waiters)
+ new_status = mon_status_decrement_entry_count (new_status);
+ tmp_status = InterlockedCompareExchange ((gint32*)&mon->status, new_status, old_status);
+ if (tmp_status == old_status) {
+ if (have_waiters)
+ ReleaseSemaphore (mon->entry_sem, 1, NULL);
+ break;
+ }
+ old_status = tmp_status;
+ }
+ LOCK_DEBUG (g_message ("%s: (%d) Object %p is now unlocked", __func__, mono_thread_info_get_small_id (), obj));
+
+ /* object is now unlocked, leave nest==1 so we don't
+ * need to set it when the lock is reacquired
+ */
+ } else {
+ LOCK_DEBUG (g_message ("%s: (%d) Object %p is now locked %d times", __func__, mono_thread_info_get_small_id (), obj, nest));
+ mon->nest = nest;
+ }
+}
+
+/*
+ * When this function is called it has already been established that the
+ * current thread owns the monitor.
+ */
+static void
+mono_monitor_exit_flat (MonoObject *obj, LockWord old_lw)
+{
+ LockWord new_lw, tmp_lw;
+ if (G_UNLIKELY (lock_word_is_nested (old_lw)))
+ new_lw = lock_word_decrement_nest (old_lw);
+ else
+ new_lw.lock_word = 0;
+
+ tmp_lw.sync = InterlockedCompareExchangePointer ((gpointer*)&obj->synchronisation, new_lw.sync, old_lw.sync);
+ if (old_lw.sync != tmp_lw.sync) {
+ /* Someone inflated the lock in the meantime */
+ mono_monitor_exit_inflated (obj);
+ }
+
+ LOCK_DEBUG (g_message ("%s: (%d) Object %p is now locked %d times; LW = %p", __func__, mono_thread_info_get_small_id (), obj, lock_word_get_nest (new_lw), obj->synchronisation));
+}
+