Ejemplo n.º 1
0
 /// <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;
 }
Ejemplo n.º 6
0
 /// <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));
 }
Ejemplo n.º 7
0
 /// <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));
 }