Imported Upstream version 4.3.2.467

Former-commit-id: 9c2cb47f45fa221e661ab616387c9cda183f283d
This commit is contained in:
Xamarin Public Jenkins
2016-02-22 11:00:01 -05:00
parent f302175246
commit f3e3aab35a
4097 changed files with 122406 additions and 82300 deletions

View File

@@ -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)