New test.
[mono.git] / mono / metadata / monitor.c
index a7b5556d9e64e6db96b0912cf5d4a0b8424f4045..3e3ac482a2b5d18457bb825b82113470b164f74a 100644 (file)
@@ -91,6 +91,63 @@ mono_monitor_cleanup (void)
        /*DeleteCriticalSection (&monitor_mutex);*/
 }
 
+static int
+monitor_is_on_freelist (MonoThreadsSync *mon)
+{
+       MonitorArray *marray;
+       for (marray = monitor_allocated; marray; marray = marray->next) {
+               if (mon >= marray->monitors && mon < &marray->monitors [marray->num_monitors])
+                       return TRUE;
+       }
+       return FALSE;
+}
+
+/**
+ * mono_locks_dump:
+ * @include_untaken:
+ *
+ * Print a report on stdout of the managed locks currently held by
+ * threads. If @include_untaken is specified, list also inflated locks
+ * which are unheld.
+ * This is supposed to be used in debuggers like gdb.
+ */
+void
+mono_locks_dump (gboolean include_untaken)
+{
+       int i;
+       int used = 0, on_freelist = 0, to_recycle = 0, total = 0, num_arrays = 0;
+       MonoThreadsSync *mon;
+       MonitorArray *marray;
+       for (mon = monitor_freelist; mon; mon = mon->data)
+               on_freelist++;
+       for (marray = monitor_allocated; marray; marray = marray->next) {
+               total += marray->num_monitors;
+               num_arrays++;
+               for (i = 0; i < marray->num_monitors; ++i) {
+                       mon = &marray->monitors [i];
+                       if (mon->data == NULL) {
+                               if (i < marray->num_monitors - 1)
+                                       to_recycle++;
+                       } else {
+                               if (!monitor_is_on_freelist (mon->data)) {
+                                       MonoObject *holder = mono_gc_weak_link_get (&mon->data);
+                                       if (mon->owner) {
+                                               g_print ("Lock %p in object %p held by thread %p, nest level: %d\n",
+                                                       mon, holder, (void*)mon->owner, mon->nest);
+                                               if (mon->entry_sem)
+                                                       g_print ("\tWaiting on semaphore %p: %d\n", mon->entry_sem, mon->entry_count);
+                                       } else if (include_untaken) {
+                                               g_print ("Lock %p in object %p untaken\n", mon, holder);
+                                       }
+                                       used++;
+                               }
+                       }
+               }
+       }
+       g_print ("Total locks (in %d array(s)): %d, used: %d, on freelist: %d, to recycle: %d\n",
+               num_arrays, total, used, on_freelist, to_recycle);
+}
+
 /* LOCKING: this is called with monitor_mutex held */
 static void 
 mon_finalize (MonoThreadsSync *mon)
@@ -404,6 +461,7 @@ retry:
        if (mon->entry_sem == NULL) {
                /* Create the semaphore */
                sem = CreateSemaphore (NULL, 0, 0x7fffffff, NULL);
+               g_assert (sem != NULL);
                if (InterlockedCompareExchangePointer ((gpointer*)&mon->entry_sem, sem, NULL) != NULL) {
                        /* Someone else just put a handle here */
                        CloseHandle (sem);
@@ -755,6 +813,9 @@ ves_icall_System_Threading_Monitor_Monitor_wait (MonoObject *obj, guint32 ms)
                mono_raise_exception (mono_get_exception_synchronization_lock ("Not locked by this thread"));
                return FALSE;
        }
+
+       /* Do this WaitSleepJoin check before creating the event handle */
+       mono_thread_current_check_pending_interrupt ();
        
        event = CreateEvent (NULL, FALSE, FALSE, NULL);
        if (event == NULL) {