#if NET_4_5
timer_callback = token => {
var cts = (CancellationTokenSource) token;
- cts.Cancel ();
+ cts.CancelSafe ();
};
#endif
}
public void Cancel (bool throwOnFirstException)
{
CheckDisposed ();
+ Cancellation (throwOnFirstException);
+ }
+
+ //
+ // Don't throw ObjectDisposedException if the callback
+ // is called concurrently with a Dispose
+ //
+ public void CancelSafe ()
+ {
+ if (!disposed)
+ Cancellation (true);
+ }
+ void Cancellation (bool throwOnFirstException)
+ {
if (canceled)
return;
Thread.MemoryBarrier ();
canceled = true;
-
- handle.Set ();
+
+ Thread.MemoryBarrier ();
+
+ // Dispose might be running at same time
+ if (!disposed)
+ handle.Set ();
+
if (linkedTokens != null)
UnregisterLinkedTokens ();
-
+
+ var cbs = callbacks;
+ if (cbs == null)
+ return;
+
List<Exception> exceptions = null;
-
+
try {
Action cb;
- for (int id = int.MinValue + 1; id <= currId; id++) {
- if (!callbacks.TryRemove (new CancellationTokenRegistration (id, this), out cb))
+ for (int id = currId; id != int.MinValue; id--) {
+ if (!cbs.TryRemove (new CancellationTokenRegistration (id, this), out cb))
continue;
if (cb == null)
continue;
}
}
} finally {
- callbacks.Clear ();
+ cbs.Clear ();
}
if (exceptions != null)
throw new AggregateException (exceptions);
}
- /* This is the callback registered on linked tokens
- * so that they don't throw an ODE if the callback
- * is called concurrently with a Dispose
- */
- void SafeLinkedCancel ()
- {
- try {
- Cancel ();
- } catch (ObjectDisposedException) {}
- }
-
#if NET_4_5
public void CancelAfter (TimeSpan delay)
{
throw new ArgumentException ("Empty tokens array");
CancellationTokenSource src = new CancellationTokenSource ();
- Action action = src.SafeLinkedCancel;
+ Action action = src.CancelSafe;
var registrations = new List<CancellationTokenRegistration> (tokens.Length);
foreach (CancellationToken token in tokens) {
void Dispose (bool disposing)
{
if (disposing && !disposed) {
- Thread.MemoryBarrier ();
disposed = true;
+ Thread.MemoryBarrier ();
if (!canceled) {
- Thread.MemoryBarrier ();
UnregisterLinkedTokens ();
callbacks = null;
+ } else {
+ handle.WaitOne ();
}
#if NET_4_5
if (timer != null)
timer.Dispose ();
#endif
+
handle.Dispose ();
}
}