private async Task StartAsyncCore(CancellationToken cancellationToken) { ListenerFactoryContext context = new ListenerFactoryContext(cancellationToken); _listener = await _factory.CreateAsync(context); _cancellationRegistration = _cancellationSource.Token.Register(_listener.Cancel); await _listener.StartAsync(cancellationToken); }
/// <summary> /// If AutoSaveChanges is set this method will auto commit changes /// </summary> /// <param name="cancellationToken"></param> /// <returns></returns> protected virtual Task<int> SaveChanges(CancellationToken cancellationToken) { var source = new TaskCompletionSource<int>(); if (AutoSaveChanges) { var registration = new CancellationTokenRegistration(); if (cancellationToken.CanBeCanceled) { if (cancellationToken.IsCancellationRequested) { source.SetCanceled(); return source.Task; } registration = cancellationToken.Register(CancelIgnoreFailure); } try { return _uow.SaveChangesAsync(cancellationToken); } catch (Exception e) { source.SetException(e); } finally { registration.Dispose(); } } return source.Task; }
public void DefaultCancellationTokenRegistration() { var registration = new CancellationTokenRegistration (); // shouldn't throw registration.Dispose (); }
protected ScheduledAsyncTask(AbstractScheduledEventExecutor executor, PreciseDeadline deadline, TaskCompletionSource promise, CancellationToken cancellationToken) : base(executor, deadline, promise) { _cancellationToken = cancellationToken; _cancellationTokenRegistration = cancellationToken.Register(CancellationAction, this); }
internal IrcNetworkStream(IIrcClient client) { _streamReader = new StreamReader(client.GetClientStream()); _streamWriter = new StreamWriter(client.GetClientStream()); _cancellationRegistration = _cancellationToken.Register(TaskRequestErrorCallback); }
public RSessionRequestSource(bool isVisible, CancellationToken ct) { _createRequestTcs = new TaskCompletionSourceEx<IRSessionInteraction>(); _responseTcs = new TaskCompletionSourceEx<object>(); _cancellationTokenRegistration = ct.Register(() => _createRequestTcs.TrySetCanceled(cancellationToken:ct)); IsVisible = isVisible; }
internal SchedulerOperationAwaiter(Func<Action, IDisposable> schedule, CancellationToken cancellationToken, bool postBackToOriginalContext) { _schedule = schedule; _cancellationToken = cancellationToken; _postBackToOriginalContext = postBackToOriginalContext; _ctr = _cancellationToken.Register(Cancel); }
public Http2ClientStream(int id, Priority priority, WriteQueue writeQueue, HeaderWriter headerWriter, CancellationToken cancel) : base(id, writeQueue, headerWriter, cancel) { _priority = priority; _responseTask = new TaskCompletionSource<IList<KeyValuePair<string, string>>>(); _outputStream = new OutputStream(id, _priority, writeQueue); _cancellation = _cancel.Register(Cancel, this); }
public void TypePropertiesForCancellationTokenRegistrationAreCorrect() { Assert.AreEqual(typeof(CancellationTokenRegistration).GetClassName(), "Bridge.CancellationTokenRegistration", "FullName"); object ctr = new CancellationTokenRegistration(); Assert.True(ctr is CancellationTokenRegistration, "CancellationTokenRegistration"); Assert.True(ctr is IDisposable, "IDisposable"); Assert.True(ctr is IEquatable<CancellationTokenRegistration>, "IEquatable<CancellationTokenRegistration>"); }
internal VerifierDialog(MainWindow parentWindow) : base(parentWindow, null) { InitializeComponent(); this.m_mainwindow = parentWindow; this.m_tcs = new TaskCompletionSource<object>(); this.m_cancel = DialogSettings.CancellationToken.Register(() => this.m_tcs.TrySetResult(null)); }
internal ClientSelectionDialog(MetroWindow parentWindow) : base(parentWindow, null) { InitializeComponent(); this.ctlList.ItemsSource = SongInfo.LastResult; this.m_tcs = new TaskCompletionSource<object>(); this.m_cancel = DialogSettings.CancellationToken.Register(() => this.m_tcs.TrySetResult(null)); }
internal ADSelectionDialog(MetroWindow parentWindow) : base(parentWindow, null) { InitializeComponent(); this.ctlList.ItemsSource = IParseRule.RulesPlayer; this.m_tcs = new TaskCompletionSource<object>(); this.m_cancel = DialogSettings.CancellationToken.Register(() => this.m_tcs.TrySetResult(null)); }
public Task RunAsync(IEnumerable<ITest> selectedTests, IProgress<double> progress, TextWriter output, CancellationToken cancellationToken) { this.progress = progress; this.output = output; progressPerTest = 1.0 / GetExpectedNumberOfTestResults(selectedTests); tcs = new TaskCompletionSource<object>(); Start(selectedTests); cancellationTokenRegistration = cancellationToken.Register(Cancel, true); return tcs.Task; }
public StopSignal() { _stopRequested = new TaskCompletionSource<bool>(); _stopToken = new CancellationTokenSource(); _registration = _stopToken.Token.Register(() => { _stopRequested.TrySetResult(true); _registration.Dispose(); }); }
public void RunJob(BuildJob job, IMSBuildChainedLoggerFilter loggerChain, Action<bool> reportWhenDone, CancellationToken cancellationToken) { Debug.Assert(loggerChain != null); this.loggerChain = loggerChain; this.reportWhenDone = reportWhenDone; try { process.Writer.Write("StartBuild"); job.WriteTo(process.Writer); this.cancellationRegistration = cancellationToken.Register(OnCancel); } catch (IOException ex) { // "Pipe is broken" loggerChain.HandleError(new BuildError(null, 0, 0, null, "Error talking to build worker: " + ex.Message)); BuildDone(false); } }
public RabbitMqBasicConsumer(ModelContext model, Uri inputAddress, IPipe<ReceiveContext> receivePipe, IReceiveObserver receiveObserver, CancellationToken cancellationToken) { _model = model; _inputAddress = inputAddress; _receivePipe = receivePipe; _receiveObserver = receiveObserver; _receiveSettings = model.GetPayload<ReceiveSettings>(); _pending = new ConcurrentDictionary<ulong, RabbitMqReceiveContext>(); _consumerComplete = new TaskCompletionSource<RabbitMqConsumerMetrics>(); _registration = cancellationToken.Register(Complete); }
// Similar to TaskFactory.FromAsync, except it supports cancellation using ICancellableAsyncResult. public static Task FromAsync(Func<AsyncCallback, object, ICancellableAsyncResult> beginMethod, Action<IAsyncResult> endMethod, CancellationToken cancellationToken) { TaskCompletionSource<object> source = new TaskCompletionSource<object>(); CancellationTokenRegistration cancellationRegistration = new CancellationTokenRegistration(); bool cancellationRegistrationDisposed = false; object cancellationRegistrationLock = new object(); ICancellableAsyncResult result = beginMethod.Invoke((ar) => { lock (cancellationRegistrationLock) { cancellationRegistration.Dispose(); cancellationRegistrationDisposed = true; } try { endMethod.Invoke(ar); source.SetResult(null); } catch (OperationCanceledException) { source.SetCanceled(); } catch (Exception exception) { source.SetException(exception); } }, null); lock (cancellationRegistrationLock) { if (!cancellationRegistrationDisposed) { cancellationRegistration = cancellationToken.Register(result.Cancel); } } if (result.CompletedSynchronously) { System.Diagnostics.Debug.Assert(source.Task.IsCompleted); } return source.Task; }
public OpenSession(EsentStorage storage, string databaseFile, CancellationToken shutdownCancellationToken) { _storage = storage; #if false id = Interlocked.Increment(ref globalId); System.Diagnostics.Trace.WriteLine("open sessionId: " + id); #endif _session = new Session(storage._instance); _databaseFile = databaseFile; _databaseId = OpenExistingDatabase(_session, databaseFile); _shutdownCancellationToken = shutdownCancellationToken; _cancellationTokenRegistration = shutdownCancellationToken.Register(() => Dispose(), useSynchronizationContext: false); }
/// <summary> /// Creates new threadpool with given settings and cancel token values /// </summary> /// <param name="settings">thread pool runtime settings</param> /// <param name="cancelToken">cancel token to indicate or send stop event to the pool</param> public CustomThreadPool3(ThreadPoolSettings settings, CancellationToken cancelToken) : base(settings, cancelToken) { _settings = settings; _linkedCts = CancellationTokenSource.CreateLinkedTokenSource(cancelToken); this._poolStopToken = _linkedCts.Token; _tokenRegister = _poolStopToken.Register(OnPoolCancelRequested); //start minimum required threads immediately _mThreads = new Thread[_settings.MaxThreads]; _mThreadLocalQueues = new ThreadLocalStealQueue<ThreadPoolWorkItem>[_settings.MaxThreads]; for (int i = 0; i < _settings.MinThreads; i++) { StartNewThread(true); } EtwLogger.Log.PoolStarted(Name, _settings.MinThreads, _settings.MaxThreads); }
/// <summary> /// Construct socket and open connection to a specified server. /// </summary> /// <param name="log">Logging facility for verbose messaging of actions.</param> /// <param name="endpoint">The IP endpoint to connect to.</param> /// <param name="maximumReconnectionTimeout">The maximum time to wait when backing off on reconnection attempts.</param> public KafkaTcpSocket(IKafkaLog log, KafkaEndpoint endpoint, TimeSpan? maximumReconnectionTimeout = null) { _log = log; _endpoint = endpoint; _maximumReconnectionTimeout = maximumReconnectionTimeout ?? TimeSpan.FromMinutes(MaxReconnectionTimeoutMinutes); _sendTaskQueue = new AsyncCollection<SocketPayloadSendTask>(); _readTaskQueue = new AsyncCollection<SocketPayloadReadTask>(); //dedicate a long running task to the read/write operations _socketTask = Task.Run(async () => { await DedicatedSocketTask(); }); _disposeTask = _disposeToken.Token.CreateTask(); _disposeRegistration = _disposeToken.Token.Register(() => { _sendTaskQueue.CompleteAdding(); _readTaskQueue.CompleteAdding(); }); }
public void AllowCancellation(SafeHandle handle, NativeOverlapped* overlapped) { Contract.Assert(handle != null, "Handle cannot be null"); Contract.Assert(!handle.IsInvalid, "Handle cannot be invalid"); Contract.Assert(overlapped != null, "Overlapped cannot be null"); Contract.Assert(this._handle == null && this._overlapped == null, "Cancellation is already allowed."); if (!_cancellationToken.CanBeCanceled) { return; } this._handle = handle; this._overlapped = overlapped; if (this._cancellationToken.IsCancellationRequested) { this.Cancel(); } else { this._cancellationRegistration = this._cancellationToken.Register(Cancel); } }
/// <summary> /// Construct socket and open connection to a specified server. /// </summary> /// <param name="log">Logging facility for verbose messaging of actions.</param> /// <param name="endpoint">The IP endpoint to connect to.</param> /// <param name="maximumReconnectionTimeout">The maximum time to wait when backing off on reconnection attempts.</param> public KafkaTcpSocket(IKafkaLog log, KafkaEndpoint endpoint, TimeSpan? maximumReconnectionTimeout = null) { _log = log; _endpoint = endpoint; _maximumReconnectionTimeout = maximumReconnectionTimeout ?? TimeSpan.FromMinutes(MaxReconnectionTimeoutMinutes); _sendTaskQueue = new AsyncCollection<SocketPayloadSendTask>(); _readTaskQueue = new AsyncCollection<SocketPayloadReadTask>(); //dedicate a long running task to the read/write operations _socketTask = Task.Factory.StartNew(DedicatedSocketTask, CancellationToken.None, TaskCreationOptions.LongRunning, TaskScheduler.Default); _disposeRegistration = _disposeToken.Token.Register(() => { _sendTaskQueue.CompleteAdding(); _readTaskQueue.CompleteAdding(); }); }
protected TransferControllerBase(TransferScheduler transferScheduler, TransferJob transferJob, CancellationToken userCancellationToken) { if (null == transferScheduler) { throw new ArgumentNullException("transferScheduler"); } if (null == transferJob) { throw new ArgumentNullException("transferJob"); } this.Scheduler = transferScheduler; this.TransferJob = transferJob; this.transferSchedulerCancellationTokenRegistration = this.Scheduler.CancellationTokenSource.Token.Register(this.CancelWork); this.userCancellationTokenRegistration = userCancellationToken.Register(this.CancelWork); this.TaskCompletionSource = new TaskCompletionSource<object>(); }
public CustomThreadPool2(ThreadPoolSettings settings, CancellationToken cancelToken) : base(settings, cancelToken) { if (settings == null) throw new ArgumentNullException("settings"); this._settings = settings; _workerKeys = new List<string>(settings.MaxThreads); //initialize min threads immediately for (int i = 0; i < settings.MinThreads; i++) { var w = AllocDelegate(); w.IsPermenant = true; _workerThreads.TryAdd(w.Name, w); _workerKeys.Add(w.Name); } _linkedCts = CancellationTokenSource.CreateLinkedTokenSource(cancelToken); this._poolStopToken = _linkedCts.Token; _tokenRegister = _poolStopToken.Register(OnPoolCancelRequested); EtwLogger.Log.PoolStarted(Name, _settings.MinThreads, _settings.MaxThreads); }
public static Task Delay(int dueTimeMs, CancellationToken cancellationToken) { if (dueTimeMs < -1) throw new ArgumentOutOfRangeException("dueTimeMs", "Invalid due time"); if (cancellationToken.IsCancellationRequested) return preCanceledTask; if (dueTimeMs == 0) return preCompletedTask; var tcs = new TaskCompletionSource<object>(); var ctr = new CancellationTokenRegistration(); var timer = new Timer(self => { ctr.Dispose(); ((Timer) self).Dispose(); tcs.TrySetResult(null); }); if (cancellationToken.CanBeCanceled) ctr = cancellationToken.Register(() => { timer.Dispose(); tcs.TrySetCanceled(); }); timer.Change(dueTimeMs, -1); return tcs.Task; }
public Receiver(MessageReceiver messageReceiver, Uri inputAddress, IPipe<ReceiveContext> receivePipe, ReceiveSettings receiveSettings, IReceiveObserver receiveObserver, CancellationToken cancellationToken) { _messageReceiver = messageReceiver; _inputAddress = inputAddress; _receivePipe = receivePipe; _receiveSettings = receiveSettings; _receiveObserver = receiveObserver; _completeTask = new TaskCompletionSource<ReceiverMetrics>(); _registration = cancellationToken.Register(Shutdown); var options = new OnMessageOptions { AutoComplete = false, AutoRenewTimeout = receiveSettings.AutoRenewTimeout, MaxConcurrentCalls = receiveSettings.MaxConcurrentCalls, }; options.ExceptionReceived += (sender, x) => _completeTask.TrySetException(x.Exception); messageReceiver.OnMessageAsync(OnMessage, options); }
public virtual Task<object> ExecuteScalarAsync(CancellationToken cancellationToken) { if (cancellationToken.IsCancellationRequested) { return ADP.CreatedTaskWithCancellation<object>(); } else { CancellationTokenRegistration registration = new CancellationTokenRegistration(); if (cancellationToken.CanBeCanceled) { registration = cancellationToken.Register(CancelIgnoreFailure); } try { return Task.FromResult<object>(ExecuteScalar()); } catch (Exception e) { registration.Dispose(); return ADP.CreatedTaskWithException<object>(e); } } }
protected virtual Task<DbDataReader> ExecuteDbDataReaderAsync(CommandBehavior behavior, CancellationToken cancellationToken) { if (cancellationToken.IsCancellationRequested) { return ADP.CreatedTaskWithCancellation<DbDataReader>(); } else { CancellationTokenRegistration registration = new CancellationTokenRegistration(); if (cancellationToken.CanBeCanceled) { registration = cancellationToken.Register(CancelIgnoreFailure); } try { return Task.FromResult<DbDataReader>(ExecuteReader(behavior)); } catch (Exception e) { registration.Dispose(); return ADP.CreatedTaskWithException<DbDataReader>(e); } } }
private void DeactivateActiveRequest( SafeCurlMultiHandle multiHandle, EasyRequest easy, IntPtr gcHandlePtr, CancellationTokenRegistration cancellationRegistration) { // Remove the operation from the multi handle so we can shut down the multi handle cleanly int removeResult = Interop.libcurl.curl_multi_remove_handle(multiHandle, easy._easyHandle); Debug.Assert(removeResult == CURLMcode.CURLM_OK, "Failed to remove easy handle"); // ignore cleanup errors in release // Release the associated GCHandle so that it's not kept alive forever if (gcHandlePtr != IntPtr.Zero) { try { GCHandle.FromIntPtr(gcHandlePtr).Free(); _activeOperations.Remove(gcHandlePtr); } catch (InvalidOperationException) { Debug.Fail("Couldn't get/free the GCHandle for an active operation while shutting down due to failure"); } } // Undo cancellation registration cancellationRegistration.Dispose(); }
CancellationTokenRegistration GetTokenReg () { CancellationTokenRegistration registration = new CancellationTokenRegistration (Interlocked.Increment (ref currId), this); return registration; }
/// <summary> /// Blocks the current thread until it can enter the <see cref="SemaphoreSlim"/>, /// using a 32-bit signed integer to measure the time interval, /// while observing a <see cref="T:System.Threading.CancellationToken"/>. /// </summary> /// <param name="millisecondsTimeout">The number of milliseconds to wait, or <see cref="Timeout.Infinite"/>(-1) to /// wait indefinitely.</param> /// <param name="cancellationToken">The <see cref="T:System.Threading.CancellationToken"/> to observe.</param> /// <returns>true if the current thread successfully entered the <see cref="SemaphoreSlim"/>; otherwise, false.</returns> /// <exception cref="ArgumentOutOfRangeException"><paramref name="millisecondsTimeout"/> is a negative number other than -1, /// which represents an infinite time-out.</exception> /// <exception cref="System.OperationCanceledException"><paramref name="cancellationToken"/> was canceled.</exception> public bool Wait(int millisecondsTimeout, CancellationToken cancellationToken) { CheckDispose(); // Validate input if (millisecondsTimeout < -1) { throw new ArgumentOutOfRangeException( "totalMilliSeconds", millisecondsTimeout, SR.SemaphoreSlim_Wait_TimeoutWrong); } cancellationToken.ThrowIfCancellationRequested(); uint startTime = 0; if (millisecondsTimeout != Timeout.Infinite && millisecondsTimeout > 0) { startTime = TimeoutHelper.GetTime(); } bool waitSuccessful = false; Task <bool> asyncWaitTask = null; bool lockTaken = false; //Register for cancellation outside of the main lock. //NOTE: Register/deregister inside the lock can deadlock as different lock acquisition orders could // occur for (1)this.m_lockObj and (2)cts.internalLock CancellationTokenRegistration cancellationTokenRegistration = cancellationToken.InternalRegisterWithoutEC(s_cancellationTokenCanceledEventHandler, this); try { // Perf: first spin wait for the count to be positive, but only up to the first planned yield. // This additional amount of spinwaiting in addition // to Monitor.Enter()’s spinwaiting has shown measurable perf gains in test scenarios. // SpinWait spin = new SpinWait(); while (m_currentCount == 0 && !spin.NextSpinWillYield) { spin.SpinOnce(); } // entering the lock and incrementing waiters must not suffer a thread-abort, else we cannot // clean up m_waitCount correctly, which may lead to deadlock due to non-woken waiters. try { } finally { Monitor.Enter(m_lock, ref lockTaken); if (lockTaken) { m_waitCount++; } } // If there are any async waiters, for fairness we'll get in line behind // then by translating our synchronous wait into an asynchronous one that we // then block on (once we've released the lock). if (m_asyncHead != null) { Contract.Assert(m_asyncTail != null, "tail should not be null if head isn't"); asyncWaitTask = WaitAsync(millisecondsTimeout, cancellationToken); } // There are no async waiters, so we can proceed with normal synchronous waiting. else { // If the count > 0 we are good to move on. // If not, then wait if we were given allowed some wait duration OperationCanceledException oce = null; if (m_currentCount == 0) { if (millisecondsTimeout == 0) { return(false); } // Prepare for the main wait... // wait until the count become greater than zero or the timeout is expired try { waitSuccessful = WaitUntilCountOrTimeout(millisecondsTimeout, startTime, cancellationToken); } catch (OperationCanceledException e) { oce = e; } } // Now try to acquire. We prioritize acquisition over cancellation/timeout so that we don't // lose any counts when there are asynchronous waiters in the mix. Asynchronous waiters // defer to synchronous waiters in priority, which means that if it's possible an asynchronous // waiter didn't get released because a synchronous waiter was present, we need to ensure // that synchronous waiter succeeds so that they have a chance to release. Contract.Assert(!waitSuccessful || m_currentCount > 0, "If the wait was successful, there should be count available."); if (m_currentCount > 0) { waitSuccessful = true; m_currentCount--; } else if (oce != null) { throw oce; } // Exposing wait handle which is lazily initialized if needed if (m_waitHandle != null && m_currentCount == 0) { m_waitHandle.Reset(); } } } finally { // Release the lock if (lockTaken) { m_waitCount--; Monitor.Exit(m_lock); } // Unregister the cancellation callback. cancellationTokenRegistration.Dispose(); } // If we had to fall back to asynchronous waiting, block on it // here now that we've released the lock, and return its // result when available. Otherwise, this was a synchronous // wait, and whether we successfully acquired the semaphore is // stored in waitSuccessful. return((asyncWaitTask != null) ? asyncWaitTask.GetAwaiter().GetResult() : waitSuccessful); }
public bool Wait(int millisecondsTimeout, CancellationToken cancellationToken) { this.CheckDispose(); if (millisecondsTimeout < -1) { throw new ArgumentOutOfRangeException("totalMilliSeconds", millisecondsTimeout, GetResourceString("SemaphoreSlim_Wait_TimeoutWrong")); } cancellationToken.ThrowIfCancellationRequested(); long startTimeTicks = 0L; if ((millisecondsTimeout != -1) && (millisecondsTimeout > 0)) { startTimeTicks = DateTime.UtcNow.Ticks; } bool lockTaken = false; CancellationTokenRegistration registration = cancellationToken.Register(s_cancellationTokenCanceledEventHandler, this); try { SpinWait wait = new SpinWait(); while ((this.m_currentCount == 0) && !wait.NextSpinWillYield) { wait.SpinOnce(); } try { } finally { Monitor.Enter(this.m_lockObj, ref lockTaken); if (lockTaken) { this.m_waitCount++; } } if (this.m_currentCount == 0) { if (millisecondsTimeout == 0) { return(false); } if (!this.WaitUntilCountOrTimeout(millisecondsTimeout, startTimeTicks, cancellationToken)) { return(false); } } this.m_currentCount--; if ((this.m_waitHandle != null) && (this.m_currentCount == 0)) { this.m_waitHandle.Reset(); } } finally { if (lockTaken) { this.m_waitCount--; Monitor.Exit(this.m_lockObj); } registration.Dispose(); } return(true); }
public bool Wait(int millisecondsTimeout, CancellationToken cancellationToken) { this.CheckDispose(); if (millisecondsTimeout < -1) { throw new ArgumentOutOfRangeException("totalMilliSeconds", (object)millisecondsTimeout, SemaphoreSlim.GetResourceString("SemaphoreSlim_Wait_TimeoutWrong")); } cancellationToken.ThrowIfCancellationRequested(); uint startTime = 0; if (millisecondsTimeout != -1 && millisecondsTimeout > 0) { startTime = TimeoutHelper.GetTime(); } bool flag = false; Task <bool> task = (Task <bool>)null; bool lockTaken = false; CancellationTokenRegistration tokenRegistration = cancellationToken.InternalRegisterWithoutEC(SemaphoreSlim.s_cancellationTokenCanceledEventHandler, (object)this); try { SpinWait spinWait = new SpinWait(); while (this.m_currentCount == 0 && !spinWait.NextSpinWillYield) { spinWait.SpinOnce(); } try { } finally { Monitor.Enter(this.m_lockObj, ref lockTaken); if (lockTaken) { this.m_waitCount = this.m_waitCount + 1; } } if (this.m_asyncHead != null) { task = this.WaitAsync(millisecondsTimeout, cancellationToken); } else { OperationCanceledException canceledException = (OperationCanceledException)null; if (this.m_currentCount == 0) { if (millisecondsTimeout == 0) { return(false); } try { flag = this.WaitUntilCountOrTimeout(millisecondsTimeout, startTime, cancellationToken); } catch (OperationCanceledException ex) { canceledException = ex; } } if (this.m_currentCount > 0) { flag = true; this.m_currentCount = this.m_currentCount - 1; } else if (canceledException != null) { throw canceledException; } if (this.m_waitHandle != null) { if (this.m_currentCount == 0) { this.m_waitHandle.Reset(); } } } } finally { if (lockTaken) { this.m_waitCount = this.m_waitCount - 1; Monitor.Exit(this.m_lockObj); } tokenRegistration.Dispose(); } if (task == null) { return(flag); } return(task.GetAwaiter().GetResult()); }
public bool Wait(int millisecondsTimeout, CancellationToken cancellationToken) { CheckDispose(); // Validate input if (millisecondsTimeout < -1) { throw new ArgumentOutOfRangeException( nameof(millisecondsTimeout), millisecondsTimeout, SR.SemaphoreSlim_Wait_TimeoutWrong); } cancellationToken.ThrowIfCancellationRequested(); // Perf: Check the stack timeout parameter before checking the volatile count if (millisecondsTimeout == 0 && m_currentCount == 0) { // Pessimistic fail fast, check volatile count outside lock (only when timeout is zero!) return(false); } uint startTime = 0; if (millisecondsTimeout != Timeout.Infinite && millisecondsTimeout > 0) { startTime = TimeoutHelper.GetTime(); } bool waitSuccessful = false; Task <bool>?asyncWaitTask = null; bool lockTaken = false; // Register for cancellation outside of the main lock. // NOTE: Register/unregister inside the lock can deadlock as different lock acquisition orders could // occur for (1)this.m_lockObjAndDisposed and (2)cts.internalLock CancellationTokenRegistration cancellationTokenRegistration = cancellationToken.UnsafeRegister(s_cancellationTokenCanceledEventHandler, this); try { // Perf: first spin wait for the count to be positive. // This additional amount of spinwaiting in addition // to Monitor.Enter()'s spinwaiting has shown measurable perf gains in test scenarios. if (m_currentCount == 0) { // Monitor.Enter followed by Monitor.Wait is much more expensive than waiting on an event as it involves another // spin, contention, etc. The usual number of spin iterations that would otherwise be used here is increased to // lessen that extra expense of doing a proper wait. int spinCount = SpinWait.SpinCountforSpinBeforeWait * 4; SpinWait spinner = default; while (spinner.Count < spinCount) { spinner.SpinOnce(sleep1Threshold: -1); if (m_currentCount != 0) { break; } } } Monitor.Enter(m_lockObjAndDisposed, ref lockTaken); m_waitCount++; // If there are any async waiters, for fairness we'll get in line behind // then by translating our synchronous wait into an asynchronous one that we // then block on (once we've released the lock). if (m_asyncHead != null) { Debug.Assert(m_asyncTail != null, "tail should not be null if head isn't"); asyncWaitTask = WaitAsync(millisecondsTimeout, cancellationToken); } // There are no async waiters, so we can proceed with normal synchronous waiting. else { // If the count > 0 we are good to move on. // If not, then wait if we were given allowed some wait duration OperationCanceledException?oce = null; if (m_currentCount == 0) { if (millisecondsTimeout == 0) { return(false); } // Prepare for the main wait... // wait until the count become greater than zero or the timeout is expired try { waitSuccessful = WaitUntilCountOrTimeout(millisecondsTimeout, startTime, cancellationToken); } catch (OperationCanceledException e) { oce = e; } } // Now try to acquire. We prioritize acquisition over cancellation/timeout so that we don't // lose any counts when there are asynchronous waiters in the mix. Asynchronous waiters // defer to synchronous waiters in priority, which means that if it's possible an asynchronous // waiter didn't get released because a synchronous waiter was present, we need to ensure // that synchronous waiter succeeds so that they have a chance to release. Debug.Assert(!waitSuccessful || m_currentCount > 0, "If the wait was successful, there should be count available."); if (m_currentCount > 0) { waitSuccessful = true; m_currentCount--; } else if (oce != null) { throw oce; } // Exposing wait handle which is lazily initialized if needed if (m_waitHandle != null && m_currentCount == 0) { m_waitHandle.Reset(); } } } finally { // Release the lock if (lockTaken) { m_waitCount--; Monitor.Exit(m_lockObjAndDisposed); } // Unregister the cancellation callback. cancellationTokenRegistration.Dispose(); } // If we had to fall back to asynchronous waiting, block on it // here now that we've released the lock, and return its // result when available. Otherwise, this was a synchronous // wait, and whether we successfully acquired the semaphore is // stored in waitSuccessful. return((asyncWaitTask != null) ? asyncWaitTask.GetAwaiter().GetResult() : waitSuccessful); }