--- /dev/null
+using System;
+using System.IO;
+using System.Threading;
+
+public class PulseTest
+{
+ private bool startedUp = false;
+ private int threadNum = 0;
+ private object theLock = new object ();
+
+ public static void Main (string[] args)
+ {
+ int lastThreadNum = 0;
+
+ for (int i = 0; i < 100; ++i) {
+ /*
+ * Start a thread going.
+ */
+ PulseTest pulseTest = new PulseTest ();
+ pulseTest.threadNum = ++ lastThreadNum;
+ Thread sysThread = new Thread (pulseTest.ThreadMain);
+
+ /*
+ * Block thread from doing anything.
+ */
+ Monitor.Enter (pulseTest.theLock);
+
+ /*
+ * Now start it.
+ */
+ sysThread.Start ();
+
+ /*
+ * Wait for pulsetest thread to call Monitor.Wait().
+ */
+ while (!pulseTest.startedUp) {
+ pulseTest.Message ("Main", "waiting");
+ Monitor.Wait (pulseTest.theLock);
+ pulseTest.Message ("Main", "woken");
+ }
+ Monitor.Exit (pulseTest.theLock);
+
+ /*
+ * Whilst it is sitting in Monitor.Wait, kill it off.
+ *
+ * Without the patch, the wait event sits in mon->wait_list,
+ * even as the mon struct gets recycled onto monitor_freelist.
+ *
+ * With the patch, the event is unlinked when the mon struct
+ * gets recycled.
+ */
+ pulseTest.Message ("Main", "disposing");
+ sysThread.Abort ();
+ sysThread.Join ();
+ pulseTest.Message ("Main", "disposed");
+ }
+ }
+
+ private void ThreadMain ()
+ {
+ Monitor.Enter (theLock);
+ startedUp = true;
+ Monitor.Pulse (theLock);
+ while (true) {
+ Message ("ThreadMain", "waiting");
+
+ /*
+ * This puts an event onto mon->wait_list.
+ * Then Main() does a sysThread.Abort() and
+ * the event is left on mon->wait_list.
+ */
+ Monitor.Wait (theLock);
+ Message ("ThreadMain", "woken");
+ }
+ }
+
+ private void Message (string func, string msg)
+ {
+ Console.WriteLine ("{0}[{1}]*: {2}", func, threadNum, msg);
+ }
+}