protected void UnregisterCancellation()
        {
            _TokenSource?.Dispose();
            _TokenSource = null;
            _Token       = default;

#if NETSTANDARD2_0
            // This may block if SwitchToCancelled is running
            _Registration.Dispose();

            OnCompletedCleanup();
#else
            // This will not block if SwitchToCancelled is running, but may continue later
            _Awaiter = _Registration.DisposeAsync().ConfigureAwait(false).GetAwaiter();

            if (_Awaiter.IsCompleted)
            {
                OnCompletedCleanup();
            }
            else
            {
                _Awaiter.OnCompleted(_CompletedCleanup);
            }
#endif
        }
        public async ValueTask DisposeAsync()
        {
            _asyncEventStream._sequencer.RemoveGatingSequence(_sequence);

            await _cancellationTokenRegistration.DisposeAsync().ConfigureAwait(false);

            _linkedTokenSource.Dispose();
        }
예제 #3
0
        public static void CancellationTokenRegistration_DisposeAsyncRemovesDelegate()
        {
            var  cts     = new CancellationTokenSource();
            bool invoked = false;
            CancellationTokenRegistration ctr = cts.Token.Register(() => invoked = true);

            Assert.True(ctr.DisposeAsync().IsCompletedSuccessfully);
            cts.Cancel();
            Assert.False(invoked);
        }
예제 #4
0
        /// <summary>
        /// Allows awaiting a <see cref="WaitHandle"/> which
        /// <inheritdoc cref="WaitHandle"/>
        /// </summary>
        /// <param name="handle">The <see cref="WaitHandle"/> to await.</param>
        /// <param name="timeout">The timeout period in milliseconds to return false if timed out.
        ///     <code>
        ///         // In order to use timeouts and infinitely wait till a resource is free use
        ///         (int)timeout.Infinite
        ///     </code></param>
        /// <param name="token">The cancellation token to use to throw a <see cref="TaskCanceledException"/>
        ///                     if this token gets cancelled</param>
        /// <returns>True if the handle is free, false if it is not</returns>
        /// <exception cref="TaskCanceledException">Throws if the cancellation token is invoked</exception>
        /// <example>
        ///     handle.WaitHandleAsync((int)Timeout.Infinite, cancellationToken);
        /// </example>
        public static async Task <bool> WaitHandleAsync(this WaitHandle handle, int timeout, CancellationToken?token)
        {
            // Create a handle that awaits the original wait handle
            RegisteredWaitHandle registeredWaitHandle = null;

            // Store the token
            CancellationTokenRegistration?tokenRegistration = null;

            try
            {
                // Create a new task completion source to await
                TaskCompletionSource <bool> taskCompletionSource = new TaskCompletionSource <bool>();

                /* Use RegisterWaitForSingleObject so we get a callback
                 * once the wait handle has finished, and set the taskCompletionSource result in that callback.
                 */
                registeredWaitHandle = ThreadPool.RegisterWaitForSingleObject(
                    // The handle to wait
                    handle,
                    // When it is finished, set the taskCompletionSource
                    (state, timedOut) =>
                    ((TaskCompletionSource <bool>)state)
                    .TrySetResult(!timedOut),
                    // Pass the taskCompletion source as the state so we don't have a reference to the parent
                    // taskCompletionSource (optimization)
                    taskCompletionSource,
                    // Set timeout if passed in
                    timeout,
                    // Run once don't keep resetting timeout
                    true);

                /*
                 * Register to run the action and set the taskCompletionSource as cancelled
                 * if the cancellation token itself is cancelled; which will throw a TaskCancelledException
                 * up to the caller.
                 */
                if (token.HasValue)
                {
                    tokenRegistration = token.Value.Register((state) =>
                                                             ((TaskCompletionSource <bool>)state)
                                                             .TrySetCanceled(), taskCompletionSource);
                }

                // Await the handle or the cancellation token
                return(await taskCompletionSource.Task);
            }
            finally
            {
                // Clean up registered wait handle
                registeredWaitHandle?.Unregister(null);

                // Dispose of the token we had to create to register for the cancellation token callback
                tokenRegistration?.DisposeAsync();
            }
        }
        public ValueTask DisposeAsync()
        {
            // Deadline registration needs to be disposed with DisposeAsync, and the task completed
            // before the lock can be disposed.
            // Awaiting deadline registration and deadline task ensures it has finished running, so there is
            // no way for deadline logic to attempt to wait on a disposed lock.
            var disposeTask = _deadlineExceededRegistration.DisposeAsync();

            if (disposeTask.IsCompletedSuccessfully &&
                (_deadlineExceededTask == null || _deadlineExceededTask.IsCompletedSuccessfully))
            {
                DisposeCore();
                return(default);
            internal async ValueTask CompleteWritesAsync(CancellationToken cancellationToken = default)
            {
                ValueTask task = _writer.CompleteAsync();

                CancellationTokenRegistration registration =
                    task.IsCompleted || !cancellationToken.CanBeCanceled ? default :
                    cancellationToken.UnsafeRegister(o => ((PipeWriter)o !).CancelPendingFlush(), _writer);

                    try
                    {
                        await task.ConfigureAwait(false);
                    }
                    finally
                    {
                        await registration.DisposeAsync().ConfigureAwait(false);
                    }
            }
예제 #7
0
        /// <summary>
        /// Due to the asynchronous design of LibVLC and the initial LibVLCSharp APIs, the C# functions returned immediately as they
        /// act as "command sender" essentially, without waiting for state changes. For consumers interested in getting notified of state
        /// changes triggered by their function calls, they could register to libvlc events manually (e.g. subscribe to the Playing event,
        /// call Play(), see your event handler invoked as the Playing event fires).
        /// Now thanks to this, we can offer Async versions of the APIs which actually wait for state changes (e.g. only return when the native
        /// event confirming state changes has fired). It may take a while and many users do not actually care about it. But some do.
        /// </summary>
        /// <typeparam name="T">the return type of the API call</typeparam>
        /// <param name="nativeCall">the native P/Invoke mapping</param>
        /// <param name="sub">the subscribe action delegate</param>
        /// <param name="unsub">the unsubscribe action delegate</param>
        /// <param name="tcs">the task completion source to wait for the event to fire</param>
        /// <param name="ctr">the cancellation token registration to dispose once the operation is over</param>
        /// <returns>The task result of the type of the API</returns>
        internal static async Task <T> InternalAsync <T>(Action nativeCall, Action sub, Action unsub, TaskCompletionSource <T> tcs, CancellationTokenRegistration ctr = default)
        {
            try
            {
                sub();
                nativeCall();
                return(await tcs.Task.ConfigureAwait(false));
            }
            finally
            {
                unsub();
#if NETFRAMEWORK || NETSTANDARD2_0 || UWP
                ctr.Dispose();
#else
                await ctr.DisposeAsync();
#endif
            }
        }
예제 #8
0
        public static async Task CancellationTokenRegistration_DisposeAsyncDuringCancellation_SuccessfullyRemovedIfNotYetInvoked()
        {
            var ctr0running = new ManualResetEventSlim();
            var ctr2blocked = new ManualResetEventSlim();
            var ctr2running = new ManualResetEventSlim();
            var cts         = new CancellationTokenSource();

            CancellationTokenRegistration ctr0 = cts.Token.Register(() => ctr0running.Set());

            bool ctr1Invoked = false;
            CancellationTokenRegistration ctr1 = cts.Token.Register(() => ctr1Invoked = true);

            CancellationTokenRegistration ctr2 = cts.Token.Register(() =>
            {
                ctr2running.Set();
                ctr2blocked.Wait();
            });

            // Cancel.  This will trigger ctr2 to run, then ctr1, then ctr0.
            Task ignored = Task.Run(() => cts.Cancel());

            ctr2running.Wait(); // wait for ctr2 to start running
            ValueTask vt2 = ctr2.DisposeAsync();

            Assert.False(vt2.IsCompleted);

            // Now that ctr2 is running, unregister ctr1. This should succeed
            // and ctr1 should not run.
            Assert.True(ctr1.DisposeAsync().IsCompletedSuccessfully);

            // Allow ctr2 to continue.  ctr1 should not run.  ctr0 should, so wait for it.
            ctr2blocked.Set();
            ctr0running.Wait();
            await ctr0.DisposeAsync();

            Assert.False(ctr1Invoked);
            await vt2;
        }
예제 #9
0
    /// <summary>
    ///     Asynchronously waits for the wait handle.
    /// </summary>
    /// <param name="handle">The handle.</param>
    /// <param name="timeout">The timeout.</param>
    /// <param name="cancellationToken">The cancellation token.</param>
    /// <returns><c>true</c> if the timeout has not been reached, <c>false</c> otherwise.</returns>
    public static async ValueTask <bool> WaitOneAsync(
        this WaitHandle handle,
        TimeSpan timeout,
        CancellationToken cancellationToken)
    {
        RegisteredWaitHandle?         registeredHandle  = null;
        CancellationTokenRegistration tokenRegistration = default;

        try
        {
            var tcs = new TaskCompletionSource <bool>();

            registeredHandle = ThreadPool.RegisterWaitForSingleObject(
                handle,
                (
                    state,
                    timedOut) => ((TaskCompletionSource <bool>)state !).TrySetResult(!timedOut),
                tcs,
                timeout,
                true);

            tokenRegistration = cancellationToken.Register(
                state => state.TrySetCanceled(),
                tcs);

            return(await tcs.Task);
        }
        finally
        {
            registeredHandle?.Unregister(null);

            #if NETSTANDARD21_OR_GREATER
            await tokenRegistration.DisposeAsync();
            #else
            tokenRegistration.Dispose();
            #endif
        }
    }
예제 #10
0
        public static async Task CancellationTokenRegistration_DisposeAsyncWhileCallbackRunning_WaitsForCallbackToComplete()
        {
            using (var barrier = new Barrier(2))
            {
                var cts = new CancellationTokenSource();
                CancellationTokenRegistration ctr = cts.Token.Register(() =>
                {
                    barrier.SignalAndWait();
                    barrier.SignalAndWait();
                });

                Task ignored = Task.Run(() => cts.Cancel());

                barrier.SignalAndWait();
                ValueTask vt = ctr.DisposeAsync();
                await Task.Delay(1);

                Assert.False(vt.IsCompleted);
                barrier.SignalAndWait();

                await vt;
            }
        }
        public static async Task <ProcessResult> RunAsTaskAsync(this ProcessStartInfo psi, CancellationToken cancellationToken = default)
        {
            cancellationToken.ThrowIfCancellationRequested();

            var logs = new List <ProcessOutput>();
            int exitCode;

            using (var process = new Process())
            {
                process.StartInfo = psi;
                if (psi.RedirectStandardError)
                {
                    process.ErrorDataReceived += (sender, e) =>
                    {
                        if (e.Data != null)
                        {
                            lock (logs)
                            {
                                logs.Add(new ProcessOutput(ProcessOutputType.StandardError, e.Data));
                            }
                        }
                    };
                }

                if (psi.RedirectStandardOutput)
                {
                    process.OutputDataReceived += (sender, e) =>
                    {
                        if (e.Data != null)
                        {
                            lock (logs)
                            {
                                logs.Add(new ProcessOutput(ProcessOutputType.StandardOutput, e.Data));
                            }
                        }
                    };
                }

                if (!process.Start())
                {
                    throw new Win32Exception("Cannot start the process");
                }

                if (psi.RedirectStandardError)
                {
                    process.BeginErrorReadLine();
                }

                if (psi.RedirectStandardOutput)
                {
                    process.BeginOutputReadLine();
                }

                if (psi.RedirectStandardInput)
                {
                    process.StandardInput.Close();
                }

                CancellationTokenRegistration registration = default;
                try
                {
                    if (cancellationToken.CanBeCanceled && !process.HasExited)
                    {
                        registration = cancellationToken.Register(() =>
                        {
                            try
                            {
                                process.Kill(entireProcessTree: true);
                            }
                            catch (InvalidOperationException)
                            {
                                try
                                {
                                    // Try to at least kill the root process
                                    process.Kill();
                                }
                                catch (InvalidOperationException)
                                {
                                }
                            }
                        });
                    }

                    await process.WaitForExitAsync(cancellationToken).ConfigureAwait(false);

                    process.WaitForExit(); // https://github.com/dotnet/runtime/issues/42556
                }
                finally
                {
                    await registration.DisposeAsync().ConfigureAwait(false);
                }

                exitCode = process.ExitCode;
            }

            cancellationToken.ThrowIfCancellationRequested();
            return(new ProcessResult(exitCode, logs));
        }
예제 #12
0
 /// <inheritdoc />
 public ValueTask DisposeAsync()
 {
     return(_lifetimeAppStopRegistration.DisposeAsync());
 }