-#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 {
public bool IsSet {
get {
- return count <= 0;
+ return count == 0;
}
}
public WaitHandle WaitHandle {
get {
- return null;
+ return evt.WaitHandle;
}
}
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