CancellationTokenRegistration.cs source code in C# .NET

Source code for the .NET framework in C#

                        

Code:

/ 4.0 / 4.0 / DEVDIV_TFS / Dev10 / Releases / RTMRel / ndp / clr / src / BCL / System / Threading / CancellationTokenRegistration.cs / 1305376 / CancellationTokenRegistration.cs

                            // ==++== 
//
//   Copyright (c) Microsoft Corporation.  All rights reserved.
//
// ==--== 
//
// [....] 
//////////////////////////////////////////////////////////////////////////////// 

using System.Diagnostics.Contracts; 
using System.Security.Permissions;

namespace System.Threading
{ 
    /// 
    /// Represents a callback delegate that has been registered with a CancellationToken. 
    ///  
    /// 
    /// To unregister a callback, dispose the corresponding Registration instance. 
    /// 
    [HostProtection(Synchronization = true, ExternalThreading = true)]
    public struct CancellationTokenRegistration : IEquatable, IDisposable
    { 
        private readonly CancellationTokenSource m_tokenSource;
        private readonly CancellationCallbackInfo m_callbackInfo; 
        private readonly SparselyPopulatedArrayAddInfo m_registrationInfo; 

        internal CancellationTokenRegistration( 
            CancellationTokenSource tokenSource,
            CancellationCallbackInfo callbackInfo,
            SparselyPopulatedArrayAddInfo registrationInfo)
        { 
            m_tokenSource = tokenSource;
            m_callbackInfo = callbackInfo; 
            m_registrationInfo = registrationInfo; 
        }
 
        /// 
        /// Attempts to deregister the item. If it's already being run, this may fail.
        /// Entails a full memory fence.
        ///  
        /// True if the callback was found and deregistered, false otherwise.
        internal bool TryDeregister() 
        { 
            if (m_registrationInfo.Source == null)  //can be null for dummy registrations.
                return false; 

            // Try to remove the callback info from the array.
            // It is possible the callback info is missing (removed for run, or removed by someone else)
            // It is also possible there is info in the array but it doesn't match our current registration's callback info. 
            CancellationCallbackInfo prevailingCallbackInfoInSlot = m_registrationInfo.Source.SafeAtomicRemove(m_registrationInfo.Index, m_callbackInfo);
 
            if (prevailingCallbackInfoInSlot != m_callbackInfo) 
                return false;  //the callback in the slot wasn't us.
 
            return true;
        }

        ///  
        /// Disposes of the registration and unregisters the target callback from the associated
        /// CancellationToken. 
        /// If the target callback is currently executing this method will wait until it completes, except 
        /// in the degenerate cases where a callback method deregisters itself.
        ///  
        public void Dispose()
        {
            // If the token source has been disposed, we must throw.
            if (m_tokenSource != null) 
                m_tokenSource.ThrowIfDisposed();
 
            // Remove the entry from the array. 
            // This call includes a full memory fence which prevents potential reorderings of the reads below
            bool deregisterOccured = TryDeregister(); 

            // We guarantee that we will not return if the callback is being executed (assuming we are not currently called by the callback itself)
            // We achieve this by the following rules:
            //    1. if we are called in the context of an executing callback, no need to wait (determined by tracking callback-executor threadID) 
            //       - if the currently executing callback is this CTR, then waiting would deadlock. (We choose to return rather than deadlock)
            //       - if not, then this CTR cannot be the one executing, hence no need to wait 
            // 
            //    2. if deregistration failed, and we are on a different thread, then the callback may be running under control of cts.Cancel()
            //       => poll until cts.ExecutingCallback is not the one we are trying to deregister. 

            if (m_tokenSource != null &&
                m_tokenSource.IsCancellationRequested && //running callbacks has commenced.
                ! m_tokenSource.IsCancellationCompleted && //running callbacks hasn't finished 
                !deregisterOccured && //deregistration failed (ie the callback is missing from the list)
                m_tokenSource.ThreadIDExecutingCallbacks != Thread.CurrentThread.ManagedThreadId) //the executingThreadID is not this threadID. 
            { 
                // Callback execution is in progress, the executing thread is different to us and has taken the callback for execution
                // so observe and wait until this target callback is no longer the executing callback. 
                m_tokenSource.WaitForCallbackToComplete(m_callbackInfo);
            }
        }
 
        /// 
        /// Determines whether two CancellationTokenRegistration 
        /// instances are equal.
        ///  
        /// The first instance.
        /// The second instance.
        /// True if the instances are equal; otherwise, false.
        public static bool operator ==(CancellationTokenRegistration left, CancellationTokenRegistration right) 
        {
            return left.Equals(right); 
        } 

        ///  
        /// Determines whether two CancellationTokenRegistration instances are not equal.
        /// 
        /// The first instance.
        /// The second instance. 
        /// True if the instances are not equal; otherwise, false.
        public static bool operator !=(CancellationTokenRegistration left, CancellationTokenRegistration right) 
        { 
            return !left.Equals(right);
        } 

        /// 
        /// Determines whether the current CancellationTokenRegistration instance is equal to the
        /// specified . 
        /// 
        /// The other object to which to compare this instance. 
        /// True, if both this and  are equal. False, otherwise. 
        /// Two CancellationTokenRegistration instances are equal if
        /// they both refer to the output of a single call to the same Register method of a 
        /// CancellationToken.
        /// 
        public override bool Equals(object obj)
        { 
            return ((obj is CancellationTokenRegistration) && Equals((CancellationTokenRegistration) obj));
        } 
 
        /// 
        /// Determines whether the current CancellationToken instance is equal to the 
        /// specified .
        /// 
        /// The other CancellationTokenRegistration to which to compare this instance.
        /// True, if both this and  are equal. False, otherwise. 
        /// Two CancellationTokenRegistration instances are equal if
        /// they both refer to the output of a single call to the same Register method of a 
        /// CancellationToken. 
        /// 
        public bool Equals(CancellationTokenRegistration other) 
        {

            return m_tokenSource == other.m_tokenSource &&
                   m_callbackInfo == other.m_callbackInfo && 
                   m_registrationInfo.Source == other.m_registrationInfo.Source &&
                   m_registrationInfo.Index == other.m_registrationInfo.Index; 
        } 

        ///  
        /// Serves as a hash function for a CancellationTokenRegistration..
        /// 
        /// A hash code for the current CancellationTokenRegistration instance.
        public override int GetHashCode() 
        {
            if (m_registrationInfo.Source != null) 
                return m_registrationInfo.Source.GetHashCode() ^ m_registrationInfo.Index.GetHashCode(); 

            return m_registrationInfo.Index.GetHashCode(); 
        }
    }
}

// File provided for Reference Use Only by Microsoft Corporation (c) 2007.
// ==++== 
//
//   Copyright (c) Microsoft Corporation.  All rights reserved.
//
// ==--== 
//
// [....] 
//////////////////////////////////////////////////////////////////////////////// 

using System.Diagnostics.Contracts; 
using System.Security.Permissions;

namespace System.Threading
{ 
    /// 
    /// Represents a callback delegate that has been registered with a CancellationToken. 
    ///  
    /// 
    /// To unregister a callback, dispose the corresponding Registration instance. 
    /// 
    [HostProtection(Synchronization = true, ExternalThreading = true)]
    public struct CancellationTokenRegistration : IEquatable, IDisposable
    { 
        private readonly CancellationTokenSource m_tokenSource;
        private readonly CancellationCallbackInfo m_callbackInfo; 
        private readonly SparselyPopulatedArrayAddInfo m_registrationInfo; 

        internal CancellationTokenRegistration( 
            CancellationTokenSource tokenSource,
            CancellationCallbackInfo callbackInfo,
            SparselyPopulatedArrayAddInfo registrationInfo)
        { 
            m_tokenSource = tokenSource;
            m_callbackInfo = callbackInfo; 
            m_registrationInfo = registrationInfo; 
        }
 
        /// 
        /// Attempts to deregister the item. If it's already being run, this may fail.
        /// Entails a full memory fence.
        ///  
        /// True if the callback was found and deregistered, false otherwise.
        internal bool TryDeregister() 
        { 
            if (m_registrationInfo.Source == null)  //can be null for dummy registrations.
                return false; 

            // Try to remove the callback info from the array.
            // It is possible the callback info is missing (removed for run, or removed by someone else)
            // It is also possible there is info in the array but it doesn't match our current registration's callback info. 
            CancellationCallbackInfo prevailingCallbackInfoInSlot = m_registrationInfo.Source.SafeAtomicRemove(m_registrationInfo.Index, m_callbackInfo);
 
            if (prevailingCallbackInfoInSlot != m_callbackInfo) 
                return false;  //the callback in the slot wasn't us.
 
            return true;
        }

        ///  
        /// Disposes of the registration and unregisters the target callback from the associated
        /// CancellationToken. 
        /// If the target callback is currently executing this method will wait until it completes, except 
        /// in the degenerate cases where a callback method deregisters itself.
        ///  
        public void Dispose()
        {
            // If the token source has been disposed, we must throw.
            if (m_tokenSource != null) 
                m_tokenSource.ThrowIfDisposed();
 
            // Remove the entry from the array. 
            // This call includes a full memory fence which prevents potential reorderings of the reads below
            bool deregisterOccured = TryDeregister(); 

            // We guarantee that we will not return if the callback is being executed (assuming we are not currently called by the callback itself)
            // We achieve this by the following rules:
            //    1. if we are called in the context of an executing callback, no need to wait (determined by tracking callback-executor threadID) 
            //       - if the currently executing callback is this CTR, then waiting would deadlock. (We choose to return rather than deadlock)
            //       - if not, then this CTR cannot be the one executing, hence no need to wait 
            // 
            //    2. if deregistration failed, and we are on a different thread, then the callback may be running under control of cts.Cancel()
            //       => poll until cts.ExecutingCallback is not the one we are trying to deregister. 

            if (m_tokenSource != null &&
                m_tokenSource.IsCancellationRequested && //running callbacks has commenced.
                ! m_tokenSource.IsCancellationCompleted && //running callbacks hasn't finished 
                !deregisterOccured && //deregistration failed (ie the callback is missing from the list)
                m_tokenSource.ThreadIDExecutingCallbacks != Thread.CurrentThread.ManagedThreadId) //the executingThreadID is not this threadID. 
            { 
                // Callback execution is in progress, the executing thread is different to us and has taken the callback for execution
                // so observe and wait until this target callback is no longer the executing callback. 
                m_tokenSource.WaitForCallbackToComplete(m_callbackInfo);
            }
        }
 
        /// 
        /// Determines whether two CancellationTokenRegistration 
        /// instances are equal.
        ///  
        /// The first instance.
        /// The second instance.
        /// True if the instances are equal; otherwise, false.
        public static bool operator ==(CancellationTokenRegistration left, CancellationTokenRegistration right) 
        {
            return left.Equals(right); 
        } 

        ///  
        /// Determines whether two CancellationTokenRegistration instances are not equal.
        /// 
        /// The first instance.
        /// The second instance. 
        /// True if the instances are not equal; otherwise, false.
        public static bool operator !=(CancellationTokenRegistration left, CancellationTokenRegistration right) 
        { 
            return !left.Equals(right);
        } 

        /// 
        /// Determines whether the current CancellationTokenRegistration instance is equal to the
        /// specified . 
        /// 
        /// The other object to which to compare this instance. 
        /// True, if both this and  are equal. False, otherwise. 
        /// Two CancellationTokenRegistration instances are equal if
        /// they both refer to the output of a single call to the same Register method of a 
        /// CancellationToken.
        /// 
        public override bool Equals(object obj)
        { 
            return ((obj is CancellationTokenRegistration) && Equals((CancellationTokenRegistration) obj));
        } 
 
        /// 
        /// Determines whether the current CancellationToken instance is equal to the 
        /// specified .
        /// 
        /// The other CancellationTokenRegistration to which to compare this instance.
        /// True, if both this and  are equal. False, otherwise. 
        /// Two CancellationTokenRegistration instances are equal if
        /// they both refer to the output of a single call to the same Register method of a 
        /// CancellationToken. 
        /// 
        public bool Equals(CancellationTokenRegistration other) 
        {

            return m_tokenSource == other.m_tokenSource &&
                   m_callbackInfo == other.m_callbackInfo && 
                   m_registrationInfo.Source == other.m_registrationInfo.Source &&
                   m_registrationInfo.Index == other.m_registrationInfo.Index; 
        } 

        ///  
        /// Serves as a hash function for a CancellationTokenRegistration..
        /// 
        /// A hash code for the current CancellationTokenRegistration instance.
        public override int GetHashCode() 
        {
            if (m_registrationInfo.Source != null) 
                return m_registrationInfo.Source.GetHashCode() ^ m_registrationInfo.Index.GetHashCode(); 

            return m_registrationInfo.Index.GetHashCode(); 
        }
    }
}

// File provided for Reference Use Only by Microsoft Corporation (c) 2007.

                        

Link Menu

Network programming in C#, Network Programming in VB.NET, Network Programming in .NET
This book is available now!
Buy at Amazon US or
Buy at Amazon UK