You've already forked linux-packaging-mono
Imported Upstream version 4.3.2.467
Former-commit-id: 9c2cb47f45fa221e661ab616387c9cda183f283d
This commit is contained in:
@@ -71,7 +71,7 @@ namespace System.Threading
|
||||
/// actually run the callbacks.
|
||||
private volatile int m_threadIDExecutingCallbacks = -1;
|
||||
|
||||
private int m_disposed;
|
||||
private bool m_disposed;
|
||||
|
||||
private CancellationTokenRegistration [] m_linkingRegistrations; //lazily initialized if required.
|
||||
|
||||
@@ -115,9 +115,6 @@ namespace System.Threading
|
||||
/// </remarks>
|
||||
public bool IsCancellationRequested
|
||||
{
|
||||
#if !FEATURE_CORECLR
|
||||
[TargetedPatchingOptOut("Performance critical to inline across NGen image boundaries")]
|
||||
#endif
|
||||
get { return m_state >= NOTIFYING; }
|
||||
}
|
||||
|
||||
@@ -134,7 +131,7 @@ namespace System.Threading
|
||||
/// </summary>
|
||||
internal bool IsDisposed
|
||||
{
|
||||
get { return m_disposed == 1; }
|
||||
get { return m_disposed; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -156,9 +153,6 @@ namespace System.Threading
|
||||
/// disposed.</exception>
|
||||
public CancellationToken Token
|
||||
{
|
||||
#if !FEATURE_CORECLR
|
||||
[TargetedPatchingOptOut("Performance critical to inline across NGen image boundaries")]
|
||||
#endif
|
||||
get
|
||||
{
|
||||
ThrowIfDisposed();
|
||||
@@ -174,9 +168,6 @@ namespace System.Threading
|
||||
/// </summary>
|
||||
internal bool CanBeCanceled
|
||||
{
|
||||
#if !FEATURE_CORECLR
|
||||
[TargetedPatchingOptOut("Performance critical to inline across NGen image boundaries")]
|
||||
#endif
|
||||
get { return m_state != CANNOT_BE_CANCELED; }
|
||||
}
|
||||
|
||||
@@ -260,9 +251,6 @@ namespace System.Threading
|
||||
/// <summary>
|
||||
/// Initializes the <see cref="T:System.Threading.CancellationTokenSource"/>.
|
||||
/// </summary>
|
||||
#if !FEATURE_CORECLR
|
||||
[TargetedPatchingOptOut("Performance critical to inline across NGen image boundaries")]
|
||||
#endif
|
||||
public CancellationTokenSource()
|
||||
{
|
||||
m_state = NOT_CANCELED;
|
||||
@@ -572,8 +560,17 @@ namespace System.Threading
|
||||
// This is safe without locks because the reg.Dispose() only
|
||||
// mutates a sparseArrayFragment and then reads from properties of the CTS that are not
|
||||
// invalidated by cts.Dispose().
|
||||
//
|
||||
// We also tolerate that a callback can be registered after the CTS has been
|
||||
// disposed. This is safe without locks because InternalRegister is tolerant
|
||||
// of m_registeredCallbacksLists becoming null during its execution. However,
|
||||
// we run the acceptable risk of m_registeredCallbacksLists getting reinitialized
|
||||
// to non-null if there is a ---- between Dispose and Register, in which case this
|
||||
// instance may unnecessarily hold onto a registered callback. But that's no worse
|
||||
// than if Dispose wasn't safe to use concurrently, as Dispose would never be called,
|
||||
// and thus no handlers would be dropped.
|
||||
|
||||
if (m_disposed != 0 || Interlocked.CompareExchange (ref m_disposed, 1, 0) != 0)
|
||||
if (m_disposed)
|
||||
return;
|
||||
|
||||
if (m_timer != null) m_timer.Dispose();
|
||||
@@ -593,11 +590,35 @@ namespace System.Threading
|
||||
|
||||
m_registeredCallbacksLists = null; // free for GC.
|
||||
|
||||
#if MONO
|
||||
//
|
||||
// .NET version has a race on m_kernelEvent which it's not easy to
|
||||
// trigger on .net probably due to much faster Close implementation
|
||||
// but on Mono this can happen quite easily.
|
||||
//
|
||||
// First race was between Dispose and NotifyCancellation where m_kernelEvent
|
||||
// can be nulled/Closed and Set at same time.
|
||||
//
|
||||
// Second race was between concurrent Dispose calls.
|
||||
//
|
||||
// Third race is between Dispose and WaitHandle propery but that should
|
||||
// be handled by user.
|
||||
//
|
||||
var ke = m_kernelEvent;
|
||||
if (ke != null)
|
||||
{
|
||||
m_kernelEvent = null;
|
||||
ke.Close();
|
||||
}
|
||||
#else
|
||||
if (m_kernelEvent != null)
|
||||
{
|
||||
m_kernelEvent.Close(); // the critical cleanup to release an OS handle
|
||||
m_kernelEvent = null; // free for GC.
|
||||
}
|
||||
#endif
|
||||
|
||||
m_disposed = true;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -606,12 +627,9 @@ namespace System.Threading
|
||||
/// <summary>
|
||||
/// Throws an exception if the source has been disposed.
|
||||
/// </summary>
|
||||
#if !FEATURE_CORECLR
|
||||
[TargetedPatchingOptOut("Performance critical to inline across NGen image boundaries")]
|
||||
#endif
|
||||
internal void ThrowIfDisposed()
|
||||
{
|
||||
if (m_disposed == 1)
|
||||
if (m_disposed)
|
||||
ThrowObjectDisposedException();
|
||||
}
|
||||
|
||||
@@ -638,7 +656,10 @@ namespace System.Threading
|
||||
internal CancellationTokenRegistration InternalRegister(
|
||||
Action<object> callback, object stateForCallback, SynchronizationContext targetSyncContext, ExecutionContext executionContext)
|
||||
{
|
||||
ThrowIfDisposed();
|
||||
if (AppContextSwitches.ThrowExceptionIfDisposedCancellationTokenSource)
|
||||
{
|
||||
ThrowIfDisposed();
|
||||
}
|
||||
|
||||
// the CancellationToken has already checked that the token is cancelable before calling this method.
|
||||
Contract.Assert(CanBeCanceled, "Cannot register for uncancelable token src");
|
||||
@@ -650,6 +671,20 @@ namespace System.Threading
|
||||
|
||||
if (!IsCancellationRequested)
|
||||
{
|
||||
// In order to enable code to not leak too many handlers, we allow Dispose to be called concurrently
|
||||
// with Register. While this is not a recommended practice, consumers can and do use it this way.
|
||||
// We don't make any guarantees about whether the CTS will hold onto the supplied callback
|
||||
// if the CTS has already been disposed when the callback is registered, but we try not to
|
||||
// while at the same time not paying any non-negligible overhead. The simple compromise
|
||||
// is to check whether we're disposed (not volatile), and if we see we are, to return an empty
|
||||
// registration, just as if CanBeCanceled was false for the check made in CancellationToken.Register.
|
||||
// If there's a ---- and m_disposed is false even though it's been disposed, or if the disposal request
|
||||
// comes in after this line, we simply run the minor risk of having m_registeredCallbacksLists reinitialized
|
||||
// (after it was cleared to null during Dispose).
|
||||
|
||||
if (m_disposed && !AppContextSwitches.ThrowExceptionIfDisposedCancellationTokenSource)
|
||||
return new CancellationTokenRegistration();
|
||||
|
||||
int myIndex = Thread.CurrentThread.ManagedThreadId % s_nLists;
|
||||
|
||||
CancellationCallbackInfo callbackInfo = new CancellationCallbackInfo(callback, stateForCallback, targetSyncContext, executionContext, this);
|
||||
@@ -717,8 +752,23 @@ namespace System.Threading
|
||||
ThreadIDExecutingCallbacks = Thread.CurrentThread.ManagedThreadId;
|
||||
|
||||
//If the kernel event is null at this point, it will be set during lazy construction.
|
||||
#if MONO
|
||||
var ke = m_kernelEvent;
|
||||
if (ke != null) {
|
||||
try {
|
||||
ke.Set(); // update the MRE value.
|
||||
} catch (ObjectDisposedException) {
|
||||
//
|
||||
// Rethrow only when we are not in race with Dispose
|
||||
//
|
||||
if (m_kernelEvent != null)
|
||||
throw;
|
||||
}
|
||||
}
|
||||
#else
|
||||
if (m_kernelEvent != null)
|
||||
m_kernelEvent.Set(); // update the MRE value.
|
||||
#endif
|
||||
|
||||
// - late enlisters to the Canceled event will have their callbacks called immediately in the Register() methods.
|
||||
// - Callbacks are not called inside a lock.
|
||||
@@ -858,9 +908,6 @@ namespace System.Threading
|
||||
/// <param name="token2">The second <see cref="T:System.Threading.CancellationToken">CancellationToken</see> to observe.</param>
|
||||
/// <returns>A <see cref="T:System.Threading.CancellationTokenSource">CancellationTokenSource</see> that is linked
|
||||
/// to the source tokens.</returns>
|
||||
/// <exception cref="T:System.ObjectDisposedException">A <see
|
||||
/// cref="T:System.Threading.CancellationTokenSource">CancellationTokenSource</see> associated with
|
||||
/// one of the source tokens has been disposed.</exception>
|
||||
public static CancellationTokenSource CreateLinkedTokenSource(CancellationToken token1, CancellationToken token2)
|
||||
{
|
||||
CancellationTokenSource linkedTokenSource = new CancellationTokenSource();
|
||||
@@ -895,9 +942,6 @@ namespace System.Threading
|
||||
/// <returns>A <see cref="T:System.Threading.CancellationTokenSource">CancellationTokenSource</see> that is linked
|
||||
/// to the source tokens.</returns>
|
||||
/// <exception cref="T:System.ArgumentNullException"><paramref name="tokens"/> is null.</exception>
|
||||
/// <exception cref="T:System.ObjectDisposedException">A <see
|
||||
/// cref="T:System.Threading.CancellationTokenSource">CancellationTokenSource</see> associated with
|
||||
/// one of the source tokens has been disposed.</exception>
|
||||
public static CancellationTokenSource CreateLinkedTokenSource(params CancellationToken[] tokens)
|
||||
{
|
||||
if (tokens == null)
|
||||
|
||||
Reference in New Issue
Block a user