Example #1
0
        internal AsyncProducerConsumerQueue <T> TryEnqueueInternal(T item, CancellationToken ct)
        {
            try
            {
                using (var source = CancellationTokenHelper.Aggregate(completed.Token, ct))
                {
                    using (mutex.Lock())
                    {
                        while (IsFull)
                        {
                            notFull.Wait(source.Token);
                        }

                        if (completed.IsCancellationRequested)
                        {
                            return(null);
                        }

                        queue.Enqueue(item);
                        completedOrNotEmpty.Notify();

                        return(this);
                    }
                }
            }
            catch (OperationCanceledException)
            {
                return(null);
            }
        }
Example #2
0
        public async Task CreateCrisis_RequestOk_ReturnViewModel()
        {
            using var context = new AppDbContext(DbHelper.GetDbContextOptions());
            context.Teams.Add(new Team(name: "Team 1", description: "Description 1"));
            context.Teams.Add(new Team(name: "Team 2", description: "Description 2"));
            context.SaveChanges();
            var request = new CreateCrisisRequest()
            {
                Name        = "test",
                Description = "test",
                TeamIds     = new List <int>()
                {
                    1, 2
                }
            };
            var handler = new CreateCrisisHandler(context);

            var result = await handler.Handle(request, CancellationTokenHelper.GetCancellationToken());

            result.IsSuccess.Should().BeTrue();
            result.Value.Should().BeOfType <BaseCrisisViewModel>();
            result.Value.Name.Should().Be("test");
            result.Value.Id.Should().NotBe(0);
            result.Value.Teams.Count.Should().Be(2);
        }
Example #3
0
        internal async Task <AsyncProducerConsumerQueue <T> > TryEnqueueAsync(T item, CancellationToken ct, TaskCompletionSource abort)
        {
            try
            {
                using (var source = CancellationTokenHelper.Aggregate(completed.Token, ct))
                {
                    using (await mutex.LockAsync().ConfigureAwait(false))
                    {
                        while (IsFull)
                        {
                            await notFull.WaitAsync(source.Token).ConfigureAwait(false);
                        }

                        if (completed.IsCancellationRequested)
                        {
                            return(null);
                        }

                        if (null != abort && false == abort.TrySetCanceled())
                        {
                            return(null);
                        }

                        queue.Enqueue(item);
                        completedOrNotEmpty.Notify();

                        return(this);
                    }
                }
            }
            catch (OperationCanceledException)
            {
                return(null);
            }
        }
Example #4
0
        /// <summary>
        ///
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="queues"></param>
        /// <param name="ct"></param>
        /// <returns></returns>
        public static async Task <AsyncProducerConsumerQueue <T> .DequeueResult> TryDequeueFromAnyAsync <T>(
            this IEnumerable <AsyncProducerConsumerQueue <T> > queues, CancellationToken ct)
        {
            var abort = new TaskCompletionSource();

            using (var cancellation = CancellationTokenHelper.FromTask(abort.Task))
            {
                using (var aggregation = CancellationTokenHelper.Aggregate(cancellation.Token, ct))
                {
                    var token   = aggregation.Token;
                    var tasks   = queues.Select(queue => queue.TryDequeueAsync(token, abort));
                    var results = await Task.WhenAll(tasks).ConfigureAwait(false);

                    var result = results.FirstOrDefault(value => value.Success);

                    if (null != result)
                    {
                        return(result);
                    }

                    ct.ThrowIfCancellationRequested();

                    return(AsyncProducerConsumerQueue <T> .FalseResult);
                }
            }
        }
Example #5
0
        //[MethodImpl(MethodImplOptions.AggressiveInlining)]
        private async ValueTask RunWithTimeout(Func <CancellationToken, ValueTask> action,
                                               CancellationToken originalCancellationToken)
        {
            originalCancellationToken.ThrowIfCancellationRequested();

            var cancellationTokenWithTimeout =
                CancellationTokenHelper.CancellationTokenWithTimeout(ClientConfig.Timeout,
                                                                     originalCancellationToken);

            try
            {
                await action.Invoke(cancellationTokenWithTimeout.Token);
            }
            catch (OperationCanceledException operationCanceledException)
            {
                throw TimeoutOrCancelledException(operationCanceledException, originalCancellationToken);
            }
            catch (SocketException socketException)
            {
                if (socketException.InnerException?.GetType().IsAssignableFrom(typeof(OperationCanceledException)) ==
                    true)
                {
                    throw TimeoutOrCancelledException(socketException.InnerException, originalCancellationToken);
                }

                throw;
            }
            finally
            {
                cancellationTokenWithTimeout.Dispose();
            }
        }
        public async Task <HttpResponseMessage> Delete(string endpoint, NameValuePair deleteParam, CancellationToken?token = null)
        {
            var url = GetUrl(endpoint, out var _);

            try
            {
                var forms = deleteParam != null
                    ? new[] { deleteParam }.AsKeyValuePairs()
                    : new KeyValuePair <string, string> [0];
                using (var content = new FormUrlEncodedContent(forms))
                    using (var request = new HttpRequestMessage(new HttpMethod("DELETE"), url)
                    {
                        Content = content
                    })
                        using (var tokenHelper = new CancellationTokenHelper(token, Timeout))
                        {
                            return(await HttpClient.SendAsync(request, tokenHelper.Token));
                        }
            }
            catch (BacklogException)
            {
                throw;
            }
            catch (Exception ex)
            {
                throw new BacklogApiException("backlog api request failed.", ex);
            }
        }
Example #7
0
        /// <summary>
        /// Blocks the current thread until the next notification
        /// </summary>
        /// <param name="timeout">Tiemout in milliseconds</param>
        /// <param name="token">Cancellation token</param>
        /// <returns>True if the current thread successfully received a notification</returns>
        /// <exception cref="SynchronizationLockException">Lock is not acquired</exception>
        /// <exception cref="ObjectDisposedException">Waiter was disposed</exception>
        /// <exception cref="OperationCanceledException">Cancellation happened</exception>
        /// <exception cref="OperationInterruptedException">Waiting was interrupted by Dispose</exception>
        public bool Wait(int timeout, CancellationToken token)
        {
            if (!Monitor.IsEntered(this))
            {
                throw new SynchronizationLockException("Lock on the current SignalWaiter should be acquired");
            }
            if (_isDisposed)
            {
                throw new ObjectDisposedException(this.GetType().Name);
            }
            if (token.IsCancellationRequested)
            {
                throw new OperationCanceledException(token);
            }

            if (timeout < 0)
            {
                timeout = Timeout.Infinite;
            }


            CancellationTokenRegistration cancellationTokenRegistration = default(CancellationTokenRegistration);

            try
            {
                if (token.CanBeCanceled)
                {
                    cancellationTokenRegistration = CancellationTokenHelper.RegisterWithoutECIfPossible(token, _cancellationTokenCanceledEventHandler, this);
                }

                // Waiting for signal
                if (!Monitor.Wait(this, timeout))
                {
                    return(false);
                }

                // Check if cancellation or dispose was the reasons of the signal
                if (token.IsCancellationRequested)
                {
                    throw new OperationCanceledException(token);
                }
                if (_isDisposed)
                {
                    throw new OperationInterruptedException("Wait was interrupted by Dispose", new ObjectDisposedException(this.GetType().Name));
                }
            }
            finally
            {
                cancellationTokenRegistration.Dispose();
            }

            return(true);
        }
        /// <summary>
        /// Enter the lock on the current <see cref="ConditionVariable"/> object
        /// </summary>
        /// <param name="timeout">Total operation timeout</param>
        /// <param name="token">Cancellation token</param>
        /// <returns>Lock guard to work with 'using' statement</returns>
        /// <exception cref="ObjectDisposedException">ConditionVariable disposed</exception>
        /// <exception cref="OperationCanceledException">Cancellation requested</exception>
        /// <exception cref="SynchronizationLockException">externalLock is already acquired</exception>
        public ConditionVariableWaiter Enter(int timeout, CancellationToken token)
        {
            if (_isDisposed)
            {
                throw new ObjectDisposedException(nameof(ConditionVariable), $"ConditionVariable '{Name}' was disposed");
            }
            if (token.IsCancellationRequested)
            {
                throw new OperationCanceledException(token);
            }
            if (Monitor.IsEntered(_externalLock))
            {
                throw new SynchronizationLockException("Recursive lock is not supported");
            }

            uint startTime = 0;

            if (timeout > 0)
            {
                startTime = TimeoutHelper.GetTimestamp();
            }
            else if (timeout < -1)
            {
                timeout = Timeout.Infinite;
            }


            CancellationTokenRegistration cancellationTokenRegistration = default(CancellationTokenRegistration);

            if (token.CanBeCanceled)
            {
                try
                {
                    cancellationTokenRegistration = CancellationTokenHelper.RegisterWithoutECIfPossible(token, _cancellationTokenCanceledEventHandler, this);
                    Monitor.Enter(_externalLock); // Can be interrupted
                }
                catch
                {
                    cancellationTokenRegistration.Dispose();
                    throw;
                }
            }
            else
            {
                Monitor.Enter(_externalLock);
            }

            Interlocked.Increment(ref _waiterCount);
            return(new ConditionVariableWaiter(this, timeout, startTime, token, cancellationTokenRegistration));
        }
Example #9
0
        private static void TestGeneratedRegister(CancellationToken token, int iter)
        {
            Action <object> act = new Action <object>(Callback);

            var sw = Stopwatch.StartNew();

            for (int i = 0; i < iter; i++)
            {
                using (var reg = CancellationTokenHelper.RegisterWithoutECIfPossible(token, act, null))
                {
                }
            }
            sw.Stop();
            Console.WriteLine($"Generated register: {sw.ElapsedMilliseconds}ms");
        }
Example #10
0
        public async Task CreateCrisis_RequestTeamIdsEmpty_ReturnFail()
        {
            var request = new CreateCrisisRequest()
            {
                Name = "test", TeamIds = new List <int>()
            };

            using var context = new AppDbContext(DbHelper.GetDbContextOptions());
            var handler = new CreateCrisisHandler(context);

            var result = await handler.Handle(request, CancellationTokenHelper.GetCancellationToken());

            result.IsFailed.Should().BeTrue();
            result.WithError("Request team empty");
        }
Example #11
0
        /// <summary>
        /// Enter the lock on the current <see cref="MonitorObject"/> object
        /// </summary>
        /// <param name="timeout">Total operation timeout</param>
        /// <param name="token">Cancellation token</param>
        /// <returns>Lock guard to work with 'using' statement</returns>
        /// <exception cref="ObjectDisposedException">MonitorObject disposed</exception>
        /// <exception cref="OperationCanceledException">Cancellation requested</exception>
        public MonitorWaiter Enter(int timeout, CancellationToken token)
        {
            if (_isDisposed)
            {
                throw new ObjectDisposedException(nameof(MonitorObject), $"MonitorObject '{Name}' was disposed");
            }
            if (token.IsCancellationRequested)
            {
                throw new OperationCanceledException(token);
            }

            uint startTime = 0;

            if (timeout > 0)
            {
                startTime = TimeoutHelper.GetTimestamp();
            }
            else if (timeout < -1)
            {
                timeout = Timeout.Infinite;
            }


            CancellationTokenRegistration cancellationTokenRegistration = default(CancellationTokenRegistration);

            if (token.CanBeCanceled)
            {
                try
                {
                    cancellationTokenRegistration = CancellationTokenHelper.RegisterWithoutECIfPossible(token, _cancellationTokenCanceledEventHandler, this);
                    Monitor.Enter(this); // Can be interrupted
                }
                catch
                {
                    cancellationTokenRegistration.Dispose();
                    throw;
                }
            }
            else
            {
                Monitor.Enter(this);
            }

            Interlocked.Increment(ref _waiterCount);
            return(new MonitorWaiter(this, timeout, startTime, token, cancellationTokenRegistration));
        }
        public async Task <HttpResponseMessage> Post(string endpoint, ICollection <NameValuePair> postParams, CancellationToken?token = null)
        {
            var url = GetUrl(endpoint, out var _);

            try
            {
                using (var content = new FormUrlEncodedContent(postParams.AsKeyValuePairs()))
                    using (var request = CreateRequestMessage(HttpMethod.Post, url, content))
                        using (var tokenHelper = new CancellationTokenHelper(token, Timeout))
                        {
                            return(await HttpClient.SendAsync(request, HttpCompletionOption.ResponseContentRead, tokenHelper.Token));
                        }
            }
            catch (BacklogException)
            {
                throw;
            }
            catch (Exception ex)
            {
                throw new BacklogApiException("backlog api request failed.", ex);
            }
        }
        public override async void OnNavigatedTo(INavigationParameters parameters)
        {
            try
            {
                _cts = CancellationTokenHelper.SetupCancellationToken(_cts);

                switch (parameters.GetNavigationMode())
                {
                case NavigationMode.Back:
                    // TODO: Handle any tasks that should occur only when navigated back to
                    break;

                case NavigationMode.New:
                    IsBusy = true;
                    break;
                }
            }
            catch (Exception ex)
            {
                LogError(ex);
            }
        }
Example #14
0
        public void RegisterWithoutECTest()
        {
            var originalContext = SynchronizationContext.Current;
            var syncContext     = new CustomSyncContext();

            try
            {
                CancellationTokenSource tokenSource = new CancellationTokenSource();
                CancellationToken       token       = tokenSource.Token;

                AtomicBool isNoExecutionContext = new AtomicBool(false);

                using (CancellationTokenHelper.RegisterWithoutECIfPossible(token, (st) =>
                {
                    isNoExecutionContext.Value = SynchronizationContext.Current == null;
                }, null))
                {
                    Barrier barrier  = new Barrier(2);
                    Barrier barrier2 = new Barrier(2);

                    Task.Run(() =>
                    {
                        barrier.SignalAndWait();
                        barrier2.SignalAndWait();
                        tokenSource.Cancel();
                    });

                    barrier.SignalAndWait();
                    SynchronizationContext.SetSynchronizationContext(syncContext);
                    barrier2.SignalAndWait();
                    TimingAssert.IsTrue(10000, isNoExecutionContext, "isNoExecutionContext");
                }
            }
            finally
            {
                SynchronizationContext.SetSynchronizationContext(originalContext);
            }
        }
        public async Task <HttpResponseMessage> Get(string endpoint, GetParams getParams, QueryParams queryParams, CancellationToken?token = null)
        {
            try
            {
                bool paramExists;
                var  url = new StringBuilder(GetUrl(endpoint, out paramExists));
                SetParamString(url, paramExists, (getParams?.Parameters ?? new NameValuePair[0]).Concat(queryParams?.Parameters ?? new NameValuePair[0]));

                using (var request = CreateRequestMessage(HttpMethod.Get, url.ToString()))
                    using (var tokenHelper = new CancellationTokenHelper(token, Timeout))
                    {
                        return(await HttpClient.SendAsync(request, HttpCompletionOption.ResponseContentRead, tokenHelper.Token));
                    }
            }
            catch (BacklogException)
            {
                throw;
            }
            catch (Exception ex)
            {
                throw new BacklogApiException("backlog api request failed.", ex);
            }
        }
        public async Task <HttpResponseMessage> PostMultiPart(string endpoint, ICollection <KeyValuePair <string, object> > postParams, CancellationToken?token = null)
        {
            var url = GetUrl(endpoint, out var _);

            try
            {
                using (var content = new MultipartFormDataContent())
                    using (var tokenHelper = new CancellationTokenHelper(token, Timeout))
                    {
                        foreach (var param in postParams)
                        {
                            if (param.Value is string strValue)
                            {
                                content.Add(new StringContent(strValue), param.Key);
                            }
                            else if (param.Value is AttachmentData attach)
                            {
                                content.Add(new StreamContent(attach.Content), param.Key, attach.FileName);
                            }
                            else
                            {
                                throw new BacklogApiException($"Illegal parameter type name={param.Key},value={param.Value}");
                            }
                        }
                        return(await HttpClient.PostAsync(url, content, tokenHelper.Token));
                    }
            }
            catch (BacklogException)
            {
                throw;
            }
            catch (Exception ex)
            {
                throw new BacklogApiException("backlog api request failed.", ex);
            }
        }
Example #17
0
        public async Task CreateCrisis_NotAllTeamsFound_ReturnFail()
        {
            var context = new AppDbContext(DbHelper.GetDbContextOptions());

            context.Teams.Add(new Team(name: "Team 1", description: "Description 1"));
            context.Teams.Add(new Team(name: "Team 2", description: "Description 2"));
            context.SaveChanges();

            var request = new CreateCrisisRequest()
            {
                Name        = "test",
                Description = "test",
                TeamIds     = new List <int>()
                {
                    1, 2, 3
                }
            };
            var handler = new CreateCrisisHandler(context);

            var result = await handler.Handle(request, CancellationTokenHelper.GetCancellationToken());

            result.IsFailed.Should().BeTrue();
            result.WithError("Not all teams found");
        }
Example #18
0
        /// <summary>
        ///
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="queues"></param>
        /// <param name="item"></param>
        /// <param name="ct"></param>
        /// <returns></returns>
        public static async Task <AsyncProducerConsumerQueue <T> > TryEnqueueToAnyAsync <T>(
            this IEnumerable <AsyncProducerConsumerQueue <T> > queues, T item, CancellationToken ct)
        {
            var abort = new TaskCompletionSource();

            using (var cancellation = CancellationTokenHelper.FromTask(abort.Task))
            {
                using (var aggregation = CancellationTokenHelper.Aggregate(cancellation.Token, ct))
                {
                    var token   = aggregation.Token;
                    var tasks   = queues.Select(queue => queue.TryEnqueueAsync(item, token, abort));
                    var results = await Task.WhenAll(tasks).ConfigureAwait(false);

                    var candidate = results.FirstOrDefault(value => null != value);

                    if (null == candidate)
                    {
                        ct.ThrowIfCancellationRequested();
                    }

                    return(candidate);
                }
            }
        }
Example #19
0
        /// <summary>
        /// Slow path
        /// </summary>
        private bool WaitSlowPath <TState>(WaitPredicate <TState> predicate, TState state, uint startTime, int timeout, CancellationToken token)
        {
            if (token.IsCancellationRequested)
            {
                throw new OperationCanceledException(token);
            }

            if (timeout < 0)
            {
                timeout = Timeout.Infinite;
            }

            if (timeout > 0 && TimeoutHelper.UpdateTimeout(startTime, timeout) <= 0) // Predicate estimation took too much time
            {
                return(false);
            }

            CancellationTokenRegistration cancellationTokenRegistration = default(CancellationTokenRegistration);
            bool internalLockTaken = false;
            bool externalLockTaken = true;

            try
            {
                if (token.CanBeCanceled)
                {
                    cancellationTokenRegistration = CancellationTokenHelper.RegisterWithoutECIfPossible(token, _cancellationTokenCanceledEventHandler, this);
                }

                try { }
                finally
                {
                    Monitor.Enter(_internalLock, ref internalLockTaken);
                    TurboContract.Assert(internalLockTaken, conditionString: "internalLockTaken");
                    _waitCount++;
                }

                if (WaitUntilPredicate(ref internalLockTaken, ref externalLockTaken, predicate, state, startTime, timeout, token))
                {
                    return(true);
                }

                if (token.IsCancellationRequested)
                {
                    throw new OperationCanceledException(token);
                }

                if (_isDisposed)
                {
                    throw new OperationInterruptedException("Wait was interrupted by Dispose", new ObjectDisposedException(this.GetType().Name));
                }
            }
            finally
            {
                if (internalLockTaken)
                {
                    _waitCount--;
                    TurboContract.Assert(_waitCount >= 0, conditionString: "_waitCount >= 0");
                    Monitor.Exit(_internalLock);
                }

                EnterLock(_externalLock, ref externalLockTaken);

                cancellationTokenRegistration.Dispose();
            }

            // Final check for predicate
            return(predicate(state));
        }
Example #20
0
        /// <summary>
        /// Blocks the current thread until the next notification
        /// </summary>
        /// <param name="timeout">Tiemout in milliseconds</param>
        /// <param name="token">Cancellation token</param>
        /// <returns>True if the current thread successfully received a notification</returns>
        /// <exception cref="SynchronizationLockException">externalLock is not acquired or acquired recursively</exception>
        /// <exception cref="ObjectDisposedException">ConditionVariable was disposed</exception>
        /// <exception cref="OperationCanceledException">Cancellation happened</exception>
        /// <exception cref="OperationInterruptedException">Waiting was interrupted by Dispose</exception>
        public bool Wait(int timeout, CancellationToken token)
        {
            if (!Monitor.IsEntered(_externalLock))
            {
                throw new SynchronizationLockException("External lock should be acquired");
            }
            if (_isDisposed)
            {
                throw new ObjectDisposedException(this.GetType().Name);
            }
            if (token.IsCancellationRequested)
            {
                throw new OperationCanceledException(token);
            }

            uint startTime = 0;

            if (timeout > 0)
            {
                startTime = TimeoutHelper.GetTimestamp();
            }
            else if (timeout < 0)
            {
                timeout = Timeout.Infinite;
            }


            CancellationTokenRegistration cancellationTokenRegistration = default(CancellationTokenRegistration);
            bool internalLockTaken = false;
            bool externalLockTaken = true;

            try
            {
                if (token.CanBeCanceled)
                {
                    cancellationTokenRegistration = CancellationTokenHelper.RegisterWithoutECIfPossible(token, _cancellationTokenCanceledEventHandler, this);
                }

                try { }
                finally
                {
                    Monitor.Enter(_internalLock, ref internalLockTaken);
                    TurboContract.Assert(internalLockTaken, conditionString: "internalLockTaken");
                    _waitCount++;
                }

                // Check if cancelled or disposed after entering the lock
                if (token.IsCancellationRequested)
                {
                    throw new OperationCanceledException(token);
                }
                if (_isDisposed)
                {
                    throw new OperationInterruptedException("Wait was interrupted by Dispose", new ObjectDisposedException(this.GetType().Name));
                }

                // Calculate remaining timeout
                int remainingWaitMilliseconds = Timeout.Infinite;
                if (timeout != Timeout.Infinite)
                {
                    remainingWaitMilliseconds = TimeoutHelper.UpdateTimeout(startTime, timeout);
                    if (remainingWaitMilliseconds <= 0)
                    {
                        return(false);
                    }
                }

                // Exit external lock right before Wait
                ExitLock(_externalLock, ref externalLockTaken);

                if (Monitor.IsEntered(_externalLock)) // Sanity check
                {
                    throw new SynchronizationLockException("Recursive lock is not supported");
                }

                // Waiting for signal
                if (!Monitor.Wait(_internalLock, remainingWaitMilliseconds))
                {
                    return(false);
                }

                // Check if cancellation or dispose was the reasons of the signal
                if (token.IsCancellationRequested)
                {
                    throw new OperationCanceledException(token);
                }
                if (_isDisposed)
                {
                    throw new OperationInterruptedException("Wait was interrupted by Dispose", new ObjectDisposedException(this.GetType().Name));
                }
            }
            finally
            {
                if (internalLockTaken)
                {
                    _waitCount--;
                    TurboContract.Assert(_waitCount >= 0, conditionString: "_waitCount >= 0");
                    Monitor.Exit(_internalLock);
                }

                EnterLock(_externalLock, ref externalLockTaken);

                cancellationTokenRegistration.Dispose();
            }

            return(true);
        }
Example #21
0
        /// <summary>
        /// Blocks the current thread until predicate estimates as True
        /// </summary>
        /// <typeparam name="TState">Type of the state object</typeparam>
        /// <param name="predicate">Predicate that should return True to complete waiting</param>
        /// <param name="state">State object for the predicate</param>
        /// <param name="timeout">Tiemout in milliseconds</param>
        /// <param name="token">Cancellation token</param>
        /// <returns>True if predicate evaluates to True</returns>
        /// <exception cref="ArgumentNullException">predicate is null</exception>
        /// <exception cref="SynchronizationLockException">Lock is not acquired</exception>
        /// <exception cref="ObjectDisposedException">Waiter was disposed</exception>
        /// <exception cref="OperationCanceledException">Cancellation happened</exception>
        /// <exception cref="OperationInterruptedException">Waiting was interrupted by Dispose</exception>
        public bool Wait <TState>(WaitPredicate <TState> predicate, TState state, int timeout, CancellationToken token)
        {
            if (predicate == null)
            {
                throw new ArgumentNullException(nameof(predicate));
            }
            if (!Monitor.IsEntered(this))
            {
                throw new SynchronizationLockException("External lock should be acquired");
            }
            if (_isDisposed)
            {
                throw new ObjectDisposedException(this.GetType().Name);
            }
            if (token.IsCancellationRequested)
            {
                throw new OperationCanceledException(token);
            }

            uint startTime = 0;

            if (timeout > 0)
            {
                startTime = TimeoutHelper.GetTimestamp();
            }
            else if (timeout < -1)
            {
                timeout = Timeout.Infinite;
            }

            if (predicate(state))
            {
                return(true);
            }

            if (timeout == 0)
            {
                return(false);
            }

            if (timeout > 0 && TimeoutHelper.UpdateTimeout(startTime, timeout) <= 0) // Predicate estimation took too much time
            {
                return(false);
            }

            CancellationTokenRegistration cancellationTokenRegistration = default(CancellationTokenRegistration);

            try
            {
                if (token.CanBeCanceled)
                {
                    cancellationTokenRegistration = CancellationTokenHelper.RegisterWithoutECIfPossible(token, _cancellationTokenCanceledEventHandler, this);
                }

                if (WaitUntilPredicate(predicate, state, startTime, timeout, token))
                {
                    return(true);
                }

                if (token.IsCancellationRequested)
                {
                    throw new OperationCanceledException(token);
                }

                if (_isDisposed)
                {
                    throw new OperationInterruptedException("Wait was interrupted by Dispose", new ObjectDisposedException(this.GetType().Name));
                }
            }
            finally
            {
                cancellationTokenRegistration.Dispose();
            }

            // Final check for predicate
            return(predicate(state));
        }
Example #22
0
 /// <summary>
 /// Helper method to register notification for token cancellation
 /// </summary>
 /// <param name="token">Cancellation token</param>
 /// <returns>Registration info</returns>
 internal CancellationTokenRegistration RegisterNotificationOnCancellation(CancellationToken token)
 {
     return(CancellationTokenHelper.RegisterWithoutECIfPossible(token, _cancellationTokenCanceledEventHandler, this));
 }
Example #23
0
        /// <summary>
        /// Blocks the current thread until it can enter the semaphore
        /// </summary>
        /// <param name="timeout">Tiemout in milliseconds</param>
        /// <param name="token">Cancellation token</param>
        /// <param name="throwOnCancellation">Whether the OperationCanceledException should be thrown if cancellation happened</param>
        /// <returns>True if the current thread successfully entered the semaphore</returns>
        internal bool Wait(int timeout, CancellationToken token, bool throwOnCancellation)
        {
            if (_isDisposed)
            {
                throw new ObjectDisposedException(this.GetType().Name);
            }

            if (token.IsCancellationRequested)
            {
                if (throwOnCancellation)
                {
                    throw new OperationCanceledException(token);
                }

                return(false);
            }

            // Делаем захват
            if (TryTakeLockFree())
            {
                return(true);
            }

            // Early exit: nothing to wait
            if (timeout == 0 && _waitCount >= _currentCountForWait)
            {
                return(false);
            }

            uint startTime = 0;

            if (timeout > 0)
            {
                startTime = TimeoutHelper.GetTimestamp();
            }
            else if (timeout < -1)
            {
                timeout = Timeout.Infinite;
            }

            // Ждём появления (лучше активно подождать, чем входить в lock)
            if (_waitCount >= _currentCountForWait)
            {
                if (timeout == 0) // Редкая ситуация. При нулевом таймауте нам нечего ловить
                {
                    return(false);
                }

                int spinNumber          = _processorCount > 1 ? 0 : SPIN_YIELD_THRESHOLD; // Пропускаем активное ожидание, если только одно ядро доступно
                int currentCountLocFree = _currentCountLockFree;
                while (spinNumber < SPIN_YIELD_THRESHOLD + 8)
                {
                    if (currentCountLocFree > 0 && Interlocked.CompareExchange(ref _currentCountLockFree, currentCountLocFree - 1, currentCountLocFree) == currentCountLocFree)
                    {
                        return(true);
                    }

                    SpinOnce(spinNumber);
                    if (spinNumber < SPIN_YIELD_THRESHOLD && _waitCount > _currentCountForWait + 2) // Жгём CPU только если немного потоков в ожидании. Иначе лучше на Thread.Yield переходить
                    {
                        spinNumber = SPIN_YIELD_THRESHOLD;
                    }
                    else
                    {
                        spinNumber++;
                    }

                    currentCountLocFree = _currentCountLockFree;
                }

                // Пробуем захватить ещё раз
                if (currentCountLocFree > 0 && Interlocked.CompareExchange(ref _currentCountLockFree, currentCountLocFree - 1, currentCountLocFree) == currentCountLocFree)
                {
                    return(true);
                }
            }

            // Вынуждены уходить в lock
            CancellationTokenRegistration cancellationTokenRegistration = default(CancellationTokenRegistration);
            bool lockTaken = false;

            try
            {
                if (token.CanBeCanceled)
                {
                    cancellationTokenRegistration = CancellationTokenHelper.RegisterWithoutECIfPossible(token, _cancellationTokenCanceledEventHandler, this);
                }

                try { }
                finally
                {
                    Monitor.Enter(_lockObj, ref lockTaken);
                    TurboContract.Assert(lockTaken, conditionString: "lockTaken");
                    Interlocked.Increment(ref _waitCount); // Release должен увидеть наше появление
                }

                // Пробуем забрать из _currentCountForWait
                if (_currentCountForWait > 0)
                {
                    _currentCountForWait--;
                    return(true);
                }

                // Пока входили в lock могли добавится значения в _currentCountLocFree
                if (TryTakeLockFree())
                {
                    return(true);
                }

                if (timeout == 0)
                {
                    return(false);
                }

                // Ожидаем появления элементов и забираем сразу
                if (WaitUntilCountOrTimeoutAndTake(timeout, startTime, token))
                {
                    return(true);
                }

                if (token.IsCancellationRequested)
                {
                    if (throwOnCancellation)
                    {
                        throw new OperationCanceledException(token);
                    }

                    return(false);
                }

                if (_isDisposed)
                {
                    throw new OperationInterruptedException("Semaphore wait was interrupted by Dispose", new ObjectDisposedException(this.GetType().Name));
                }
            }
            finally
            {
                if (lockTaken)
                {
                    _waitCount--;
                    TurboContract.Assert(_waitCount >= 0, conditionString: "_waitCount >= 0");
                    Monitor.Exit(_lockObj);
                }

                cancellationTokenRegistration.Dispose();
            }

            return(false);
        }
Example #24
0
        /// <summary>
        /// Blocks the current thread if it is required
        /// </summary>
        /// <param name="timeout">Waiting timeout in milliseconds</param>
        /// <param name="token">Cancellation token</param>
        /// <returns>True if the current thread successfully passed the <see cref="PartialThreadBlocker"/> (false - exited by timeout)</returns>
        public bool Wait(int timeout, CancellationToken token)
        {
            token.ThrowIfCancellationRequested();
            if (timeout < 0)
            {
                timeout = Timeout.Infinite;
            }

            if (_realWaiterCount >= _expectedWaiterCount)
            {
                return(true);
            }

            if (timeout == 0)
            {
                return(false);
            }

            uint startTime   = 0;
            int  currentTime = Timeout.Infinite;

            if (timeout != Timeout.Infinite)
            {
                startTime = TimeoutHelper.GetTimestamp();
            }

            for (int i = 0; i < 10; i++)
            {
                if (_realWaiterCount >= _expectedWaiterCount)
                {
                    return(true);
                }

                if (i == 5)
                {
                    Thread.Yield();
                }
                else
                {
                    Thread.SpinWait(150 + (4 << i));
                }
            }


            using (CancellationTokenHelper.RegisterWithoutECIfPossible(token, _cancellationTokenCanceledEventHandler, this))
            {
                lock (_lockObj)
                {
                    if (_realWaiterCount < _expectedWaiterCount)
                    {
                        try
                        {
                            _realWaiterCount++;

                            while (_realWaiterCount <= _expectedWaiterCount)
                            {
                                token.ThrowIfCancellationRequested();

                                if (timeout != Timeout.Infinite)
                                {
                                    currentTime = TimeoutHelper.UpdateTimeout(startTime, timeout);
                                    if (currentTime <= 0)
                                    {
                                        return(false);
                                    }
                                }

                                if (!Monitor.Wait(_lockObj, currentTime))
                                {
                                    return(false);
                                }
                            }
                        }
                        finally
                        {
                            _realWaiterCount--;
                        }
                    }
                }
            }
            return(true);
        }
Example #25
0
        /// <summary>
        /// Blocks the current thread until it can enter the semaphore
        /// </summary>
        /// <param name="timeout">Tiemout in milliseconds</param>
        /// <param name="token">Cancellation token</param>
        /// <param name="throwOnCancellation">Whether the OperationCanceledException should be thrown if cancellation happened</param>
        /// <returns>True if the current thread successfully entered the semaphore</returns>
        internal bool Wait(int timeout, CancellationToken token, bool throwOnCancellation)
        {
            if (_isDisposed)
            {
                throw new ObjectDisposedException(this.GetType().Name);
            }

            if (token.IsCancellationRequested)
            {
                if (throwOnCancellation)
                {
                    throw new OperationCanceledException(token);
                }

                return(false);
            }

            // Делаем захват
            if (TryTakeLockFree())
            {
                return(true);
            }

            // Early exit: nothing to wait
            if (timeout == 0 && _waitCount >= _currentCountForWait)
            {
                return(false);
            }

            uint startTime = 0;

            if (timeout > 0)
            {
                startTime = TimeoutHelper.GetTimestamp();
            }
            else if (timeout < -1)
            {
                timeout = Timeout.Infinite;
            }


            // Ждём появления (лучше активно подождать, чем входить в lock)
            if (_processorCount > 1)
            {
                int currentCountLocFree = _currentCountLockFree;
                if (_waitCount >= _currentCountForWait && _waitCount <= _currentCountForWait + 2)
                {
                    for (int i = 0; i < 8; i++)
                    {
                        if (currentCountLocFree > 0 && Interlocked.CompareExchange(ref _currentCountLockFree, currentCountLocFree - 1, currentCountLocFree) == currentCountLocFree)
                        {
                            return(true);
                        }

                        Thread.SpinWait(150 + 16 * i);
                        currentCountLocFree = _currentCountLockFree;
                    }
                }

                // Пробуем захватить ещё раз
                if (currentCountLocFree > 0 && Interlocked.CompareExchange(ref _currentCountLockFree, currentCountLocFree - 1, currentCountLocFree) == currentCountLocFree)
                {
                    return(true);
                }
            }


            if (timeout == 0 && _waitCount >= _currentCountForWait)
            {
                return(false);
            }

            if (_waitCount >= _currentCountForWait)
            {
                Thread.Yield();

                int currentCountLocFree = _currentCountLockFree;
                if (currentCountLocFree > 0 && Interlocked.CompareExchange(ref _currentCountLockFree, currentCountLocFree - 1, currentCountLocFree) == currentCountLocFree)
                {
                    return(true);
                }
            }

            // Вынуждены уходить в lock
            CancellationTokenRegistration cancellationTokenRegistration = default(CancellationTokenRegistration);
            bool lockTaken = false;

            try
            {
                if (token.CanBeCanceled)
                {
                    cancellationTokenRegistration = CancellationTokenHelper.RegisterWithoutECIfPossible(token, _cancellationTokenCanceledEventHandler, this);
                }

                try { }
                finally
                {
                    Monitor.Enter(_lockObj, ref lockTaken);
                    TurboContract.Assert(lockTaken, conditionString: "lockTaken");
                    Interlocked.Increment(ref _waitCount); // Release должен увидеть наше появление
                }

                // Пробуем забрать из _currentCountForWait
                if (_currentCountForWait > 0)
                {
                    _currentCountForWait--;
                    return(true);
                }

                // Пока входили в lock могли добавится значения в _currentCountLocFree
                if (TryTakeLockFree())
                {
                    return(true);
                }

                if (timeout == 0)
                {
                    return(false);
                }

                // Ожидаем появления элементов и забираем сразу
                if (WaitUntilCountOrTimeoutAndTake(timeout, startTime, token))
                {
                    return(true);
                }

                if (token.IsCancellationRequested)
                {
                    if (throwOnCancellation)
                    {
                        throw new OperationCanceledException(token);
                    }

                    return(false);
                }

                if (_isDisposed)
                {
                    throw new OperationInterruptedException("Semaphore wait was interrupted by Dispose", new ObjectDisposedException(this.GetType().Name));
                }
            }
            finally
            {
                if (lockTaken)
                {
                    _waitCount--;
                    TurboContract.Assert(_waitCount >= 0, conditionString: "_waitCount >= 0");
                    Monitor.Exit(_lockObj);
                }

                cancellationTokenRegistration.Dispose();
            }

            return(false);
        }