X-Git-Url: http://wien.tomnetworks.com/gitweb/?a=blobdiff_plain;f=mcs%2Fclass%2Fcorlib%2FSystem.Threading%2FCancellationTokenSource.cs;h=c5557f0446e69b7808e73a295b08c7c244d4e469;hb=424595ea7043f30b0553f2842654db13baeda3ca;hp=b82e49f59bfb751b810a4406af15003b593f7152;hpb=e946a6cdebde729e1c03ec374184254ab38da184;p=mono.git diff --git a/mcs/class/corlib/System.Threading/CancellationTokenSource.cs b/mcs/class/corlib/System.Threading/CancellationTokenSource.cs index b82e49f59bf..c5557f0446e 100644 --- a/mcs/class/corlib/System.Threading/CancellationTokenSource.cs +++ b/mcs/class/corlib/System.Threading/CancellationTokenSource.cs @@ -61,7 +61,7 @@ namespace System.Threading #if NET_4_5 timer_callback = token => { var cts = (CancellationTokenSource) token; - cts.Cancel (); + cts.CancelSafe (); }; #endif } @@ -118,23 +118,46 @@ namespace System.Threading 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 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; @@ -153,24 +176,13 @@ namespace System.Threading } } } 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) { @@ -212,7 +224,7 @@ namespace System.Threading throw new ArgumentException ("Empty tokens array"); CancellationTokenSource src = new CancellationTokenSource (); - Action action = src.SafeLinkedCancel; + Action action = src.CancelSafe; var registrations = new List (tokens.Length); foreach (CancellationToken token in tokens) { @@ -250,18 +262,20 @@ namespace System.Threading 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 (); } }