WebApplications.Utilities.Threading.PauseToken.WaitWhilePausedAsync C# (CSharp) Method

WaitWhilePausedAsync() private method

private WaitWhilePausedAsync ( CancellationToken token = default(CancellationToken) ) : Task
token System.Threading.CancellationToken
return Task
        public Task WaitWhilePausedAsync(CancellationToken token = default(CancellationToken))
        {
            return _source != null && _source.IsPaused
                ? _source.WaitWhilePausedAsync(token)
                : TaskResult.Completed;
        }
    }

Usage Example

Example #1
0
        /// <summary>
        /// The timer task executes the callback asynchronously after set delays.
        /// </summary>
        /// <param name="cancellationToken">The cancellation token.</param>
        /// <returns></returns>
        // ReSharper disable once FunctionComplexityOverflow
        private async Task TimerTask(CancellationToken cancellationToken)
        {
            long startTicks = long.MinValue;
            long endTicks   = long.MinValue;

            while (!cancellationToken.IsCancellationRequested)
            {
                try
                {
                    CancellationTokenSource timeoutsChanged;

                    // Check we're not set to run immediately
                    if (Interlocked.Exchange(ref _runImmediate, 0) == 0)
                    {
                        do
                        {
                            // Create new cancellation token source and set _timeOutsChanged to it in a thread-safe none-locking way.
                            timeoutsChanged = new CancellationTokenSource();
                            CancellationTokenSource toc = Interlocked.Exchange(ref _timeOutsChanged, timeoutsChanged);
                            if (ReferenceEquals(toc, null))
                            {
                                toc = Interlocked.CompareExchange(ref _timeOutsChanged, null, timeoutsChanged);
                                if (!ReferenceEquals(toc, null))
                                {
                                    toc.Dispose();
                                }
                                return;
                            }

                            // If we have run immediate set at this point, we can't rely on the correct _timeOutsChanged cts being cancelled.
                            if (Interlocked.Exchange(ref _runImmediate, 0) > 0)
                            {
                                break;
                            }

                            using (ITokenSource tokenSource = cancellationToken.CreateLinked(timeoutsChanged.Token))
                            {
                                // Check for pausing.
                                try
                                {
                                    await _pauseToken.WaitWhilePausedAsync(tokenSource.Token).ConfigureAwait(false);
                                }
                                catch (OperationCanceledException)
                                {
                                }
                                catch (Exception exception)
                                {
                                    if (!ReferenceEquals(_errorHandler, null))
                                    {
                                        _errorHandler(exception);
                                    }
                                }

                                if (cancellationToken.IsCancellationRequested)
                                {
                                    return;
                                }

                                // Get timeouts
                                TimeOuts timeOuts = _timeOuts;
                                if (ReferenceEquals(timeOuts, null))
                                {
                                    return;
                                }

                                if (timeOuts.DueTimeMs < 0 ||
                                    (startTicks > timeOuts.DueTimeStamp && (timeOuts.MinimumGapMs < 0 || timeOuts.PeriodMs < 0)))
                                {
                                    // If we have infinite waits then we are effectively awaiting cancellation
                                    // ReSharper disable once PossibleNullReferenceException
                                    await tokenSource.ConfigureAwait(false);

                                    if (cancellationToken.IsCancellationRequested)
                                    {
                                        return;
                                    }
                                    continue;
                                }

                                // If all timeouts are zero we effectively run again immediately (after checking we didn't get a cancellation
                                // indicating the value have changed again).
                                if (timeOuts.DueTimeMs == 0 &&
                                    timeOuts.MinimumGapMs == 0 &&
                                    timeOuts.PeriodMs == 0)
                                {
                                    continue;
                                }

                                int wait;

                                if (startTicks > long.MinValue)
                                {
                                    // Calculate the wait time based on the minimum gap and the period.
                                    long now = HighPrecisionClock.Instance.NowTicks;
                                    int  a   = timeOuts.PeriodMs -
                                               (int)((now - startTicks) / NodaConstants.TicksPerMillisecond);
                                    int b = timeOuts.MinimumGapMs -
                                            (int)((now - endTicks) / NodaConstants.TicksPerMillisecond);
                                    int c = (int)((timeOuts.DueTimeStamp - now) / NodaConstants.TicksPerMillisecond);

                                    wait = Math.Max(a, Math.Max(b, c));
                                }
                                else
                                {
                                    // Wait the initial due time
                                    wait =
                                        (int)
                                        ((timeOuts.DueTimeStamp - HighPrecisionClock.Instance.NowTicks) /
                                         NodaConstants.TicksPerMillisecond);
                                }

                                // If we don't need to wait run again immediately (after checking values haven't changed).
                                if (wait < 1)
                                {
                                    continue;
                                }

                                try
                                {
                                    // Wait for set milliseconds
                                    // ReSharper disable PossibleNullReferenceException
                                    await Task.Delay(wait, tokenSource.Token).ConfigureAwait(false);

                                    // ReSharper restore PossibleNullReferenceException
                                }
                                catch (OperationCanceledException)
                                {
                                }
                                catch (Exception exception)
                                {
                                    if (!ReferenceEquals(_errorHandler, null))
                                    {
                                        _errorHandler(exception);
                                    }
                                }
                            }

                            // Recalculate wait time if 'cancelled' due to signal, and not set to run immediately; or if we're currently paused.
                        } while (
                            _pauseToken.IsPaused ||
                            (timeoutsChanged.IsCancellationRequested &&
                             !cancellationToken.IsCancellationRequested &&
                             Interlocked.Exchange(ref _runImmediate, 0) < 1));
                    }

                    if (cancellationToken.IsCancellationRequested)
                    {
                        return;
                    }

                    try
                    {
                        Interlocked.CompareExchange(
                            ref _callbackCompletionSource,
                            new TaskCompletionSource <bool>(),
                            null);

                        startTicks = HighPrecisionClock.Instance.NowTicks;

                        // ReSharper disable once PossibleNullReferenceException
                        await _callback(cancellationToken).ConfigureAwait(false);

                        if (cancellationToken.IsCancellationRequested)
                        {
                            return;
                        }
                    }
                    catch (OperationCanceledException)
                    {
                        // Just finish as we're cancelled

                        TaskCompletionSource <bool> callbackCompletionSource =
                            Interlocked.Exchange(ref _callbackCompletionSource, null);

                        // If the completion source is not null, then someone is awaiting last execution, so complete the task
                        if (!ReferenceEquals(callbackCompletionSource, null))
                        {
                            callbackCompletionSource.TrySetCanceled();
                        }

                        return;
                    }
                    // ReSharper disable once EmptyGeneralCatchClause
                    catch (Exception exception)
                    {
                        // Supress errors thrown by callback, unless someone is awaiting it.

                        TaskCompletionSource <bool> callbackCompletionSource =
                            Interlocked.Exchange(ref _callbackCompletionSource, null);

                        // If the completion source is not null, then someone is awaiting last execution, so complete the task
                        if (!ReferenceEquals(callbackCompletionSource, null))
                        {
                            callbackCompletionSource.TrySetException(exception);
                        }

                        if (!ReferenceEquals(_errorHandler, null))
                        {
                            _errorHandler(exception);
                        }
                    }
                    finally
                    {
                        endTicks = HighPrecisionClock.Instance.NowTicks;

                        // If run immediately was set whilst we were running, we can clear it.
                        Interlocked.Exchange(ref _runImmediate, 0);

                        TaskCompletionSource <bool> callbackCompletionSource =
                            Interlocked.Exchange(ref _callbackCompletionSource, null);

                        // If the completion source is not null, then someone is awaiting last execution, so complete the task
                        if (!ReferenceEquals(callbackCompletionSource, null))
                        {
                            callbackCompletionSource.TrySetResult(true);
                        }
                    }
                }
                catch (Exception exception)
                {
                    if (!ReferenceEquals(_errorHandler, null))
                    {
                        _errorHandler(exception);
                    }
                }
            }
        }