/// <summary> /// Disposes of the registration and unregisters the target callback from the associated /// <see cref="System.Threading.CancellationToken">CancellationToken</see>. /// The returned <see cref="ValueTask"/> will complete once the associated callback /// is unregistered without having executed or once it's finished executing, except /// in the degenerate case where the callback itself is unregistering itself. /// </summary> public ValueTask DisposeAsync() { CancellationTokenSource.CallbackNode node = _node; return node != null && !node.Partition.Unregister(_id, node) ? WaitForCallbackIfNecessaryAsync() : default; }
/// <summary> /// Disposes of the registration and unregisters the target callback from the associated /// <see cref="T:System.Threading.CancellationToken">CancellationToken</see>. /// 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. /// </summary> public void Dispose() { CancellationTokenSource.CallbackNode node = _node; if (node != null && !node.Partition.Unregister(_id, node)) { WaitForCallbackIfNecessary(); } }
static void WaitForCallbackIfNecessary(long id, CancellationTokenSource.CallbackNode node) { // We're a valid registration but we were unable to unregister, which means the callback wasn't in the list, // which means either it already executed or it's currently executing. 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 unregistration 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 unregister. CancellationTokenSource source = node.Registrations.Source; if (source.IsCancellationRequested && // Running callbacks has commenced. !source.IsCancellationCompleted && // Running callbacks hasn't finished. node.Registrations.ThreadIDExecutingCallbacks != Environment.CurrentManagedThreadId) // The executing thread ID is not this thread's ID. { // Callback execution is in progress, the executing thread is different from this thread and has taken the callback for execution // so observe and wait until this target callback is no longer the executing callback. node.Registrations.WaitForCallbackToComplete(id); } }
/// <summary> /// Disposes of the registration and unregisters the target callback from the associated /// <see cref="T:System.Threading.CancellationToken">CancellationToken</see>. /// </summary> internal bool TryDeregister() // corefx currently has an InternalsVisibleTo dependency on this { CancellationTokenSource.CallbackNode node = _node; return(node != null && node.Partition.Unregister(_id, node)); }
internal CancellationTokenRegistration(long id, CancellationTokenSource.CallbackNode node) { _id = id; _node = node; }
/// <summary> /// Disposes of the registration and unregisters the target callback from the associated /// <see cref="T:System.Threading.CancellationToken">CancellationToken</see>. /// </summary> public bool Unregister() { CancellationTokenSource.CallbackNode node = _node; return(node != null && node.Partition.Unregister(_id, node)); }
/// <summary> /// Disposes of the registration and unregisters the target callback from the associated /// <see cref="T:System.Threading.CancellationToken">CancellationToken</see>. /// </summary> public bool Unregister() // TODO dotnet/corefx#14903: This is "public" for corefx usage, but it's not yet in the refs or approved public API. { CancellationTokenSource.CallbackNode node = _node; return(node != null && node.Partition.Unregister(_id, node)); }