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;
}
}