You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@etch.apache.org by sc...@apache.org on 2008/12/03 20:42:19 UTC

svn commit: r723034 - in /incubator/etch/trunk/binding-csharp/runtime/src: main/csharp/Etch/Util/AbstractStartable.cs main/csharp/Etch/Util/AlarmManager.cs main/csharp/Etch/Util/TodoManager.cs test/csharp/Etch/Util/TestAlarmManager.cs

Author: sccomer
Date: Wed Dec  3 11:42:19 2008
New Revision: 723034

URL: http://svn.apache.org/viewvc?rev=723034&view=rev
Log:
csharp fix for ETCH-11: AlarmManager deadlocks during shutdown(). break lock on AbstractStartable start() and stop() methods. Add back necessary synchronization for Monitor.PulseAll() in Stop0(). Port java version of unit test.

Modified:
    incubator/etch/trunk/binding-csharp/runtime/src/main/csharp/Etch/Util/AbstractStartable.cs
    incubator/etch/trunk/binding-csharp/runtime/src/main/csharp/Etch/Util/AlarmManager.cs
    incubator/etch/trunk/binding-csharp/runtime/src/main/csharp/Etch/Util/TodoManager.cs
    incubator/etch/trunk/binding-csharp/runtime/src/test/csharp/Etch/Util/TestAlarmManager.cs

Modified: incubator/etch/trunk/binding-csharp/runtime/src/main/csharp/Etch/Util/AbstractStartable.cs
URL: http://svn.apache.org/viewvc/incubator/etch/trunk/binding-csharp/runtime/src/main/csharp/Etch/Util/AbstractStartable.cs?rev=723034&r1=723033&r2=723034&view=diff
==============================================================================
--- incubator/etch/trunk/binding-csharp/runtime/src/main/csharp/Etch/Util/AbstractStartable.cs (original)
+++ incubator/etch/trunk/binding-csharp/runtime/src/main/csharp/Etch/Util/AbstractStartable.cs Wed Dec  3 11:42:19 2008
@@ -24,31 +24,33 @@
     /// </summary>
     abstract public class AbstractStartable : Startable
     {
-        [MethodImpl(MethodImplOptions.Synchronized)]
         public void Start()
         {
-            if (IsStarted())
-                throw new Exception("is already started");
+            lock (this)
+            {
+                if (IsStarted())
+                    throw new Exception("is already started");
+                SetStarted();
+            }
 
             try
             {
-                started = true;
                 Start0();
             }
             catch (Exception e)
             {
-                SetStopped();
-                Stop0();
-                throw e;
+                Stop();
+                throw;
             }
         }
 
-        [MethodImpl(MethodImplOptions.Synchronized)]
         public void Stop()
         {
-            CheckIsStarted();
-
-            started = false;
+            lock (this)
+            {
+                CheckIsStarted();
+                SetStopped();
+            }
 
             Stop0();
         }

Modified: incubator/etch/trunk/binding-csharp/runtime/src/main/csharp/Etch/Util/AlarmManager.cs
URL: http://svn.apache.org/viewvc/incubator/etch/trunk/binding-csharp/runtime/src/main/csharp/Etch/Util/AlarmManager.cs?rev=723034&r1=723033&r2=723034&view=diff
==============================================================================
--- incubator/etch/trunk/binding-csharp/runtime/src/main/csharp/Etch/Util/AlarmManager.cs (original)
+++ incubator/etch/trunk/binding-csharp/runtime/src/main/csharp/Etch/Util/AlarmManager.cs Wed Dec  3 11:42:19 2008
@@ -140,7 +140,7 @@
             worker = new Thread[nWorkers];
             for (int i = 0; i < nWorkers; i++)
             {
-                worker[i] = new Thread(new ThreadStart(run));
+                worker[i] = new Thread(run);
                 worker[i].IsBackground = true;
                 worker[i].Start();
             }
@@ -151,7 +151,11 @@
         {
             ClearAlarms();
             ClearQueue();
-            System.Threading.Monitor.PulseAll(this);
+
+            lock (this)
+            {
+                Monitor.PulseAll(this);
+            }
 
             for (int i = 0; i < nWorkers; i++)
             {
@@ -178,7 +182,7 @@
         public void Add(AlarmListener listener, Object state, int delay)
         {
             if (listener == null)
-                throw new ArgumentNullException("listener == null");
+                throw new ArgumentNullException("listener");
 
             if (delay <= 0)
                 throw new ArgumentException("delay <= 0");
@@ -215,7 +219,6 @@
 
             alarm.setDue(due);
             Enqueue(alarm);
-
             NotifyWorker("update");
         }
 
@@ -231,9 +234,10 @@
 
             Alarm alarm = RemoveAlarm(listener);
             if (alarm != null)
+            {
                 Dequeue(alarm);
-
-            NotifyWorker("remove");
+                NotifyWorker("remove");
+            }
         }
 
         [MethodImpl(MethodImplOptions.Synchronized)]
@@ -252,10 +256,10 @@
                 else
                     Remove(alarm);
             }
-            catch (Exception)
+            catch (Exception e)
             {
                 Remove(alarm);
-                //			Log.report( "wakeup", "who", alarm.listener, Log.EXCP, e );
+                Report(e);
             }
         }
 
@@ -284,7 +288,7 @@
                             {
                                 //Console.WriteLine(" Waiting in getNextDueAlarm ");
 
-                                System.Threading.Monitor.Wait(this, Int32.MaxValue);
+                                Monitor.Wait(this, Int32.MaxValue);
 
                                 //Console.WriteLine(" Done Waiting in getNextDueAlarm ");
 
@@ -306,7 +310,7 @@
                                 if (delay > 0)
                                 {
                                     int d = (int)delay;
-                                    System.Threading.Monitor.Wait(this, d);
+                                    Monitor.Wait(this, d);
                                 }
                                 continue;
                             }
@@ -335,7 +339,7 @@
         {
             //		Log.report( "notify", "who", this, "reason", reason, "where", new Throwable() );
             // the set of alarms has changed.
-            System.Threading.Monitor.Pulse(this);
+            Monitor.Pulse(this);
         }
 
         public void run()
@@ -350,9 +354,13 @@
             }
             catch (Exception e)
             {
-                Console.WriteLine(e);
+                Report(e);
             }
+        }
 
+        private void Report(Exception e)
+        {
+            Console.WriteLine(e);
         }
 
         private Alarm GetAlarm(AlarmListener listener)
@@ -476,8 +484,6 @@
                 if (obj == this)
                     return true;
 
-
-
                 if (obj == null)
                     return false;
 

Modified: incubator/etch/trunk/binding-csharp/runtime/src/main/csharp/Etch/Util/TodoManager.cs
URL: http://svn.apache.org/viewvc/incubator/etch/trunk/binding-csharp/runtime/src/main/csharp/Etch/Util/TodoManager.cs?rev=723034&r1=723033&r2=723034&view=diff
==============================================================================
--- incubator/etch/trunk/binding-csharp/runtime/src/main/csharp/Etch/Util/TodoManager.cs (original)
+++ incubator/etch/trunk/binding-csharp/runtime/src/main/csharp/Etch/Util/TodoManager.cs Wed Dec  3 11:42:19 2008
@@ -83,7 +83,10 @@
      
         protected override void Stop0()
         {
-            System.Threading.Monitor.PulseAll( this );
+            lock (this)
+            {
+                Monitor.PulseAll(this);
+            }
         }
 
         /// <summary>
@@ -98,7 +101,7 @@
             CheckIsStarted();
 
             int n = AddEntry( todo );
-            System.Threading.Monitor.Pulse( this );
+            Monitor.Pulse( this );
 
             ConsiderStartingAWorker( n ) ;
 
@@ -160,7 +163,7 @@
         private void StartAWorker()
         {
             workers.Adjust( 1 );
-            Thread t = new Thread( new ThreadStart( Run ) );
+            Thread t = new Thread(Run);
             t.Start();
         }
 
@@ -265,7 +268,7 @@
                         return null;
                     }
 
-                    System.Threading.Monitor.Wait( this, workerLinger );
+                    Monitor.Wait( this, workerLinger );
 
                     // we lingered. we might have been woken because
                     // we're stopping, or a todo might have been

Modified: incubator/etch/trunk/binding-csharp/runtime/src/test/csharp/Etch/Util/TestAlarmManager.cs
URL: http://svn.apache.org/viewvc/incubator/etch/trunk/binding-csharp/runtime/src/test/csharp/Etch/Util/TestAlarmManager.cs?rev=723034&r1=723033&r2=723034&view=diff
==============================================================================
--- incubator/etch/trunk/binding-csharp/runtime/src/test/csharp/Etch/Util/TestAlarmManager.cs (original)
+++ incubator/etch/trunk/binding-csharp/runtime/src/test/csharp/Etch/Util/TestAlarmManager.cs Wed Dec  3 11:42:19 2008
@@ -23,42 +23,437 @@
     [TestFixture]
     public class TestAlarmManager
     {
-        private const int Q1 = 30;
-        private const int Q2 = 60;
+        private const int Q1 = 50;
+
+        private const int Q2 = 100;
+
+        private const int Q3 = 150;
+
+        private readonly Object s1 = new Object();
+
+        private readonly Object s2 = new Object();
+
+        //private readonly MyAlarmListener listener = new MyAlarmListener(0);
+
 
         [Test]
         public void start1()
         {
+            AlarmManager am = new AlarmManager();
+            Assert.IsFalse(am.IsStarted());
+            am.Start();
+            Assert.IsTrue(am.IsStarted());
         }
 
+
         [Test]
+        [ExpectedException(typeof(Exception))]
         public void start2()
         {
+            // already started
+            AlarmManager am = new AlarmManager();
+            Assert.IsFalse(am.IsStarted());
+            am.Start();
+            Assert.IsTrue(am.IsStarted());
+            am.Start();
+        }
+
+
+        [Test]
+        [ExpectedException(typeof(Exception))]
+        public void stop1()
+        {
+            // is not started
+            AlarmManager am = new AlarmManager();
+            Assert.IsFalse(am.IsStarted());
+            am.Stop();
+        }
+
+
+        [Test]
+        public void stop2()
+        {
+            AlarmManager am = new AlarmManager();
+            Assert.IsFalse(am.IsStarted());
+            am.Start();
+            Assert.IsTrue(am.IsStarted());
+            am.Stop();
+            Assert.IsFalse(am.IsStarted());
+        }
+
+
+        [Test]
+        public void static1()
+        {
+            AlarmManager.shutdown();
+
+            Assert.IsNull(AlarmManager.GetAlarmManager(false));
+            Assert.IsNull(AlarmManager.GetAlarmManager(false));
+
+            AlarmManager am1 = AlarmManager.GetAlarmManager(true);
+            Assert.IsNotNull(am1);
+            Assert.IsTrue(am1.IsStarted());
+
+            AlarmManager am2 = AlarmManager.GetAlarmManager(true);
+            Assert.AreSame(am2, am1);
+            Assert.IsTrue(am1.IsStarted());
+
+            AlarmManager.shutdown();
+            Assert.IsFalse(am1.IsStarted());
+            Assert.IsNull(AlarmManager.GetAlarmManager(false));
+
+            AlarmManager.shutdown();
+        }
+
+
+        [Test]
+        public void listener1()
+        {
+            MyAlarmListener listener = new MyAlarmListener(0);
+
+            Assert.AreEqual(0, listener.delay);
+            Assert.IsFalse(listener.wake.Get());
+            Assert.IsNull(listener.state);
+
+            listener.Wakeup(null, null, 12345);
+            Assert.AreEqual(0, listener.delay);
+            Assert.IsTrue(listener.wake.Get());
+            Assert.IsNull(listener.state);
+
+            listener.Wakeup(null, s1, 23456);
+            Assert.AreEqual(0, listener.delay);
+            Assert.IsTrue(listener.wake.Get());
+            Assert.AreSame(s1, listener.state);
+
+            MyAlarmListener listener1 = new MyAlarmListener(1);
+            Assert.AreEqual(1, listener1.delay);
+        }
+
+
+        [Test]
+        [ExpectedException(typeof(Exception))]
+        public void add1()
+        {
+            // is not started
+            AlarmManager am = new AlarmManager();
+
+            MyAlarmListener listener = new MyAlarmListener(0);
+
+            am.Add(listener, null, Q1);
+        }
+
+
+        [Test]
+        [ExpectedException(typeof(ArgumentNullException))]
+        public void add2()
+        {
+            // listener == null
+            AlarmManager am = new AlarmManager();
+            am.Start();
+
+            am.Add(null, null, Q1);
+        }
+
+
+        [Test]
+        [ExpectedException(typeof(ArgumentException))]
+        public void add3()
+        {
+            // delay <= 0
+            AlarmManager am = new AlarmManager();
+            am.Start();
+
+            MyAlarmListener listener = new MyAlarmListener(0);
+
+            am.Add(listener, null, -1);
+        }
+
+
+        [Test]
+        public void add4()
+        {
+            AlarmManager am = new AlarmManager();
+            am.Start();
+
+            MyAlarmListener listener = new MyAlarmListener(0);
+
+            //Log("Adding");
+            am.Add(listener, null, Q1);
+            //Log("Added");
+            Assert.IsFalse(listener.wake.Get());
+            Assert.IsNull(listener.state);
+
+            Thread.Sleep(Q2);
+            Assert.IsTrue(listener.wake.Get());
+            Assert.IsNull(listener.state);
+        }
+
+        private static readonly long t0 = HPTimer.Now();
+
+        //public static void Log(string msg)
+        //{
+        //    Console.WriteLine("{0} happened at {1}", msg, (HPTimer.Now()-t0)/1000000.0);
+        //}
+
+        [Test]
+        public void add5()
+        {
+            AlarmManager am = new AlarmManager();
+            am.Start();
+
+            MyAlarmListener listener = new MyAlarmListener(0);
+
+            am.Add(listener, s1, Q1);
+            Assert.IsFalse(listener.wake.Get());
+            Assert.IsNull(listener.state);
+
+            Thread.Sleep(Q2);
+            Assert.IsTrue(listener.wake.Get());
+            Assert.AreSame(s1, listener.state);
+        }
+
+
+        [Test]
+        public void add6()
+        {
+            AlarmManager am = new AlarmManager();
+            am.Start();
+
+            MyAlarmListener listener = new MyAlarmListener(0);
+
+            am.Add(listener, s1, Q3);
+            Assert.IsFalse(listener.wake.Get());
+            Assert.IsNull(listener.state);
+
+            am.Add(listener, s2, Q1);
+            Assert.IsFalse(listener.wake.Get());
+            Assert.IsNull(listener.state);
+
+            Thread.Sleep(Q2);
+            Assert.IsTrue(listener.wake.Get());
+            Assert.AreSame(s2, listener.state);
+        }
+
+
+        [Test]
+        public void add7()
+        {
+            AlarmManager am = new AlarmManager();
+            am.Start();
+
+            MyAlarmListener listener = new MyAlarmListener(0);
+
+            listener.excp = true;
+            am.Add(listener, s1, Q1);
+            Assert.IsFalse(listener.wake.Get());
+            Assert.IsNull(listener.state);
+
+            Thread.Sleep(Q2);
+            Assert.IsTrue(listener.wake.Get());
+            Assert.AreSame(s1, listener.state);
+        }
+
+
+        [Test]
+        [ExpectedException(typeof(Exception))]
+        public void remove1()
+        {
+            // is not started
+            AlarmManager am = new AlarmManager();
+
+            MyAlarmListener listener = new MyAlarmListener(0);
+
+            am.Remove(listener);
+        }
+
+
+        [Test]
+        public void remove2()
+        {
+            AlarmManager am = new AlarmManager();
+            am.Start();
+
+            MyAlarmListener listener = new MyAlarmListener(0);
+
+            am.Remove(listener);
         }
 
+
         [Test]
-        public void start3()
+        public void remove3()
         {
+            AlarmManager am = new AlarmManager();
+            am.Start();
+
+            MyAlarmListener listener = new MyAlarmListener(0);
+
+            am.Add(listener, null, Q1);
+            Assert.IsFalse(listener.wake.Get());
+            Assert.IsNull(listener.state);
+
+            am.Remove(listener);
+            Assert.IsFalse(listener.wake.Get());
+            Assert.IsNull(listener.state);
+
+            Thread.Sleep(Q2);
+            Assert.IsFalse(listener.wake.Get());
+            Assert.IsNull(listener.state);
+        }
+
+
+        [Test]
+        public void repeat1()
+        {
+            AlarmManager am = new AlarmManager();
+            am.Start();
+
+            MyAlarmListener listener = new MyAlarmListener(0);
+
+            listener.delay = Q2;
+            am.Add(listener, null, Q2);
+
+            listener.wake.WaitUntilEqAndSet(true, Q3, false);
+            Console.WriteLine("due0 = {0}", listener.due);
+            long t0 = listener.due;
+
+            listener.wake.WaitUntilEqAndSet(true, Q3, false);
+            Console.WriteLine("due1 = {0}", listener.due);
+            long d1 = listener.due - t0;
+
+            listener.wake.WaitUntilEqAndSet(true, Q3, false);
+            Console.WriteLine("due2 = {0}", listener.due);
+            long d2 = listener.due - t0;
+
+            listener.wake.WaitUntilEqAndSet(true, Q3, false);
+            Console.WriteLine("due3 = {0}", listener.due);
+            long d3 = listener.due - t0;
+
+            Thread.Sleep(Q1);
+            listener.delay = 0;
+
+            listener.wake.WaitUntilEqAndSet(true, Q3, false);
+            Console.WriteLine("due4 = {0}", listener.due);
+            long d4 = listener.due - t0;
+
+            long m1 = d1 / d1;
+            long m2 = d2 / d1;
+            long m3 = d3 / d1;
+            long m4 = d4 / d1;
+
+            Console.WriteLine("times {0} {1} {2} {3} {4}", t0, d1, d2, d3, d4);
+
+            Assert.AreEqual(1, m1);
+            Assert.AreEqual(2, m2);
+            Assert.AreEqual(3, m3);
+            Assert.AreEqual(4, m4);
+        }
+
+
+        [Test]
+        public void repeat2()
+        {
+            AlarmManager am = new AlarmManager();
+            am.Start();
+
+            MyAlarmListener listener = new MyAlarmListener(0);
+
+            listener.delay = -Q2;
+            am.Add(listener, null, Q2);
+
+            listener.wake.WaitUntilEqAndSet(true, Q3, false);
+            Console.WriteLine("due0 = {0}", listener.due);
+            long t0 = listener.due;
+
+            listener.wake.WaitUntilEqAndSet(true, Q3, false);
+            Console.WriteLine("due1 = {0}", listener.due);
+            long d1 = listener.due - t0;
+
+            listener.wake.WaitUntilEqAndSet(true, Q3, false);
+            Console.WriteLine("due2 = {0}", listener.due);
+            long d2 = listener.due - t0;
+
+            listener.wake.WaitUntilEqAndSet(true, Q3, false);
+            Console.WriteLine("due3 = {0}", listener.due);
+            long d3 = listener.due - t0;
+
+            Thread.Sleep(Q1);
+            listener.delay = 0;
+
+            listener.wake.WaitUntilEqAndSet(true, Q3, false);
+            Console.WriteLine("due4 = {0}", listener.due);
+            long d4 = listener.due - t0;
+
+            long m1 = d1 / d1;
+            long m2 = d2 / d1;
+            long m3 = d3 / d1;
+            long m4 = d4 / d1;
+
+            Console.WriteLine("times {0} {1} {2} {3} {4}", t0, d1, d2, d3, d4);
+
+            Assert.AreEqual(1, m1);
+            Assert.AreEqual(2, m2);
+            Assert.AreEqual(3, m3);
+            Assert.AreEqual(4, m4);
+        }
+
+
+        [Test]
+        [ExpectedException(typeof(ThreadInterruptedException))]
+        public void repeat3()
+        {
+            // timeout
+            AlarmManager am = new AlarmManager();
+            am.Start();
+
+            MyAlarmListener listener = new MyAlarmListener(0);
+
+            listener.delay = Q2;
+            am.Add(listener, null, Q2);
+
+            listener.wake.WaitUntilEqAndSet(true, Q3, false);
+
+            listener.wake.WaitUntilEqAndSet(true, Q3, false);
+
+            listener.wake.WaitUntilEqAndSet(true, Q3, false);
+
+            Thread.Sleep(Q1);
+            listener.delay = 0;
+
+            listener.wake.WaitUntilEqAndSet(true, Q3, false);
+            // alarm is now canceled
+
+            // this should timeout...
+            listener.wake.WaitUntilEqAndSet(true, Q3, false);
         }
     }
 
-    class MyAlarmListener: AlarmListener
+    class MyAlarmListener : AlarmListener
     {
-        public MyAlarmListener( int delay )
+        public MyAlarmListener(int delay)
         {
             this.delay = delay;
         }
 
         public int delay;
 
-        public bool wake;
+        public bool excp;
+
+        public Monitor<bool> wake = new Monitor<bool>("wake", false);
 
         public object state;
 
+        public long due;
+
         public int Wakeup(AlarmManager manager, object state, long due)
         {
-            wake = true;
+            //TestAlarmManager.Log("Wakeup");
             this.state = state;
+            this.due = due;
+            wake.Set(true);
+
+            if (excp)
+                throw new Exception();
+
             return delay;
         }
     }