Simplify Parallel.For execution.
[mono.git] / mcs / class / corlib / System.Threading / CountdownEvent.cs
index fc86772451765f31f2858edad44f259e2c79d59c..eaeb3ac6e14e8a087bbadfc7f4ba70609cc53599 100644 (file)
@@ -1,4 +1,3 @@
-#if NET_4_0
 // CountdownEvent.cs
 //
 // Copyright (c) 2008 Jérémie "Garuma" Laval
 //
 //
 
+#if NET_4_0 || BOOTSTRAP_NET_4_0
+
 using System;
-using System.Diagnostics;
 
 namespace System.Threading
 {      
-       public class CountdownEvent: ISupportsCancellation, IDisposable
+       public class CountdownEvent : IDisposable
        {
                int count;
                readonly int initial;
-               bool isCanceled;
+               ManualResetEventSlim evt = new ManualResetEventSlim (false);
                
-               public CountdownEvent(int count)
+               public CountdownEvent (int count)
                {
                        if (count < 0)
-                               throw new ArgumentOutOfRangeException("count is negative");
+                               throw new ArgumentOutOfRangeException ("count is negative");
                        this.initial = this.count = count;
                }
                
-               /*~CountdownEvent()
+               public bool Signal ()
                {
-                       Dispose(false);
-               }*/
+                       return Signal (1);
+               }
                
-               public void Decrement()
+               public bool Signal (int num)
                {
-                       Decrement(1);
+                       if (num <= 0)
+                               throw new ArgumentOutOfRangeException ("num");
+                       
+                       Action<int> check = delegate (int value) {
+                               if (value < 0)
+                               throw new InvalidOperationException ("the specified count is larger that CurrentCount");
+                       };
+                       
+                       int newValue;
+                       if (!ApplyOperation (-num, check, out newValue))
+                               throw new InvalidOperationException ("The event is already set");
+                       
+                       if (newValue == 0) {
+                               evt.Set ();
+                               return true;
+                       }
+                       
+                       return false;
                }
                
-               public void Decrement(int num)
+               public void AddCount ()
                {
-                       if (num < 0)
-                               throw new ArgumentOutOfRangeException("num");
-                       if (IsSet || num > count)
-                               throw new InvalidOperationException();
-                       Interlocked.Add(ref count, -num);
+                       AddCount (1);
                }
                
-               public void Increment()
+               public void AddCount (int num)
                {
-                       Increment(1);
+                       if (num < 0)
+                               throw new ArgumentOutOfRangeException ("num");
+                       
+                       if (!TryAddCount (num))
+                               throw new InvalidOperationException ("The event is already set");
                }
                
-               public void Increment(int num)
+               public bool TryAddCount ()
                {
+                       return TryAddCount (1);
+               }
+               
+               public bool TryAddCount (int num)
+               {       
                        if (num < 0)
-                               throw new ArgumentOutOfRangeException("num");
-                       if (IsSet || num > int.MaxValue - count)
-                               throw new InvalidOperationException();
-                       Interlocked.Add(ref count, num);
+                               throw new ArgumentOutOfRangeException ("num");
+                       
+                       return ApplyOperation (num, null);
                }
                
-               public bool TryIncrement()
+               bool ApplyOperation (int num, Action<int> doCheck)
                {
-                       return TryIncrement(1);
+                       int temp;
+                       return ApplyOperation (num, doCheck, out temp);
                }
-               
-               public bool TryIncrement(int num)
+                       
+               bool ApplyOperation (int num, Action<int> doCheck, out int newValue)
                {
-                       if (IsSet)
-                               return false;
-                       if (num < 0)
-                               throw new ArgumentOutOfRangeException("num");
-                       if (num > int.MaxValue - count)
-                               throw new InvalidOperationException();
+                       int oldCount;
+                       newValue = 0;
                        
-                       if (IsSet)
-                               return false;
+                       do {
+                               oldCount = count;
+                               if (oldCount == 0)
+                                       return false;
+                               
+                               newValue = oldCount + num;
+                               
+                               if (doCheck != null)
+                                       doCheck (newValue);
+                       } while (Interlocked.CompareExchange (ref count, newValue, oldCount) != oldCount);
                        
-                       Interlocked.Add(ref count, num);
                        return true;
                }
                
-               public void Wait()
+               public void Wait ()
                {
-                       SpinWait wait = new SpinWait();
-                       while (!IsSet) {
-                               wait.SpinOnce();
-                       }
+                       evt.Wait ();
                }
                
-               public bool Wait(int timeoutMilli)
+               public void Wait (CancellationToken token)
                {
-                       if (timeoutMilli == -1) {
-                               Wait();
-                               return true;
-                       }
-                       
-                       SpinWait wait = new SpinWait();
-                       Stopwatch sw = Stopwatch.StartNew();
-                       
-                       while (!IsSet) {
-                               if (sw.ElapsedMilliseconds > (long)timeoutMilli) {
-                                       sw.Stop();
-                                       return false;
-                               }
-                               wait.SpinOnce();
-                       }
-                       return true;
+                       evt.Wait (token);
+               }
+               
+               public bool Wait (int timeoutMilli)
+               {
+                       return evt.Wait (timeoutMilli);
                }
                
                public bool Wait(TimeSpan span)
                {
-                       return Wait((int)span.TotalMilliseconds);
+                       return evt.Wait (span);
                }
                
-               public void Reset()
+               public bool Wait (int timeoutMilli, CancellationToken token)
+               {
+                       return evt.Wait (timeoutMilli, token);
+               }
+               
+               public bool Wait(TimeSpan span, CancellationToken token)
+               {
+                       return evt.Wait (span, token);
+               }
+
+               public void Reset ()
                {
-                       Reset(initial);
+                       Reset (initial);
                }
                
-               public void Reset(int value)
+               public void Reset (int value)
                {
-                       Thread.VolatileWrite(ref count, value);
+                       evt.Reset ();
+                       Interlocked.Exchange (ref count, value);
                }
                
                public int CurrentCount {
@@ -152,13 +175,13 @@ namespace System.Threading
                        
                public bool IsSet {
                        get {
-                               return count <= 0;
+                               return count == 0;
                        }
                }
                
                public WaitHandle WaitHandle {
                        get {
-                               return null;
+                               return evt.WaitHandle;
                        }
                }
 
@@ -166,32 +189,14 @@ namespace System.Threading
                
                public void Dispose ()
                {
-                       //Dispose(true);
+                       
                }
                
-               /*protected virtual void Dispose(bool managedRes)
+               protected virtual void Dispose (bool managedRes)
                {
                        
-               }*/
-               #endregion 
-               
-               
-               #region ISupportsCancellation implementation 
-               
-               public void Cancel()
-               {
-                       Thread.VolatileWrite(ref count, 0);
-                       isCanceled = true;
                }
-               
-               public bool IsCanceled {
-                       get {
-                               return isCanceled;
-                       }
-               }
-               
-               #endregion 
-               
+               #endregion      
        }
 }
 #endif