Author: lupus
Date: 2007-10-16 06:00:19 -0400 (Tue, 16 Oct 2007)
New Revision: 87565

Modified:
   trunk/mcs/class/corlib/System.Threading/ChangeLog
   trunk/mcs/class/corlib/System.Threading/Timer.cs
Log:


Tue Oct 16 12:14:43 CEST 2007 Paolo Molaro <[EMAIL PROTECTED]>

        * Timer.cs: rewrote to use threadpool threads to invoke the callbacks,
        avoid Thread.Abort and Thread.Interrupt and use a single scheduler
        thread, partially from the patch of Rafael Ferreira in bug #315999.
        Fixes bug #315999, #332206.



Modified: trunk/mcs/class/corlib/System.Threading/ChangeLog
===================================================================
--- trunk/mcs/class/corlib/System.Threading/ChangeLog   2007-10-16 09:42:56 UTC 
(rev 87564)
+++ trunk/mcs/class/corlib/System.Threading/ChangeLog   2007-10-16 10:00:19 UTC 
(rev 87565)
@@ -1,3 +1,11 @@
+
+Tue Oct 16 12:14:43 CEST 2007 Paolo Molaro <[EMAIL PROTECTED]>
+
+       * Timer.cs: rewrote to use threadpool threads to invoke the callbacks,
+       avoid Thread.Abort and Thread.Interrupt and use a single scheduler
+       thread, partially from the patch of Rafael Ferreira in bug #315999.
+       Fixes bug #315999, #332206.
+
 2007-10-15  Dick Porter  <[EMAIL PROTECTED]>
 
        * Thread.cs: Initialise synch_cs to null now we aren't using it as

Modified: trunk/mcs/class/corlib/System.Threading/Timer.cs
===================================================================
--- trunk/mcs/class/corlib/System.Threading/Timer.cs    2007-10-16 09:42:56 UTC 
(rev 87564)
+++ trunk/mcs/class/corlib/System.Threading/Timer.cs    2007-10-16 10:00:19 UTC 
(rev 87565)
@@ -29,6 +29,7 @@
 //
 
 using System.Runtime.InteropServices;
+using System.Collections;
 
 namespace System.Threading
 {
@@ -37,125 +38,66 @@
 #endif
        public sealed class Timer : MarshalByRefObject, IDisposable
        {
-               sealed class Runner : MarshalByRefObject
-               {
-                       ManualResetEvent wait;
-                       AutoResetEvent start_event;
-                       TimerCallback callback;
-                       object state;
-                       int dueTime;
-                       int period;
-                       bool disposed;
-                       bool aborted;
+#region Timer instance fields
+               TimerCallback callback;
+               object state;
+               long due_time_ms;
+               long period_ms;
+               long next_run; // in ticks
+               bool disposed;
+#endregion
 
-                       public Runner (TimerCallback callback, object state, 
AutoResetEvent start_event)
-                       {
-                               this.callback = callback;
-                               this.state = state;
-                               this.start_event = start_event;
-                               this.wait = new ManualResetEvent (false);
-                       }
+#region Timer static fields
+               static Thread scheduler;
+               static Hashtable jobs;
+               static AutoResetEvent change_event;
+#endregion
 
-                       public int DueTime {
-                               get { return dueTime; }
-                               set { dueTime = value; }
-                       }
+               /* we use a static initializer to avoid race issues with the 
thread creation */
+               static Timer ()
+               {
+                       change_event = new AutoResetEvent (false);
+                       jobs = new Hashtable ();
+                       scheduler = new Thread (SchedulerThread);
+                       scheduler.IsBackground = true;
+                       scheduler.Start ();
+               }
 
-                       public int Period {
-                               get { return period; }
-                               set { period = value == 0 ? Timeout.Infinite : 
value; }
-                       }
+               static long Ticks ()
+               {
+                       /* use a monotonic time value later */
+                       return DateTime.UtcNow.Ticks;
+               }
 
-                       bool WaitForDueTime ()
-                       {
-                               if (dueTime > 0) {
-                                       bool signaled;
-                                       do {
-                                               wait.Reset ();
-                                               signaled = wait.WaitOne 
(dueTime, false);
-                                       } while (signaled == true && !disposed 
&& !aborted);
-
-                                       if (!signaled)
-                                               callback (state);
-
-                                       if (disposed)
-                                               return false;
-                               }
-                               else
-                                       callback (state);
-
-                               return true;
-                       }
-
-                       public void Abort ()
-                       {
-                               lock (this) {
-                                       aborted = true;
-                                       wait.Set ();
-                               }
-                       }
-                       
-                       public void Dispose ()
-                       {
-                               lock (this) {
-                                       disposed = true;
-                                       Abort ();
-                               }
-                       }
-
-                       public void Start ()
-                       {
-                               while (!disposed && start_event.WaitOne ()) {
-                                       if (disposed)
-                                               return;
-
-                                       aborted = false;
-
-                                       if (dueTime == Timeout.Infinite)
-                                               continue;
-
-                                       if (!WaitForDueTime ())
-                                               return;
-
-                                       if (aborted || (period == 
Timeout.Infinite))
-                                               continue;
-
-                                       bool signaled = false;
-                                       while (true) {
-                                               if (disposed)
-                                                       return;
-
-                                               if (aborted)
-                                                       break;
-
-                                               try {
-                                                       wait.Reset ();
-                                               } catch 
(ObjectDisposedException) {
-                                                       // FIXME: There is some 
race condition
-                                                       //        here when the 
thread is being
-                                                       //        aborted on 
exit.
-                                                       return;
+               static private void SchedulerThread ()
+               {
+                       Thread.CurrentThread.Name = "Timer-Scheduler";
+                       while (true) {
+                               long min_wait = long.MaxValue;
+                               lock (jobs) {
+                                       long ticks = Ticks ();
+                                       foreach (DictionaryEntry entry in jobs) 
{
+                                               Timer t1 = entry.Value as Timer;
+                                               if (t1.next_run <= ticks) {
+                                                       
ThreadPool.QueueUserWorkItem (new WaitCallback (t1.callback), t1.state);
+                                                       if (t1.period_ms == -1)
+                                                               t1.next_run = 
long.MaxValue;
+                                                       else
+                                                               t1.next_run = 
ticks + TimeSpan.TicksPerMillisecond * t1.period_ms;
                                                }
-
-                                               signaled = wait.WaitOne 
(period, false);
-
-                                               if (aborted || disposed)
-                                                       break;
-
-                                               if (!signaled) {
-                                                       callback (state);
-                                               } else if (!WaitForDueTime ()) {
-                                                       return;
+                                               if (t1.next_run != 
long.MaxValue) {
+                                                       min_wait = Math.Min 
(min_wait, t1.next_run - ticks);
                                                }
                                        }
                                }
+                               if (min_wait != long.MaxValue) {
+                                       change_event.WaitOne ((int)(min_wait / 
TimeSpan.TicksPerMillisecond), true);
+                               } else {
+                                       change_event.WaitOne (Timeout.Infinite, 
true);
+                               }
                        }
                }
 
-               Runner runner;
-               AutoResetEvent start_event;
-               WeakReference weak_t;
-
                public Timer (TimerCallback callback, object state, int 
dueTime, int period)
                {
                        if (dueTime < -1)
@@ -175,11 +117,11 @@
                        if (period < -1)
                                throw new ArgumentOutOfRangeException 
("period");
 
-                       Init (callback, state, (int) dueTime, (int) period);
+                       Init (callback, state, dueTime, period);
                }
 
                public Timer (TimerCallback callback, object state, TimeSpan 
dueTime, TimeSpan period)
-                       : this (callback, state, 
Convert.ToInt32(dueTime.TotalMilliseconds), 
Convert.ToInt32(period.TotalMilliseconds))
+                       : this (callback, state, 
(long)dueTime.TotalMilliseconds, (long)period.TotalMilliseconds)
                {
                }
 
@@ -196,36 +138,17 @@
                }
 #endif
 
-               void Init (TimerCallback callback, object state, int dueTime, 
int period)
+               void Init (TimerCallback callback, object state, long dueTime, 
long period)
                {
-                       start_event = new AutoResetEvent (false);
-                       runner = new Runner (callback, state, start_event);
-                       Change (dueTime, period);
-                       Thread t = new Thread (new ThreadStart (runner.Start));
+                       this.callback = callback;
+                       this.state = state;
 
-                       weak_t = new WeakReference (t);
-                       
-                       t.IsBackground = true;
-                       t.Start ();
+                       Change (dueTime, period);
                }
 
                public bool Change (int dueTime, int period)
                {
-                       if (dueTime < -1)
-                               throw new ArgumentOutOfRangeException 
("dueTime");
-
-                       if (period < -1)
-                               throw new ArgumentOutOfRangeException 
("period");
-
-                       if (runner == null)
-                               return false;
-
-                       start_event.Reset ();
-                       runner.Abort ();
-                       runner.DueTime = dueTime;
-                       runner.Period = period;
-                       start_event.Set ();
-                       return true;
+                       return Change ((long)dueTime, (long)period);
                }
 
                public bool Change (long dueTime, long period)
@@ -236,12 +159,40 @@
                        if(period > 4294967294)
                                throw new NotSupportedException ("Period too 
large");
 
-                       return Change ((int) dueTime, (int) period);
+                       if (dueTime < -1)
+                               throw new ArgumentOutOfRangeException 
("dueTime");
+
+                       if (period < -1)
+                               throw new ArgumentOutOfRangeException 
("period");
+
+                       if (disposed)
+                               return false;
+
+                       due_time_ms = dueTime;
+                       period_ms = period;
+                       if (dueTime == 0) {
+                               next_run = Ticks ();
+                       } else if (dueTime == Timeout.Infinite) {
+                               next_run = long.MaxValue;
+                       } else {
+                               next_run = dueTime * 
TimeSpan.TicksPerMillisecond + Ticks ();
+                       }
+                       lock (jobs) {
+                               if (next_run != long.MaxValue) {
+                                       Timer t = jobs [this] as Timer;
+                                       if (t == null)
+                                               jobs [this] = this;
+                                       change_event.Set ();
+                               } else {
+                                       jobs.Remove (this);
+                               }
+                       }
+                       return true;
                }
 
                public bool Change (TimeSpan dueTime, TimeSpan period)
                {
-                       return Change 
(Convert.ToInt32(dueTime.TotalMilliseconds), 
Convert.ToInt32(period.TotalMilliseconds));
+                       return Change ((long)dueTime.TotalMilliseconds, 
(long)period.TotalMilliseconds);
                }
 
                [CLSCompliant(false)]
@@ -253,23 +204,15 @@
                        if (period > Int32.MaxValue)
                                throw new NotSupportedException ("Period too 
large");
 
-                       return Change ((int) dueTime, (int) period);
+                       return Change ((long) dueTime, (long) period);
                }
 
                public void Dispose ()
                {
-                       Thread t = (Thread)weak_t.Target;
-                               
-                       if (t != null && t.IsAlive) {
-                               if (t != Thread.CurrentThread)
-                                       t.Abort ();
+                       disposed = true;
+                       lock (jobs) {
+                               jobs.Remove (this);
                        }
-
-                       if (runner != null) {
-                               runner.Dispose ();
-                               runner = null;
-                       }
-                       GC.SuppressFinalize (this);
                }
 
                public bool Dispose (WaitHandle notifyObject)
@@ -279,16 +222,6 @@
                        return true;
                }
 
-               ~Timer ()
-               {
-                       Thread t = (Thread)weak_t.Target;
-                       
-                       if (t != null && t.IsAlive)
-                               t.Abort ();
-
-                       if (runner != null)
-                               runner.Abort ();
-               }
        }
 }
 

_______________________________________________
Mono-patches maillist  -  [email protected]
http://lists.ximian.com/mailman/listinfo/mono-patches

Reply via email to