private void CancelAllOperations() { if (_operation.TcsClose != null) { var exception = new WebSocketException( WebSocketError.InvalidState, SR.Format( SR.net_WebSockets_InvalidState_ClosedOrAborted, "System.Net.WebSockets.InternalClientWebSocket", "Aborted")); _operation.TcsClose.TrySetException(exception); } if (_operation.TcsCloseOutput != null) { var exception = new WebSocketException( WebSocketError.InvalidState, SR.Format( SR.net_WebSockets_InvalidState_ClosedOrAborted, "System.Net.WebSockets.InternalClientWebSocket", "Aborted")); _operation.TcsCloseOutput.TrySetException(exception); } if (_operation.TcsReceive != null) { var exception = new WebSocketException( WebSocketError.InvalidState, SR.Format( SR.net_WebSockets_InvalidState_ClosedOrAborted, "System.Net.WebSockets.InternalClientWebSocket", "Aborted")); _operation.TcsReceive.TrySetException(exception); } if (_operation.TcsSend != null) { var exception = new OperationCanceledException(); _operation.TcsSend.TrySetException(exception); } if (_operation.TcsUpgrade != null) { var exception = new WebSocketException(SR.net_webstatus_ConnectFailure); _operation.TcsUpgrade.TrySetException(exception); } }
public void SendAsync_IfSendAsyncCancels_InControllerSelector_DoesNotCallExceptionServices() { // Arrange Exception expectedException = new OperationCanceledException(); Mock<IExceptionLogger> exceptionLoggerMock = new Mock<IExceptionLogger>(MockBehavior.Strict); IExceptionLogger exceptionLogger = exceptionLoggerMock.Object; Mock<IExceptionHandler> exceptionHandlerMock = new Mock<IExceptionHandler>(MockBehavior.Strict); IExceptionHandler exceptionHandler = exceptionHandlerMock.Object; using (HttpRequestMessage expectedRequest = CreateRequestWithRouteData()) using (HttpConfiguration configuration = CreateConfiguration()) using (HttpMessageHandler product = CreateProductUnderTest(configuration, exceptionLogger, exceptionHandler)) { configuration.Services.Replace(typeof(IHttpControllerSelector), CreateThrowingControllerSelector(expectedException)); CancellationToken cancellationToken = CreateCancellationToken(); Task<HttpResponseMessage> task = product.SendAsync(expectedRequest, cancellationToken); // Act task.WaitUntilCompleted(); // Assert Assert.Equal(TaskStatus.Canceled, task.Status); } }
/// <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( 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/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 { m_lock.Acquire(); lockTaken = true; 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) { 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--; m_lock.Release(); } // 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", (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 void Invoke_IfStreamingCancels_DoesNotCallExceptionLogger() { // Arrange Exception expectedException = new OperationCanceledException(); using (HttpContent content = CreateFaultingContent(expectedException)) using (HttpResponseMessage expectedResponse = CreateResponse(content)) using (HttpMessageHandler messageHandler = CreateStubMessageHandler(expectedResponse)) { Mock<IExceptionLogger> mock = new Mock<IExceptionLogger>(MockBehavior.Strict); IExceptionLogger exceptionLogger = mock.Object; HttpMessageHandlerOptions options = CreateValidOptions(messageHandler); options.BufferPolicySelector = CreateBufferPolicySelector(bufferInput: false, bufferOutput: false); options.ExceptionLogger = exceptionLogger; using (HttpMessageHandlerAdapter product = CreateProductUnderTest(options)) using (CancellationTokenSource tokenSource = CreateCancellationTokenSource()) { CancellationToken expectedCancellationToken = tokenSource.Token; IOwinRequest owinRequest = CreateFakeOwinRequest(expectedCancellationToken); IOwinResponse owinResponse = CreateFakeOwinResponse(Stream.Null); IOwinContext context = CreateStubOwinContext(owinRequest, owinResponse); // Act Task task = product.Invoke(context); // Assert Assert.NotNull(task); task.WaitUntilCompleted(); Assert.Equal(TaskStatus.Canceled, task.Status); } } }
public void Invoke_IfBufferingErrorCancels_DoesNotCallExceptionLogger() { // Arrange Exception expectedOriginalException = CreateException(); Exception expectedErrorException = new OperationCanceledException(); using (HttpContent content = CreateFaultingContent(expectedOriginalException)) using (HttpResponseMessage expectedOriginalResponse = CreateResponse(content)) using (HttpMessageHandler messageHandler = CreateStubMessageHandler(expectedOriginalResponse)) using (HttpContent errorContent = CreateFaultingContent(expectedErrorException)) using (HttpResponseMessage expectedErrorResponse = CreateResponse(errorContent)) using (CancellationTokenSource tokenSource = CreateCancellationTokenSource()) { Mock<IExceptionLogger> mock = CreateStubExceptionLoggerMock(); IExceptionLogger exceptionLogger = mock.Object; HttpMessageHandlerOptions options = CreateValidOptions(messageHandler); options.BufferPolicySelector = CreateBufferPolicySelector(bufferInput: false, bufferOutput: true); options.ExceptionLogger = exceptionLogger; options.ExceptionHandler = CreateExceptionHandler(new ResponseMessageResult(expectedErrorResponse)); using (HttpMessageHandlerAdapter product = CreateProductUnderTest(options)) { CancellationToken expectedCancellationToken = tokenSource.Token; IOwinRequest owinRequest = CreateFakeOwinRequest(expectedCancellationToken); IOwinResponse owinResponse = CreateFakeOwinResponse(Stream.Null); IOwinContext context = CreateStubOwinContext(owinRequest, owinResponse, isLocal: true); // Act Task task = product.Invoke(context); // Assert Assert.NotNull(task); task.WaitUntilCompleted(); Assert.Equal(TaskStatus.Canceled, task.Status); mock.Verify(l => l.LogAsync(It.Is<ExceptionLoggerContext>(c => c.ExceptionContext != null && c.ExceptionContext.Exception == expectedOriginalException && c.ExceptionContext.CatchBlock == OwinExceptionCatchBlocks.HttpMessageHandlerAdapterBufferContent && c.ExceptionContext.Request != null && c.ExceptionContext.Response == expectedOriginalResponse), expectedCancellationToken), Times.Once()); // This shouldn't be called for 'HttpMessageHandlerAdapterBufferError' because that's what's being // cancelled. mock.Verify(l => l.LogAsync(It.Is<ExceptionLoggerContext>(c => c.ExceptionContext != null && c.ExceptionContext.Exception == expectedErrorException && c.ExceptionContext.CatchBlock == OwinExceptionCatchBlocks.HttpMessageHandlerAdapterBufferError && c.ExceptionContext.Request != null && c.ExceptionContext.Response == expectedErrorResponse), expectedCancellationToken), Times.Never()); } } }