Code:
/ 4.0 / 4.0 / DEVDIV_TFS / Dev10 / Releases / RTMRel / ndp / clr / src / BCL / System / Threading / CancellationToken.cs / 1305376 / CancellationToken.cs
// ==++==
//
// Copyright (c) Microsoft Corporation. All rights reserved.
//
// ==--==
//
// [....]
////////////////////////////////////////////////////////////////////////////////
#pragma warning disable 0420 // turn off 'a reference to a volatile field will not be treated as volatile' during CAS.
using System;
using System.Diagnostics;
using System.Runtime.InteropServices;
using System.Security.Permissions;
using System.Diagnostics.Contracts;
namespace System.Threading
{
///
/// Propogates notification that operations should be canceled.
///
///
///
/// A may be created directly in an unchangeable canceled or non-canceled state
/// using the CancellationToken's constructors. However, to have a CancellationToken that can change
/// from a non-canceled to a canceled state,
/// CancellationTokenSource must be used.
/// CancellationTokenSource exposes the associated CancellationToken that may be canceled by the source through its
/// Token property.
///
///
/// Once canceled, a token may not transition to a non-canceled state, and a token whose
/// is false will never change to one that can be canceled.
///
///
/// All members of this struct are thread-safe and may be used concurrently from multiple threads.
///
///
[ComVisible(false)]
[HostProtection(SecurityAction.LinkDemand, Synchronization = true, ExternalThreading = true)]
[DebuggerDisplay("IsCancellationRequested = {IsCancellationRequested}")]
public struct CancellationToken
{
// The backing TokenSource.
// if null, it implicitly represents the same thing as new CancellationToken(false).
// When required, it will be instantiated to reflect this.
private CancellationTokenSource m_source;
//!! warning. If more fields are added, the assumptions in CreateLinkedToken may no longer be valid
/* Properties */
///
/// Returns an empty CancellationToken value.
///
///
/// The value returned by this property will be non-cancelable by default.
///
public static CancellationToken None
{
get
{
return new CancellationToken();
}
}
///
/// Gets whether cancellation has been requested for this token.
///
/// Whether cancellation has been requested for this token.
///
///
/// This property indicates whether cancellation has been requested for this token,
/// either through the token initially being construted in a canceled state, or through
/// calling Cancel
/// on the token's associated .
///
///
/// If this property is true, it only guarantees that cancellation has been requested.
/// It does not guarantee that every registered handler
/// has finished executing, nor that cancellation requests have finished propagating
/// to all registered handlers. Additional synchronization may be required,
/// particularly in situations where related objects are being canceled concurrently.
///
///
public bool IsCancellationRequested {
get
{
return m_source != null && m_source.IsCancellationRequested;
}
}
///
/// Gets whether this token is capable of being in the canceled state.
///
///
/// If CanBeCanceled returns false, it is guaranteed that the token will never transition
/// into a canceled state, meaning that will never
/// return true.
///
public bool CanBeCanceled
{
get
{
return m_source != null && m_source.CanBeCanceled;
}
}
///
/// Gets a that is signaled when the token is canceled.
///
/// Accessing this property causes a WaitHandle
/// to be instantiated. It is preferable to only use this property when necessary, and to then
/// dispose the associated instance at the earliest opportunity (disposing
/// the source will dispose of this allocated handle). The handle should not be closed or disposed directly.
///
/// The associated CancellationTokenSource has been disposed.
public WaitHandle WaitHandle
{
get
{
if (m_source == null)
{
InitializeDefaultSource();
}
return m_source.WaitHandle;
}
}
// public CancellationToken()
// this constructor is implicit for structs
// -> this should behaves exactly as for new CancellationToken(false)
///
/// Internal constructor only a CancellationTokenSource should create a CancellationToken
///
internal CancellationToken(CancellationTokenSource source)
{
m_source = source;
}
///
/// Initializes the CancellationToken .
///
///
/// The canceled state for the token.
///
///
/// Tokens created with this constructor will remain in the canceled state specified
/// by the parameter. If is false,
/// both and will be false.
/// If is true,
/// both and will be true.
///
public CancellationToken(bool canceled) :
this()
{
if(canceled)
m_source = CancellationTokenSource.InternalGetStaticSource(canceled);
}
/* Methods */
private static Action s_ActionToActionObjShunt = new Action(ActionToActionObjShunt);
private static void ActionToActionObjShunt(object obj)
{
Action action = obj as Action;
Contract.Assert(action != null, "Expected an Action here");
action();
}
///
/// Registers a delegate that will be called when this CancellationToken is canceled.
///
///
///
/// If this token is already in the canceled state, the
/// delegate will be run immediately and synchronously. Any exception the delegate generates will be
/// propogated out of this method call.
///
///
/// The current ExecutionContext , if one exists, will be captured
/// along with the delegate and will be used when executing it.
///
///
/// The delegate to be executed when the CancellationToken is canceled.
/// The instance that can
/// be used to deregister the callback.
/// is null.
/// The associated CancellationTokenSource has been disposed.
public CancellationTokenRegistration Register(Action callback)
{
if (callback == null)
throw new ArgumentNullException("callback");
return Register(
s_ActionToActionObjShunt,
callback,
false, // useSync=false
true // useExecutionContext=true
);
}
///
/// Registers a delegate that will be called when this
/// CancellationToken is canceled.
///
///
///
/// If this token is already in the canceled state, the
/// delegate will be run immediately and synchronously. Any exception the delegate generates will be
/// propogated out of this method call.
///
///
/// The current ExecutionContext , if one exists, will be captured
/// along with the delegate and will be used when executing it.
///
///
/// The delegate to be executed when the CancellationToken is canceled.
/// A Boolean value that indicates whether to capture
/// the current SynchronizationContext and use it
/// when invoking the .
/// The instance that can
/// be used to deregister the callback.
/// is null.
/// The associated CancellationTokenSource has been disposed.
public CancellationTokenRegistration Register(Action callback, bool useSynchronizationContext)
{
if (callback == null)
throw new ArgumentNullException("callback");
return Register(
s_ActionToActionObjShunt,
callback,
useSynchronizationContext,
true // useExecutionContext=true
);
}
///
/// Registers a delegate that will be called when this
/// CancellationToken is canceled.
///
///
///
/// If this token is already in the canceled state, the
/// delegate will be run immediately and synchronously. Any exception the delegate generates will be
/// propogated out of this method call.
///
///
/// The current ExecutionContext , if one exists, will be captured
/// along with the delegate and will be used when executing it.
///
///
/// The delegate to be executed when the CancellationToken is canceled.
/// The state to pass to the when the delegate is invoked. This may be null.
/// The instance that can
/// be used to deregister the callback.
/// is null.
/// The associated CancellationTokenSource has been disposed.
public CancellationTokenRegistration Register(Action callback, Object state)
{
if (callback == null)
throw new ArgumentNullException("callback");
return Register(
callback,
state,
false, // useSync=false
true // useExecutionContext=true
);
}
///
/// Registers a delegate that will be called when this
/// CancellationToken is canceled.
///
///
///
/// If this token is already in the canceled state, the
/// delegate will be run immediately and synchronously. Any exception the delegate generates will be
/// propogated out of this method call.
///
///
/// The current ExecutionContext , if one exists,
/// will be captured along with the delegate and will be used when executing it.
///
///
/// The delegate to be executed when the CancellationToken is canceled.
/// The state to pass to the when the delegate is invoked. This may be null.
/// A Boolean value that indicates whether to capture
/// the current SynchronizationContext and use it
/// when invoking the .
/// The instance that can
/// be used to deregister the callback.
/// is null.
/// The associated CancellationTokenSource has been disposed.
public CancellationTokenRegistration Register(Action callback, Object state, bool useSynchronizationContext)
{
return Register(
callback,
state,
useSynchronizationContext,
true // useExecutionContext=true
);
}
// helper for internal registration needs that don't require an EC capture (e.g. creating linked token sources, or registering unstarted TPL tasks)
// has a handy signature, and skips capturing execution context.
internal CancellationTokenRegistration InternalRegisterWithoutEC(Action callback, Object state)
{
return Register(
callback,
state,
false, // useSyncContext=false
false // useExecutionContext=false
);
}
// the real work..
private CancellationTokenRegistration Register(Action callback, Object state, bool useSynchronizationContext, bool useExecutionContext)
{
if (callback == null)
throw new ArgumentNullException("callback");
if(CanBeCanceled == false)
{
return new CancellationTokenRegistration(); // nothing to do for tokens than can never reach the canceled state. Give them a dummy registration.
}
// Capture [....]/execution contexts if required.
// Note: Only capture [....]/execution contexts if IsCancellationRequested = false
// as we know that if it is true that the callback will just be called synchronously.
SynchronizationContext capturedSyncContext = null;
if (!IsCancellationRequested && useSynchronizationContext)
capturedSyncContext = SynchronizationContext.Current;
ExecutionContext capturedExecutionContext = null;
if (!IsCancellationRequested && useExecutionContext)
capturedExecutionContext = ExecutionContext.Capture();
// Register the callback with the source.
return m_source.InternalRegister(callback, state, capturedSyncContext, capturedExecutionContext);
}
///
/// Determines whether the current CancellationToken instance is equal to the
/// specified token.
///
/// The other CancellationToken to which to compare this
/// instance.
/// True if the instances are equal; otherwise, false. Two tokens are equal if they are associated
/// with the same CancellationTokenSource or if they were both constructed
/// from public CancellationToken constructors and their values are equal.
public bool Equals(CancellationToken other)
{
//if both sources are null, then both tokens represent the Empty token.
if (m_source == null && other.m_source == null)
{
return true;
}
// one is null but other has inflated the default source
// these are only equal if the inflated one is the staticSource(false)
if (m_source == null)
{
return other.m_source == CancellationTokenSource.InternalGetStaticSource(false);
}
if (other.m_source == null)
{
return m_source == CancellationTokenSource.InternalGetStaticSource(false);
}
// general case, we check if the sources are identical
return m_source == other.m_source;
}
///
/// Determines whether the current CancellationToken instance is equal to the
/// specified .
///
/// The other object to which to compare this instance.
/// True if is a CancellationToken
/// and if the two instances are equal; otherwise, false. Two tokens are equal if they are associated
/// with the same CancellationTokenSource or if they were both constructed
/// from public CancellationToken constructors and their values are equal.
/// An associated CancellationTokenSource has been disposed.
public override bool Equals(Object other)
{
if (other is CancellationToken)
{
return Equals((CancellationToken) other);
}
return false;
}
///
/// Serves as a hash function for a CancellationToken .
///
/// A hash code for the current CancellationToken instance.
public override Int32 GetHashCode()
{
if (m_source == null)
{
// link to the common source so that we have a source to interrogate.
return CancellationTokenSource.InternalGetStaticSource(false).GetHashCode();
}
return m_source.GetHashCode();
}
///
/// Determines whether two CancellationToken instances are equal.
///
/// The first instance.
/// The second instance.
/// True if the instances are equal; otherwise, false.
/// An associated CancellationTokenSource has been disposed.
public static bool operator ==(CancellationToken left, CancellationToken right)
{
return left.Equals(right);
}
///
/// Determines whether two CancellationToken instances are not equal.
///
/// The first instance.
/// The second instance.
/// True if the instances are not equal; otherwise, false.
/// An associated CancellationTokenSource has been disposed.
public static bool operator !=(CancellationToken left, CancellationToken right)
{
return !left.Equals(right);
}
///
/// Throws a OperationCanceledException if
/// this token has had cancellation requested.
///
///
/// This method provides functionality equivalent to:
///
/// if (token.IsCancellationRequested)
/// throw new OperationCanceledException(token);
///
///
/// The token has had cancellation requested.
/// The associated CancellationTokenSource has been disposed.
public void ThrowIfCancellationRequested()
{
if (IsCancellationRequested)
throw new OperationCanceledException(Environment.GetResourceString("OperationCanceled"), this);
}
// Throw an ODE if this CancellationToken's source is disposed.
internal void ThrowIfSourceDisposed()
{
if ((m_source != null) && m_source.IsDisposed)
{
throw new ObjectDisposedException(null, Environment.GetResourceString("CancellationToken_SourceDisposed"));
}
}
// -----------------------------------
// Private helpers
private void InitializeDefaultSource()
{
// Lazy is slower, and although multiple threads may ---- and set m_source repeatedly, the ---- is benign.
// Alternative: LazyInititalizer.EnsureInitialized(ref m_source, ()=>CancellationTokenSource.InternalGetStaticSource(false));
m_source = CancellationTokenSource.InternalGetStaticSource(false);
}
}
}
// File provided for Reference Use Only by Microsoft Corporation (c) 2007.
// ==++==
//
// Copyright (c) Microsoft Corporation. All rights reserved.
//
// ==--==
//
// [....]
////////////////////////////////////////////////////////////////////////////////
#pragma warning disable 0420 // turn off 'a reference to a volatile field will not be treated as volatile' during CAS.
using System;
using System.Diagnostics;
using System.Runtime.InteropServices;
using System.Security.Permissions;
using System.Diagnostics.Contracts;
namespace System.Threading
{
///
/// Propogates notification that operations should be canceled.
///
///
///
/// A may be created directly in an unchangeable canceled or non-canceled state
/// using the CancellationToken's constructors. However, to have a CancellationToken that can change
/// from a non-canceled to a canceled state,
/// CancellationTokenSource must be used.
/// CancellationTokenSource exposes the associated CancellationToken that may be canceled by the source through its
/// Token property.
///
///
/// Once canceled, a token may not transition to a non-canceled state, and a token whose
/// is false will never change to one that can be canceled.
///
///
/// All members of this struct are thread-safe and may be used concurrently from multiple threads.
///
///
[ComVisible(false)]
[HostProtection(SecurityAction.LinkDemand, Synchronization = true, ExternalThreading = true)]
[DebuggerDisplay("IsCancellationRequested = {IsCancellationRequested}")]
public struct CancellationToken
{
// The backing TokenSource.
// if null, it implicitly represents the same thing as new CancellationToken(false).
// When required, it will be instantiated to reflect this.
private CancellationTokenSource m_source;
//!! warning. If more fields are added, the assumptions in CreateLinkedToken may no longer be valid
/* Properties */
///
/// Returns an empty CancellationToken value.
///
///
/// The value returned by this property will be non-cancelable by default.
///
public static CancellationToken None
{
get
{
return new CancellationToken();
}
}
///
/// Gets whether cancellation has been requested for this token.
///
/// Whether cancellation has been requested for this token.
///
///
/// This property indicates whether cancellation has been requested for this token,
/// either through the token initially being construted in a canceled state, or through
/// calling Cancel
/// on the token's associated .
///
///
/// If this property is true, it only guarantees that cancellation has been requested.
/// It does not guarantee that every registered handler
/// has finished executing, nor that cancellation requests have finished propagating
/// to all registered handlers. Additional synchronization may be required,
/// particularly in situations where related objects are being canceled concurrently.
///
///
public bool IsCancellationRequested {
get
{
return m_source != null && m_source.IsCancellationRequested;
}
}
///
/// Gets whether this token is capable of being in the canceled state.
///
///
/// If CanBeCanceled returns false, it is guaranteed that the token will never transition
/// into a canceled state, meaning that will never
/// return true.
///
public bool CanBeCanceled
{
get
{
return m_source != null && m_source.CanBeCanceled;
}
}
///
/// Gets a that is signaled when the token is canceled.
///
/// Accessing this property causes a WaitHandle
/// to be instantiated. It is preferable to only use this property when necessary, and to then
/// dispose the associated instance at the earliest opportunity (disposing
/// the source will dispose of this allocated handle). The handle should not be closed or disposed directly.
///
/// The associated CancellationTokenSource has been disposed.
public WaitHandle WaitHandle
{
get
{
if (m_source == null)
{
InitializeDefaultSource();
}
return m_source.WaitHandle;
}
}
// public CancellationToken()
// this constructor is implicit for structs
// -> this should behaves exactly as for new CancellationToken(false)
///
/// Internal constructor only a CancellationTokenSource should create a CancellationToken
///
internal CancellationToken(CancellationTokenSource source)
{
m_source = source;
}
///
/// Initializes the CancellationToken .
///
///
/// The canceled state for the token.
///
///
/// Tokens created with this constructor will remain in the canceled state specified
/// by the parameter. If is false,
/// both and will be false.
/// If is true,
/// both and will be true.
///
public CancellationToken(bool canceled) :
this()
{
if(canceled)
m_source = CancellationTokenSource.InternalGetStaticSource(canceled);
}
/* Methods */
private static Action s_ActionToActionObjShunt = new Action(ActionToActionObjShunt);
private static void ActionToActionObjShunt(object obj)
{
Action action = obj as Action;
Contract.Assert(action != null, "Expected an Action here");
action();
}
///
/// Registers a delegate that will be called when this CancellationToken is canceled.
///
///
///
/// If this token is already in the canceled state, the
/// delegate will be run immediately and synchronously. Any exception the delegate generates will be
/// propogated out of this method call.
///
///
/// The current ExecutionContext , if one exists, will be captured
/// along with the delegate and will be used when executing it.
///
///
/// The delegate to be executed when the CancellationToken is canceled.
/// The instance that can
/// be used to deregister the callback.
/// is null.
/// The associated CancellationTokenSource has been disposed.
public CancellationTokenRegistration Register(Action callback)
{
if (callback == null)
throw new ArgumentNullException("callback");
return Register(
s_ActionToActionObjShunt,
callback,
false, // useSync=false
true // useExecutionContext=true
);
}
///
/// Registers a delegate that will be called when this
/// CancellationToken is canceled.
///
///
///
/// If this token is already in the canceled state, the
/// delegate will be run immediately and synchronously. Any exception the delegate generates will be
/// propogated out of this method call.
///
///
/// The current ExecutionContext , if one exists, will be captured
/// along with the delegate and will be used when executing it.
///
///
/// The delegate to be executed when the CancellationToken is canceled.
/// A Boolean value that indicates whether to capture
/// the current SynchronizationContext and use it
/// when invoking the .
/// The instance that can
/// be used to deregister the callback.
/// is null.
/// The associated CancellationTokenSource has been disposed.
public CancellationTokenRegistration Register(Action callback, bool useSynchronizationContext)
{
if (callback == null)
throw new ArgumentNullException("callback");
return Register(
s_ActionToActionObjShunt,
callback,
useSynchronizationContext,
true // useExecutionContext=true
);
}
///
/// Registers a delegate that will be called when this
/// CancellationToken is canceled.
///
///
///
/// If this token is already in the canceled state, the
/// delegate will be run immediately and synchronously. Any exception the delegate generates will be
/// propogated out of this method call.
///
///
/// The current ExecutionContext , if one exists, will be captured
/// along with the delegate and will be used when executing it.
///
///
/// The delegate to be executed when the CancellationToken is canceled.
/// The state to pass to the when the delegate is invoked. This may be null.
/// The instance that can
/// be used to deregister the callback.
/// is null.
/// The associated CancellationTokenSource has been disposed.
public CancellationTokenRegistration Register(Action callback, Object state)
{
if (callback == null)
throw new ArgumentNullException("callback");
return Register(
callback,
state,
false, // useSync=false
true // useExecutionContext=true
);
}
///
/// Registers a delegate that will be called when this
/// CancellationToken is canceled.
///
///
///
/// If this token is already in the canceled state, the
/// delegate will be run immediately and synchronously. Any exception the delegate generates will be
/// propogated out of this method call.
///
///
/// The current ExecutionContext , if one exists,
/// will be captured along with the delegate and will be used when executing it.
///
///
/// The delegate to be executed when the CancellationToken is canceled.
/// The state to pass to the when the delegate is invoked. This may be null.
/// A Boolean value that indicates whether to capture
/// the current SynchronizationContext and use it
/// when invoking the .
/// The instance that can
/// be used to deregister the callback.
/// is null.
/// The associated CancellationTokenSource has been disposed.
public CancellationTokenRegistration Register(Action callback, Object state, bool useSynchronizationContext)
{
return Register(
callback,
state,
useSynchronizationContext,
true // useExecutionContext=true
);
}
// helper for internal registration needs that don't require an EC capture (e.g. creating linked token sources, or registering unstarted TPL tasks)
// has a handy signature, and skips capturing execution context.
internal CancellationTokenRegistration InternalRegisterWithoutEC(Action callback, Object state)
{
return Register(
callback,
state,
false, // useSyncContext=false
false // useExecutionContext=false
);
}
// the real work..
private CancellationTokenRegistration Register(Action callback, Object state, bool useSynchronizationContext, bool useExecutionContext)
{
if (callback == null)
throw new ArgumentNullException("callback");
if(CanBeCanceled == false)
{
return new CancellationTokenRegistration(); // nothing to do for tokens than can never reach the canceled state. Give them a dummy registration.
}
// Capture [....]/execution contexts if required.
// Note: Only capture [....]/execution contexts if IsCancellationRequested = false
// as we know that if it is true that the callback will just be called synchronously.
SynchronizationContext capturedSyncContext = null;
if (!IsCancellationRequested && useSynchronizationContext)
capturedSyncContext = SynchronizationContext.Current;
ExecutionContext capturedExecutionContext = null;
if (!IsCancellationRequested && useExecutionContext)
capturedExecutionContext = ExecutionContext.Capture();
// Register the callback with the source.
return m_source.InternalRegister(callback, state, capturedSyncContext, capturedExecutionContext);
}
///
/// Determines whether the current CancellationToken instance is equal to the
/// specified token.
///
/// The other CancellationToken to which to compare this
/// instance.
/// True if the instances are equal; otherwise, false. Two tokens are equal if they are associated
/// with the same CancellationTokenSource or if they were both constructed
/// from public CancellationToken constructors and their values are equal.
public bool Equals(CancellationToken other)
{
//if both sources are null, then both tokens represent the Empty token.
if (m_source == null && other.m_source == null)
{
return true;
}
// one is null but other has inflated the default source
// these are only equal if the inflated one is the staticSource(false)
if (m_source == null)
{
return other.m_source == CancellationTokenSource.InternalGetStaticSource(false);
}
if (other.m_source == null)
{
return m_source == CancellationTokenSource.InternalGetStaticSource(false);
}
// general case, we check if the sources are identical
return m_source == other.m_source;
}
///
/// Determines whether the current CancellationToken instance is equal to the
/// specified .
///
/// The other object to which to compare this instance.
/// True if is a CancellationToken
/// and if the two instances are equal; otherwise, false. Two tokens are equal if they are associated
/// with the same CancellationTokenSource or if they were both constructed
/// from public CancellationToken constructors and their values are equal.
/// An associated CancellationTokenSource has been disposed.
public override bool Equals(Object other)
{
if (other is CancellationToken)
{
return Equals((CancellationToken) other);
}
return false;
}
///
/// Serves as a hash function for a CancellationToken .
///
/// A hash code for the current CancellationToken instance.
public override Int32 GetHashCode()
{
if (m_source == null)
{
// link to the common source so that we have a source to interrogate.
return CancellationTokenSource.InternalGetStaticSource(false).GetHashCode();
}
return m_source.GetHashCode();
}
///
/// Determines whether two CancellationToken instances are equal.
///
/// The first instance.
/// The second instance.
/// True if the instances are equal; otherwise, false.
/// An associated CancellationTokenSource has been disposed.
public static bool operator ==(CancellationToken left, CancellationToken right)
{
return left.Equals(right);
}
///
/// Determines whether two CancellationToken instances are not equal.
///
/// The first instance.
/// The second instance.
/// True if the instances are not equal; otherwise, false.
/// An associated CancellationTokenSource has been disposed.
public static bool operator !=(CancellationToken left, CancellationToken right)
{
return !left.Equals(right);
}
///
/// Throws a OperationCanceledException if
/// this token has had cancellation requested.
///
///
/// This method provides functionality equivalent to:
///
/// if (token.IsCancellationRequested)
/// throw new OperationCanceledException(token);
///
///
/// The token has had cancellation requested.
/// The associated CancellationTokenSource has been disposed.
public void ThrowIfCancellationRequested()
{
if (IsCancellationRequested)
throw new OperationCanceledException(Environment.GetResourceString("OperationCanceled"), this);
}
// Throw an ODE if this CancellationToken's source is disposed.
internal void ThrowIfSourceDisposed()
{
if ((m_source != null) && m_source.IsDisposed)
{
throw new ObjectDisposedException(null, Environment.GetResourceString("CancellationToken_SourceDisposed"));
}
}
// -----------------------------------
// Private helpers
private void InitializeDefaultSource()
{
// Lazy is slower, and although multiple threads may ---- and set m_source repeatedly, the ---- is benign.
// Alternative: LazyInititalizer.EnsureInitialized(ref m_source, ()=>CancellationTokenSource.InternalGetStaticSource(false));
m_source = CancellationTokenSource.InternalGetStaticSource(false);
}
}
}
// File provided for Reference Use Only by Microsoft Corporation (c) 2007.