Revert stalling changes introduced in SpinWait. Add a guard for ntime overflow.
[mono.git] / mcs / class / corlib / System.Threading / Timer.cs
index ca5f444cd00f85f661bfd59eb305cfc9472e22ec..d0f9a6562354699d9bea9fdf3ab996f06612a008 100644 (file)
@@ -33,9 +33,7 @@ using System.Collections;
 
 namespace System.Threading
 {
-#if NET_2_0
        [ComVisible (true)]
-#endif
        public sealed class Timer : MarshalByRefObject, IDisposable
        {
                static Scheduler scheduler = Scheduler.Instance;
@@ -49,43 +47,32 @@ namespace System.Threading
 #endregion
                public Timer (TimerCallback callback, object state, int dueTime, int period)
                {
-                       if (dueTime < -1)
-                               throw new ArgumentOutOfRangeException ("dueTime");
-
-                       if (period < -1)
-                               throw new ArgumentOutOfRangeException ("period");
-
                        Init (callback, state, dueTime, period);
                }
 
                public Timer (TimerCallback callback, object state, long dueTime, long period)
                {
-                       if (dueTime < -1)
-                               throw new ArgumentOutOfRangeException ("dueTime");
-
-                       if (period < -1)
-                               throw new ArgumentOutOfRangeException ("period");
-
                        Init (callback, state, dueTime, period);
                }
 
                public Timer (TimerCallback callback, object state, TimeSpan dueTime, TimeSpan period)
-                       : this (callback, state, (long)dueTime.TotalMilliseconds, (long)period.TotalMilliseconds)
                {
+                       Init (callback, state, (long)dueTime.TotalMilliseconds, (long)period.TotalMilliseconds);
                }
 
                [CLSCompliant(false)]
                public Timer (TimerCallback callback, object state, uint dueTime, uint period)
-                       : this (callback, state, (long) dueTime, (long) period)
                {
+                       // convert all values to long - with a special case for -1 / 0xffffffff
+                       long d = (dueTime == UInt32.MaxValue) ? Timeout.Infinite : (long) dueTime;
+                       long p = (period == UInt32.MaxValue) ? Timeout.Infinite : (long) period;
+                       Init (callback, state, d, p);
                }
 
-#if NET_2_0
                public Timer (TimerCallback callback)
                {
                        Init (callback, this, Timeout.Infinite, Timeout.Infinite);
                }
-#endif
 
                void Init (TimerCallback callback, object state, long dueTime, long period)
                {
@@ -100,24 +87,21 @@ namespace System.Threading
 
                public bool Change (int dueTime, int period)
                {
-                       return Change ((long)dueTime, (long)period);
+                       return Change (dueTime, period, false);
                }
 
                public bool Change (TimeSpan dueTime, TimeSpan period)
                {
-                       return Change ((long)dueTime.TotalMilliseconds, (long)period.TotalMilliseconds);
+                       return Change ((long)dueTime.TotalMilliseconds, (long)period.TotalMilliseconds, false);
                }
 
                [CLSCompliant(false)]
                public bool Change (uint dueTime, uint period)
                {
-                       if (dueTime > Int32.MaxValue)
-                               throw new NotSupportedException ("Due time too large");
-
-                       if (period > Int32.MaxValue)
-                               throw new NotSupportedException ("Period too large");
-
-                       return Change ((long) dueTime, (long) period);
+                       // convert all values to long - with a special case for -1 / 0xffffffff
+                       long d = (dueTime == UInt32.MaxValue) ? Timeout.Infinite : (long) dueTime;
+                       long p = (period == UInt32.MaxValue) ? Timeout.Infinite : (long) period;
+                       return Change (d, p, false);
                }
 
                public void Dispose ()
@@ -134,18 +118,21 @@ namespace System.Threading
                        return Change (dueTime, period, false);
                }
 
+               const long MaxValue = UInt32.MaxValue - 1;
+
                bool Change (long dueTime, long period, bool first)
                {
-                       if(dueTime > 4294967294)
-                               throw new NotSupportedException ("Due time too large");
+                       if (dueTime > MaxValue)
+                               throw new ArgumentOutOfRangeException ("Due time too large");
 
-                       if(period > 4294967294)
-                               throw new NotSupportedException ("Period too large");
+                       if (period > MaxValue)
+                               throw new ArgumentOutOfRangeException ("Period too large");
 
-                       if (dueTime < -1)
+                       // Timeout.Infinite == -1, so this accept everything greater than -1
+                       if (dueTime < Timeout.Infinite)
                                throw new ArgumentOutOfRangeException ("dueTime");
 
-                       if (period < -1)
+                       if (period < Timeout.Infinite)
                                throw new ArgumentOutOfRangeException ("period");
 
                        if (disposed)
@@ -156,7 +143,7 @@ namespace System.Threading
                        long nr;
                        if (dueTime == 0) {
                                nr = 0; // Due now
-                       } else if (dueTime == Timeout.Infinite) {
+                       } else if (dueTime < 0) { // Infinite == -1
                                nr = long.MaxValue;
                                /* No need to call Change () */
                                if (first) {
@@ -173,27 +160,30 @@ namespace System.Threading
 
                public bool Dispose (WaitHandle notifyObject)
                {
+                       if (notifyObject == null)
+                               throw new ArgumentNullException ("notifyObject");
                        Dispose ();
                        NativeEventCalls.SetEvent_internal (notifyObject.Handle);
                        return true;
                }
 
-               class TimerComparer : IComparer {
+               sealed class TimerComparer : IComparer {
                        public int Compare (object x, object y)
                        {
-                               if (!(x is Timer))
+                               Timer tx = (x as Timer);
+                               if (tx == null)
                                        return -1;
-                               if (!(y is Timer))
+                               Timer ty = (y as Timer);
+                               if (ty == null)
                                        return 1;
-                               long nr1 = ((Timer) x).next_run;
-                               long nr2 = ((Timer) y).next_run;
-                               long result = nr1 - nr2;
-                               return result > 0 ? 1 : result < 0 ? -1 : 0;
+                               long result = tx.next_run - ty.next_run;
+                               if (result == 0)
+                                       return x == y ? 0 : -1;
+                               return result > 0 ? 1 : -1;
                        }
-
                }
 
-               class Scheduler {
+               sealed class Scheduler {
                        static Scheduler instance;
                        SortedList list;
 
@@ -230,9 +220,11 @@ namespace System.Threading
                        public void Change (Timer timer, long new_next_run)
                        {
                                lock (this) {
-                                       // Don't try to remove items that are not initialized or not in the list
-                                       if (timer.next_run != 0 && timer.next_run != Int64.MaxValue)
-                                               InternalRemove (timer);
+                                       InternalRemove (timer);
+                                       if (new_next_run == Int64.MaxValue) {
+                                               timer.next_run = new_next_run;
+                                               return;
+                                       }
 
                                        if (!timer.disposed) {
                                                // We should only change next_run after removing and before adding
@@ -251,9 +243,14 @@ namespace System.Threading
                                // Make sure there are no collisions (10000 ticks == 1ms, so we should be safe here)
                                int idx = list.IndexOfKey (timer);
                                if (idx != -1) {
+                                       bool up = (Int64.MaxValue - timer.next_run) > 20000 ? true : false;
                                        while (true) {
                                                idx++;
-                                               timer.next_run++;
+                                               if (up)
+                                                       timer.next_run++;
+                                               else
+                                                       timer.next_run--;
+
                                                if (idx >= list.Count)
                                                        break;
                                                Timer t2 = (Timer) list.GetByIndex (idx);
@@ -299,12 +296,7 @@ namespace System.Threading
                                                                timer.next_run = Int64.MaxValue;
                                                        } else {
                                                                timer.next_run = DateTime.GetTimeMonotonic () + TimeSpan.TicksPerMillisecond * timer.period_ms;
-                                                               if (timer.next_run > ticks) {
-                                                                       Add (timer); // Safe to add here
-                                                                       count++;
-                                                               } else {
-                                                                       new_time.Add (timer); // Not safe, add it once we're done
-                                                               }
+                                                               new_time.Add (timer);
                                                        }
                                                }
 
@@ -330,7 +322,7 @@ namespace System.Threading
                                                //PrintList ();
                                                int ms_wait = -1;
                                                if (min_next_run != Int64.MaxValue) {
-                                                       long diff = min_next_run - ticks
+                                                       long diff = min_next_run - DateTime.GetTimeMonotonic ()
                                                        ms_wait = (int)(diff / TimeSpan.TicksPerMillisecond);
                                                        if (ms_wait < 0)
                                                                ms_wait = 0;