/// <summary> /// Registers a callback for the <paramref name="cancellationToken"/> that blocks calls to <see cref="CancellationTokenSource.Cancel()"/> until <see cref="Dispose"/> has been called. /// </summary> /// <param name="cancellationToken">Used to signal cancellation requests.</param> public CancellationGuard(CancellationToken cancellationToken) { _registration = cancellationToken.Register( #if NET40 || NET45 _tcs.Task.Wait #else () => _event.WaitOne() #endif ); }
/// <summary> /// Registers a callback for the <paramref name="cancellationToken"/> that blocks calls to <see cref="CancellationTokenSource.Cancel()"/> until <see cref="Dispose"/> has been called. /// </summary> /// <param name="cancellationToken">Used to signal cancellation requests.</param> /// <param name="timeout">A timespan after which the cancellation will be considered completed even if <see cref="Dispose"/> has not been called yet.</param> public CancellationGuard(CancellationToken cancellationToken, TimeSpan timeout) { _registration = cancellationToken.Register( #if NET40 || NET45 () => _tcs.Task.Wait(timeout) #else () => { _event.WaitOne(timeout, exitContext: true); _event.Close(); } #endif ); }
public async Task ConnectAsync(Uri uri, CancellationToken cancellationToken, ClientWebSocketOptions options) { _operation.InterlockedCheckAndUpdateState(WebSocketState.Connecting, s_validConnectStates); using (CancellationTokenRegistration ctr = ThrowOrRegisterCancellation(cancellationToken)) { lock (_operation.Lock) { _operation.CheckValidState(s_validConnectingStates); // Must grab lock until RequestHandle is populated, otherwise we risk resource leaks on Abort. // // TODO (Issue 2506): Alternatively, release the lock between WinHTTP operations and check, under lock, that the // state is still valid to continue operation. _operation.SessionHandle = InitializeWinHttp(options); _operation.ConnectionHandle = Interop.WinHttp.WinHttpConnectWithCallback( _operation.SessionHandle, uri.IdnHost, (ushort)uri.Port, 0); ThrowOnInvalidHandle(_operation.ConnectionHandle); bool secureConnection = uri.Scheme == UriScheme.Https || uri.Scheme == UriScheme.Wss; _operation.RequestHandle = Interop.WinHttp.WinHttpOpenRequestWithCallback( _operation.ConnectionHandle, "GET", uri.PathAndQuery, null, Interop.WinHttp.WINHTTP_NO_REFERER, null, secureConnection ? Interop.WinHttp.WINHTTP_FLAG_SECURE : 0); ThrowOnInvalidHandle(_operation.RequestHandle); if (!Interop.WinHttp.WinHttpSetOption( _operation.RequestHandle, Interop.WinHttp.WINHTTP_OPTION_UPGRADE_TO_WEB_SOCKET, IntPtr.Zero, 0)) { WinHttpException.ThrowExceptionUsingLastError(); } // We need the address of the IntPtr to the GCHandle. IntPtr context = _operation.ToIntPtr(); IntPtr contextAddress; unsafe { contextAddress = (IntPtr)(void *)&context; } if (!Interop.WinHttp.WinHttpSetOption( _operation.RequestHandle, Interop.WinHttp.WINHTTP_OPTION_CONTEXT_VALUE, contextAddress, (uint)IntPtr.Size)) { WinHttpException.ThrowExceptionUsingLastError(); } if (Interop.WinHttp.WinHttpSetStatusCallback( _operation.RequestHandle, WinHttpWebSocketCallback.s_StaticCallbackDelegate, Interop.WinHttp.WINHTTP_CALLBACK_FLAG_ALL_NOTIFICATIONS, IntPtr.Zero) == (IntPtr)Interop.WinHttp.WINHTTP_INVALID_STATUS_CALLBACK) { WinHttpException.ThrowExceptionUsingLastError(); } _operation.RequestHandle.AttachCallback(); AddRequestHeaders(uri, options); _operation.TcsUpgrade = new TaskCompletionSource <bool>(); } await InternalSendWsUpgradeRequestAsync().ConfigureAwait(false); await InternalReceiveWsUpgradeResponse().ConfigureAwait(false); lock (_operation.Lock) { VerifyUpgradeResponse(); ThrowOnInvalidConnectState(); _operation.WebSocketHandle = Interop.WinHttp.WinHttpWebSocketCompleteUpgrade(_operation.RequestHandle, IntPtr.Zero); ThrowOnInvalidHandle(_operation.WebSocketHandle); // We need the address of the IntPtr to the GCHandle. IntPtr context = _operation.ToIntPtr(); IntPtr contextAddress; unsafe { contextAddress = (IntPtr)(void *)&context; } if (!Interop.WinHttp.WinHttpSetOption( _operation.WebSocketHandle, Interop.WinHttp.WINHTTP_OPTION_CONTEXT_VALUE, contextAddress, (uint)IntPtr.Size)) { WinHttpException.ThrowExceptionUsingLastError(); } _operation.WebSocketHandle.AttachCallback(); _operation.UpdateState(WebSocketState.Open); if (_operation.RequestHandle != null) { _operation.RequestHandle.Dispose(); // RequestHandle will be set to null in the callback. } _operation.TcsUpgrade = null; ctr.Dispose(); } } }
private async ValueTask <FlushResult> FlushAsyncInternal(bool writeToStream, ReadOnlyMemory <byte> data, CancellationToken cancellationToken = default) { // Write all completed segments and whatever remains in the current segment // and flush the result. CancellationTokenRegistration reg = default; if (cancellationToken.CanBeCanceled) { reg = cancellationToken.UnsafeRegister(state => ((StreamPipeWriter)state !).Cancel(), this); } if (_tailBytesBuffered > 0) { Debug.Assert(_tail != null); // Update any buffered data _tail.End += _tailBytesBuffered; _tailBytesBuffered = 0; } using (reg) { CancellationToken localToken = InternalTokenSource.Token; try { BufferSegment?segment = _head; while (segment != null) { BufferSegment returnSegment = segment; segment = segment.NextSegment; if (returnSegment.Length > 0 && writeToStream) { await InnerStream.WriteAsync(returnSegment.Memory, localToken).ConfigureAwait(false); } returnSegment.ResetMemory(); ReturnSegmentUnsynchronized(returnSegment); // Update the head segment after we return the current segment _head = segment; } if (writeToStream) { // Write data after the buffered data if (data.Length > 0) { await InnerStream.WriteAsync(data, localToken).ConfigureAwait(false); } if (_bytesBuffered > 0 || data.Length > 0) { await InnerStream.FlushAsync(localToken).ConfigureAwait(false); } } // Mark bytes as written *after* flushing _head = null; _tail = null; _tailMemory = default; _bytesBuffered = 0; return(new FlushResult(isCanceled: false, isCompleted: false)); } catch (OperationCanceledException) { // Remove the cancellation token such that the next time Flush is called // A new CTS is created. lock (_lockObject) { _internalTokenSource = null; } if (localToken.IsCancellationRequested && !cancellationToken.IsCancellationRequested) { // Catch cancellation and translate it into setting isCanceled = true return(new FlushResult(isCanceled: true, isCompleted: false)); } throw; } } }
public Data(TaskCompletionSource <bool> source, Action <object> cancel) { Source = source; Cancel = cancel; Registration = default; }
private async Task AcceptAsync(CancellationToken shutdownSignal) { object connectionCountLock = new object(); int openConnections = 0; TaskCompletionSource <object> allClosed = null; try { TaskCompletionSource <object> shutdown = new TaskCompletionSource <object>(); using (CancellationTokenRegistration shutdownRegistration = shutdownSignal.Register(() => { shutdown.SetResult(null); })) { Task[] tasks = new Task[2]; tasks[1] = shutdown.Task; while (!shutdownSignal.IsCancellationRequested) { Task <TcpClient> acceptTask = this.listener.AcceptTcpClientAsync(); tasks[0] = acceptTask; Task completedTask = await Task.WhenAny(tasks); if (!object.ReferenceEquals(completedTask, acceptTask)) { // Server shutdown this.ConsumeException(acceptTask, "accept"); continue; } // New connection TcpClient connection = acceptTask.Result; lock (connectionCountLock) { Debug.Assert(openConnections >= 0); openConnections++; } Task connectionTask = Task.Factory.StartNew( async() => { await this.ConnectionLoopAsync(connection, shutdownSignal); }, shutdownSignal, TaskCreationOptions.LongRunning | TaskCreationOptions.DenyChildAttach, TaskScheduler.Current); var ignored = connectionTask.ContinueWith(t => { TaskCompletionSource <object> done = null; lock (connectionCountLock) { Debug.Assert(openConnections > 0); openConnections--; if (openConnections == 0 && allClosed != null) { done = allClosed; } } if (done != null) { done.SetResult(null); } }); } } } finally { Task done = null; lock (connectionCountLock) { Debug.Assert(openConnections >= 0); if (openConnections != 0) { Debug.Assert(allClosed == null); allClosed = new TaskCompletionSource <object>(); done = allClosed.Task; } } if (done != null) { await done; } } }
public override async ValueTask <int> ReadAsync(Memory <byte> destination, CancellationToken cancellationToken) { cancellationToken.ThrowIfCancellationRequested(); if (_connection == null || destination.Length == 0) { // Response body fully consumed or the caller didn't ask for any data return(0); } Debug.Assert(_contentBytesRemaining > 0); if ((ulong)destination.Length > _contentBytesRemaining) { destination = destination.Slice(0, (int)_contentBytesRemaining); } ValueTask <int> readTask = _connection.ReadAsync(destination); int bytesRead; if (readTask.IsCompletedSuccessfully) { bytesRead = readTask.Result; } else { CancellationTokenRegistration ctr = _connection.RegisterCancellation(cancellationToken); try { bytesRead = await readTask.ConfigureAwait(false); } catch (Exception exc) when(ShouldWrapInOperationCanceledException(exc, cancellationToken)) { throw CreateOperationCanceledException(exc, cancellationToken); } finally { ctr.Dispose(); } } if (bytesRead <= 0) { // A cancellation request may have caused the EOF. cancellationToken.ThrowIfCancellationRequested(); // Unexpected end of response stream. throw new IOException(SR.net_http_invalid_response); } Debug.Assert((ulong)bytesRead <= _contentBytesRemaining); _contentBytesRemaining -= (ulong)bytesRead; if (_contentBytesRemaining == 0) { // End of response body _connection.CompleteResponse(); _connection = null; } return(bytesRead); }
public static async Task <ProcessResult> RunAsTaskAsync(this ProcessStartInfo psi, CancellationToken cancellationToken = default) { cancellationToken.ThrowIfCancellationRequested(); var logs = new List <ProcessOutput>(); int exitCode; using (var process = new Process()) { process.StartInfo = psi; if (psi.RedirectStandardError) { process.ErrorDataReceived += (sender, e) => { if (e.Data != null) { lock (logs) { logs.Add(new ProcessOutput(ProcessOutputType.StandardError, e.Data)); } } }; } if (psi.RedirectStandardOutput) { process.OutputDataReceived += (sender, e) => { if (e.Data != null) { lock (logs) { logs.Add(new ProcessOutput(ProcessOutputType.StandardOutput, e.Data)); } } }; } if (!process.Start()) { throw new Win32Exception("Cannot start the process"); } if (psi.RedirectStandardError) { process.BeginErrorReadLine(); } if (psi.RedirectStandardOutput) { process.BeginOutputReadLine(); } if (psi.RedirectStandardInput) { process.StandardInput.Close(); } CancellationTokenRegistration registration = default; try { if (cancellationToken.CanBeCanceled && !process.HasExited) { registration = cancellationToken.Register(() => { try { process.Kill(entireProcessTree: true); } catch (InvalidOperationException) { try { // Try to at least kill the root process process.Kill(); } catch (InvalidOperationException) { } } }); } await process.WaitForExitAsync(cancellationToken).ConfigureAwait(false); process.WaitForExit(); // https://github.com/dotnet/runtime/issues/42556 } finally { await registration.DisposeAsync().ConfigureAwait(false); } exitCode = process.ExitCode; } cancellationToken.ThrowIfCancellationRequested(); return(new ProcessResult(exitCode, logs)); }
protected TestBase(ITestOutputHelper logger) { this.Logger = WriteTestOutputToFile ? new FileLogger($@"d:\temp\test.{DateTime.Now:HH-mm-ss.ff}.log", logger) : logger; this.timeoutTokenSource = new CancellationTokenSource(TestTimeout); this.timeoutLoggerRegistration = this.timeoutTokenSource.Token.Register(() => logger.WriteLine("**Timeout token signaled** (Time index: {0:HH:mm:ss.ff}, Elapsed: {1})", DateTime.Now, this.ElapsedTime)); }
/// <summary> /// Initializes a new instance of the <see cref="DisposableBag"/> class. /// </summary> internal DisposableBag(CancellationToken cancellationToken = default) { _cts = CancellationTokenSource.CreateLinkedTokenSource(cancellationToken); _cancellationToken = _cts.Token; _autoDisposeRegistration = RegisterNoThrowOnDispose(Dispose, cancellationToken); }
public WorkPool(IModel model) { _actions = new ConcurrentQueue <Action>(); _tokenSource = new CancellationTokenSource(); _tokenRegistration = _tokenSource.Token.Register(() => _syncSource.TrySetCanceled()); }
private async ValueTask <int> ReadAsyncCore(Memory <byte> destination, CancellationToken cancellationToken) { // Should only be called if ReadChunksFromConnectionBuffer returned 0. Debug.Assert(_connection != null); Debug.Assert(destination.Length > 0); CancellationTokenRegistration ctr = _connection.RegisterCancellation(cancellationToken); try { while (true) { if (_connection == null) { // Fully consumed the response in ReadChunksFromConnectionBuffer. return(0); } if (_state == ParsingState.ExpectChunkData && destination.Length >= _connection.ReadBufferSize && _chunkBytesRemaining >= (ulong)_connection.ReadBufferSize) { // As an optimization, we skip going through the connection's read buffer if both // the remaining chunk data and the destination buffer are both at least as large // as the connection buffer. That avoids an unnecessary copy while still reading // the maximum amount we'd otherwise read at a time. Debug.Assert(_connection.RemainingBuffer.Length == 0); int bytesRead = await _connection.ReadAsync(destination.Slice(0, (int)Math.Min((ulong)destination.Length, _chunkBytesRemaining))); if (bytesRead == 0) { throw new IOException(SR.net_http_invalid_response); } _chunkBytesRemaining -= (ulong)bytesRead; if (_chunkBytesRemaining == 0) { _state = ParsingState.ExpectChunkTerminator; } return(bytesRead); } // We're only here if we need more data to make forward progress. await _connection.FillAsync(); // Now that we have more, see if we can get any response data, and if // we can we're done. int bytesCopied = ReadChunksFromConnectionBuffer(destination.Span); if (bytesCopied > 0) { return(bytesCopied); } } } catch (Exception exc) when(ShouldWrapInOperationCanceledException(exc, cancellationToken)) { throw new OperationCanceledException(s_cancellationMessage, exc, cancellationToken); } finally { ctr.Dispose(); } }
protected ScheduledAsyncTask(AbstractScheduledEventExecutor executor, long deadlineNanos, long periodNanos, IPromise promise, CancellationToken cancellationToken) : base(executor, deadlineNanos, periodNanos, promise) { _cancellationToken = cancellationToken; _cancellationTokenRegistration = cancellationToken.Register(s => ((ScheduledAsyncTask)s).Cancel(), this); }
private ReadOnlyMemory <byte> ReadChunkFromConnectionBuffer(int maxBytesToRead, CancellationTokenRegistration cancellationRegistration) { Debug.Assert(maxBytesToRead > 0); try { ReadOnlySpan <byte> currentLine; switch (_state) { case ParsingState.ExpectChunkHeader: Debug.Assert(_chunkBytesRemaining == 0, $"Expected {nameof(_chunkBytesRemaining)} == 0, got {_chunkBytesRemaining}"); // Read the chunk header line. _connection._allowedReadLineBytes = MaxChunkBytesAllowed; if (!_connection.TryReadNextLine(out currentLine)) { // Could not get a whole line, so we can't parse the chunk header. return(default); } // Parse the hex value from it. if (!Utf8Parser.TryParse(currentLine, out ulong chunkSize, out int bytesConsumed, 'X')) { throw new IOException(SR.net_http_invalid_response); } _chunkBytesRemaining = chunkSize; // If there's a chunk extension after the chunk size, validate it. if (bytesConsumed != currentLine.Length) { ValidateChunkExtension(currentLine.Slice(bytesConsumed)); } // Proceed to handle the chunk. If there's data in it, go read it. // Otherwise, finish handling the response. if (chunkSize > 0) { _state = ParsingState.ExpectChunkData; goto case ParsingState.ExpectChunkData; } else { _state = ParsingState.ConsumeTrailers; goto case ParsingState.ConsumeTrailers; } case ParsingState.ExpectChunkData: Debug.Assert(_chunkBytesRemaining > 0); ReadOnlyMemory <byte> connectionBuffer = _connection.RemainingBuffer; if (connectionBuffer.Length == 0) { return(default);
public CancelableEnumerator(IAsyncEnumerator <T> asyncEnumerator, CancellationTokenRegistration registration) { _asyncEnumerator = asyncEnumerator; _cancellationTokenRegistration = registration; }
internal RequestStreamAsyncResult(RequestStream requestStream, object userState, AsyncCallback callback, byte[] buffer, int offset, uint dataAlreadyRead, CancellationTokenRegistration cancellationRegistration) : this(requestStream, userState, callback) { _dataAlreadyRead = dataAlreadyRead; var boundHandle = requestStream.RequestContext.Server.RequestQueue.BoundHandle; _overlapped = new SafeNativeOverlapped(boundHandle, boundHandle.AllocateNativeOverlapped(IOCallback, this, buffer)); _pinnedBuffer = (Marshal.UnsafeAddrOfPinnedArrayElement(buffer, offset)); _cancellationRegistration = cancellationRegistration; }
public CancellationEvent(CancellationToken cancellationToken) { _mre = new ManualResetEvent(false); _registration = cancellationToken.Register(SetEvent, _mre); }
private void UnregisterCancellationToken() { _cancellationTokenRegistration.Dispose(); _cancellationTokenRegistration = default(CancellationTokenRegistration); }
public DiposeCancellationState(CancellationCallbackWrapper callbackWrapper, CancellationTokenRegistration registration) { _callbackWrapper = callbackWrapper; _registration = registration; }
public WasmFetchResponse(JSObject fetchResponse, JSObject abortController, CancellationTokenRegistration abortRegistration) { this.fetchResponse = fetchResponse; this.abortController = abortController; this.abortRegistration = abortRegistration; }
internal FollowCancelableTaskState <T> WithRegisteredCallback(CancellationTokenRegistration registeredCallback) => new FollowCancelableTaskState <T>(this.getTaskToFollow, registeredCallback, this.UltimateCancellation);
private async Task doFetch(TaskCompletionSource <HttpResponseMessage> tcs, HttpRequestMessage request, CancellationToken cancellationToken) { try { var requestObject = new JSObject(); requestObject.SetObjectProperty("method", request.Method.Method); // See https://developer.mozilla.org/en-US/docs/Web/API/Request/credentials for // standard values and meanings requestObject.SetObjectProperty("credentials", DefaultCredentials); // See https://developer.mozilla.org/en-US/docs/Web/API/Request/cache for // standard values and meanings requestObject.SetObjectProperty("cache", Cache); // See https://developer.mozilla.org/en-US/docs/Web/API/Request/mode for // standard values and meanings requestObject.SetObjectProperty("mode", Mode); // We need to check for body content if (request.Content != null) { if (request.Content is StringContent) { requestObject.SetObjectProperty("body", await request.Content.ReadAsStringAsync()); } else { // 2.1.801 seems to have a problem with the line // using (var uint8Buffer = Uint8Array.From(await request.Content.ReadAsByteArrayAsync ())) // so we split it up into two lines. var byteAsync = await request.Content.ReadAsByteArrayAsync(); using (var uint8Buffer = Uint8Array.From(byteAsync)) { requestObject.SetObjectProperty("body", uint8Buffer); } } } // Process headers // Cors has it's own restrictions on headers. // https://developer.mozilla.org/en-US/docs/Web/API/Headers using (var jsHeaders = new HostObject("Headers")) { if (request.Headers != null) { foreach (var header in request.Headers) { foreach (var value in header.Value) { jsHeaders.Invoke("append", header.Key, value); } } } if (request.Content?.Headers != null) { foreach (var header in request.Content.Headers) { foreach (var value in header.Value) { jsHeaders.Invoke("append", header.Key, value); } } } requestObject.SetObjectProperty("headers", jsHeaders); } JSObject abortController = null; JSObject signal = null; WasmHttpReadStream wasmHttpReadStream = null; CancellationTokenRegistration abortRegistration = default(CancellationTokenRegistration); if (cancellationToken.CanBeCanceled) { abortController = new HostObject("AbortController"); signal = (JSObject)abortController.GetObjectProperty("signal"); requestObject.SetObjectProperty("signal", signal); abortRegistration = cancellationToken.Register((Action)(() => { if (abortController.JSHandle != -1) { abortController.Invoke((string)"abort"); abortController?.Dispose(); } wasmHttpReadStream?.Dispose(); })); } var args = new Core.Array(); args.Push(request.RequestUri.ToString()); args.Push(requestObject); requestObject.Dispose(); var response = fetch.Invoke("apply", window, args) as Task <object>; args.Dispose(); if (response == null) { throw new Exception("Internal error marshalling the response Promise from `fetch`."); } var t = await response; var status = new WasmFetchResponse((JSObject)t, abortController, abortRegistration); //Console.WriteLine($"bodyUsed: {status.IsBodyUsed}"); //Console.WriteLine($"ok: {status.IsOK}"); //Console.WriteLine($"redirected: {status.IsRedirected}"); //Console.WriteLine($"status: {status.Status}"); //Console.WriteLine($"statusText: {status.StatusText}"); //Console.WriteLine($"type: {status.ResponseType}"); //Console.WriteLine($"url: {status.Url}"); HttpResponseMessage httpresponse = new HttpResponseMessage((HttpStatusCode)Enum.Parse(typeof(HttpStatusCode), status.Status.ToString())); httpresponse.Content = StreamingSupported && StreamingEnabled ? new StreamContent(wasmHttpReadStream = new WasmHttpReadStream(status)) : (HttpContent) new WasmHttpContent(status); // Fill the response headers // CORS will only allow access to certain headers. // If a request is made for a resource on another origin which returns the CORs headers, then the type is cors. // cors and basic responses are almost identical except that a cors response restricts the headers you can view to // `Cache-Control`, `Content-Language`, `Content-Type`, `Expires`, `Last-Modified`, and `Pragma`. // View more information https://developers.google.com/web/updates/2015/03/introduction-to-fetch#response_types // // Note: Some of the headers may not even be valid header types in .NET thus we use TryAddWithoutValidation using (var respHeaders = (JSObject)status.Headers) { if (respHeaders != null) { using (var entriesIterator = (JSObject)respHeaders.Invoke("entries")) { JSObject nextResult = null; try { nextResult = (JSObject)entriesIterator.Invoke("next"); while (!(bool)nextResult.GetObjectProperty("done")) { using (var resultValue = (WebAssembly.Core.Array)nextResult.GetObjectProperty("value")) { var name = (string)resultValue [0]; var value = (string)resultValue [1]; if (!httpresponse.Headers.TryAddWithoutValidation(name, value)) { if (httpresponse.Content != null) { if (!httpresponse.Content.Headers.TryAddWithoutValidation(name, value)) { Console.WriteLine($"Warning: Can not add response header for name: {name} value: {value}"); } } } } nextResult?.Dispose(); nextResult = (JSObject)entriesIterator.Invoke("next"); } } finally { nextResult?.Dispose(); } } } } tcs.SetResult(httpresponse); signal?.Dispose(); } catch (Exception exception) { tcs.SetException(exception); } }
/// <summary> /// Returns a task that will receive the last value or the exception produced by the observable sequence. /// </summary> /// <typeparam name="TResult">The type of the elements in the source sequence.</typeparam> /// <param name="observable">Observable sequence to convert to a task.</param> /// <param name="cancellationToken">Cancellation token that can be used to cancel the task, causing unsubscription from the observable sequence.</param> /// <param name="state">The state to use as the underlying task's AsyncState.</param> /// <returns>A task that will receive the last element or the exception produced by the observable sequence.</returns> /// <exception cref="ArgumentNullException"><paramref name="observable"/> is null.</exception> public static Task <TResult> ToTask <TResult>(this IObservable <TResult> observable, CancellationToken cancellationToken, object state) { if (observable == null) { throw new ArgumentNullException("observable"); } bool hasValue = false; TResult lastValue = default(TResult); TaskCompletionSource <TResult> tcs = new TaskCompletionSource <TResult>(state); SingleAssignmentDisposable disposable = new SingleAssignmentDisposable(); CancellationTokenRegistration ctr = default(CancellationTokenRegistration); if (cancellationToken.CanBeCanceled) { ctr = cancellationToken.Register(() => { disposable.Dispose(); tcs.TrySetCanceled(cancellationToken); }); } IObserver <TResult> taskCompletionObserver = Observer.Create <TResult>( value => { hasValue = true; lastValue = value; }, ex => { tcs.TrySetException(ex); ctr.Dispose(); // no null-check needed (struct) disposable.Dispose(); }, () => { if (hasValue) { tcs.TrySetResult(lastValue); } else { tcs.TrySetException(new InvalidOperationException("Strings_Linq.NO_ELEMENTS")); } ctr.Dispose(); // no null-check needed (struct) disposable.Dispose(); } ); // // Subtle race condition: if the source completes before we reach the line below, the SingleAssigmentDisposable // will already have been disposed. Upon assignment, the disposable resource being set will be disposed on the // spot, which may throw an exception. (Similar to TFS 487142) // try { // // [OK] Use of unsafe Subscribe: we're catching the exception here to set the TaskCompletionSource. // // Notice we could use a safe subscription to route errors through OnError, but we still need the // exception handling logic here for the reason explained above. We cannot afford to throw here // and as a result never set the TaskCompletionSource, so we tunnel everything through here. // disposable.Disposable = observable.Subscribe/*Unsafe*/ (taskCompletionObserver); } catch (Exception ex) { tcs.TrySetException(ex); } return(tcs.Task); }
protected TestBase(ITestOutputHelper logger) { this.Logger = logger; this.timeoutTokenSource = new CancellationTokenSource(TestTimeout); this.timeoutLoggerRegistration = this.timeoutTokenSource.Token.Register(() => logger.WriteLine("**Timeout token signaled**")); }
public Task SendMailAsync(MailMessage message, CancellationToken cancellationToken) { if (cancellationToken.IsCancellationRequested) { return(Task.FromCanceled(cancellationToken)); } // Create a TaskCompletionSource to represent the operation var tcs = new TaskCompletionSource(); CancellationTokenRegistration ctr = default; // Indicates whether the CTR has been set - captured in handler int state = 0; // Register a handler that will transfer completion results to the TCS Task SendCompletedEventHandler?handler = null; handler = (sender, e) => { if (e.UserState == tcs) { try { ((SmtpClient)sender).SendCompleted -= handler; if (Interlocked.Exchange(ref state, 1) != 0) { // A CTR has been set, we have to wait until it completes before completing the task ctr.Dispose(); } } catch (ObjectDisposedException) { } // SendAsyncCancel will throw if SmtpClient was disposed finally { if (e.Error != null) { tcs.TrySetException(e.Error); } else if (e.Cancelled) { tcs.TrySetCanceled(); } else { tcs.TrySetResult(); } } } }; SendCompleted += handler; // Start the async operation. try { SendAsync(message, tcs); } catch { SendCompleted -= handler; throw; } ctr = cancellationToken.Register(s => { ((SmtpClient)s !).SendAsyncCancel(); }, this); if (Interlocked.Exchange(ref state, 1) != 0) { // SendCompleted was already invoked, ensure the CTR completes before returning the task ctr.Dispose(); } // Return the task to represent the asynchronous operation return(tcs.Task); }
internal static void TryDeregister(this CancellationTokenRegistration ctr) { //nothing to do for projectN }
public WithCancellationSource(UniTask task, CancellationToken cancellationToken) { this.cancellationToken = cancellationToken; this.tokenRegistration = cancellationToken.RegisterWithoutCaptureExecutionContext(cancellationCallbackDelegate, this); RunTask(task).Forget(); }
private async ValueTask <int> ReadAsyncCore(Memory <byte> buffer, CancellationToken cancellationToken) { // Should only be called if ReadChunksFromConnectionBuffer returned 0. Debug.Assert(_connection != null); CancellationTokenRegistration ctr = _connection.RegisterCancellation(cancellationToken); try { while (true) { if (_connection == null) { // Fully consumed the response in ReadChunksFromConnectionBuffer. return(0); } if (_state == ParsingState.ExpectChunkData && buffer.Length >= _connection.ReadBufferSize && _chunkBytesRemaining >= (ulong)_connection.ReadBufferSize) { // As an optimization, we skip going through the connection's read buffer if both // the remaining chunk data and the buffer are both at least as large // as the connection buffer. That avoids an unnecessary copy while still reading // the maximum amount we'd otherwise read at a time. Debug.Assert(_connection.RemainingBuffer.Length == 0); Debug.Assert(buffer.Length != 0); int bytesRead = await _connection.ReadAsync(buffer.Slice(0, (int)Math.Min((ulong)buffer.Length, _chunkBytesRemaining))).ConfigureAwait(false); if (bytesRead == 0) { throw new IOException(SR.Format(SR.net_http_invalid_response_premature_eof_bytecount, _chunkBytesRemaining)); } _chunkBytesRemaining -= (ulong)bytesRead; if (_chunkBytesRemaining == 0) { _state = ParsingState.ExpectChunkTerminator; } return(bytesRead); } if (buffer.Length == 0) { // User requested a zero-byte read, and we have no data available in the buffer for processing. // This zero-byte read indicates their desire to trade off the extra cost of a zero-byte read // for reduced memory consumption when data is not immediately available. // So, we will issue our own zero-byte read against the underlying stream to allow it to make use of // optimizations, such as deferring buffer allocation until data is actually available. await _connection.ReadAsync(buffer).ConfigureAwait(false); } // We're only here if we need more data to make forward progress. await _connection.FillAsync(async : true).ConfigureAwait(false); // Now that we have more, see if we can get any response data, and if // we can we're done. if (buffer.Length == 0) { if (PeekChunkFromConnectionBuffer()) { return(0); } } else { int bytesCopied = ReadChunksFromConnectionBuffer(buffer.Span, ctr); if (bytesCopied > 0) { return(bytesCopied); } } } } catch (Exception exc) when(CancellationHelper.ShouldWrapInOperationCanceledException(exc, cancellationToken)) { throw CancellationHelper.CreateOperationCanceledException(exc, cancellationToken); } finally { ctr.Dispose(); } }
public override Task SendAsync( ArraySegment <byte> buffer, WebSocketMessageType messageType, bool endOfMessage, CancellationToken cancellationToken) { _operation.InterlockedCheckValidStates(s_validSendStates); using (CancellationTokenRegistration ctr = ThrowOrRegisterCancellation(cancellationToken)) { var bufferType = WebSocketMessageTypeAdapter.GetWinHttpMessageType(messageType, endOfMessage); // TODO (Issue 2505): replace with PinnableBufferCache. if (!_cachedSendPinnedBuffer.IsAllocated || _cachedSendPinnedBuffer.Target != buffer.Array) { if (_cachedSendPinnedBuffer.IsAllocated) { _cachedSendPinnedBuffer.Free(); } _cachedSendPinnedBuffer = GCHandle.Alloc(buffer.Array, GCHandleType.Pinned); } bool sendOperationAlreadyPending = false; if (_operation.PendingWriteOperation == false) { lock (_operation.Lock) { _operation.CheckValidState(s_validSendStates); if (_operation.PendingWriteOperation == false) { _operation.PendingWriteOperation = true; _operation.TcsSend = new TaskCompletionSource <bool>(); uint ret = Interop.WinHttp.WinHttpWebSocketSend( _operation.WebSocketHandle, bufferType, buffer.Count > 0 ? Marshal.UnsafeAddrOfPinnedArrayElement(buffer.Array, buffer.Offset) : IntPtr.Zero, (uint)buffer.Count); if (Interop.WinHttp.ERROR_SUCCESS != ret) { throw WinHttpException.CreateExceptionUsingError((int)ret); } } else { sendOperationAlreadyPending = true; } } } else { sendOperationAlreadyPending = true; } if (sendOperationAlreadyPending) { var exception = new InvalidOperationException( SR.Format(SR.net_Websockets_AlreadyOneOutstandingOperation, "SendAsync")); _operation.TcsSend.TrySetException(exception); Abort(); } return(_operation.TcsSend.Task); } }
internal BackgroundCommandHandler(IFtpConnection connection) { _connection = connection; _cancellationTokenRegistration = _connection.CancellationToken.Register(() => _cancellationTokenSource.Cancel(true)); }
private async Task ConnectAsyncCore(Uri uri, CancellationToken cancellationToken) { HttpWebResponse response = null; CancellationTokenRegistration connectCancellation = new CancellationTokenRegistration(); // Any errors from here on out are fatal and this instance will be disposed. try { HttpWebRequest request = CreateAndConfigureRequest(uri); if (Logging.On) { Logging.Associate(Logging.WebSockets, this, request); } connectCancellation = cancellationToken.Register(AbortRequest, request, false); response = await request.GetResponseAsync().SuppressContextFlow() as HttpWebResponse; Contract.Assert(response != null, "Not an HttpWebResponse"); if (Logging.On) { Logging.Associate(Logging.WebSockets, this, response); } this.ResponseHeaders = response.Headers; string subprotocol = ValidateResponse(request, response); innerWebSocket = WebSocket.CreateClientWebSocket(response.GetResponseStream(), subprotocol, options.ReceiveBufferSize, options.SendBufferSize, options.KeepAliveInterval, false, options.GetOrCreateBuffer()); if (Logging.On) { Logging.Associate(Logging.WebSockets, this, innerWebSocket); } // Change internal state to 'connected' to enable the other methods if (Interlocked.CompareExchange(ref state, connected, connecting) != connecting) { // Aborted/Disposed during connect. throw new ObjectDisposedException(GetType().FullName); } } catch (WebException ex) { ConnectExceptionCleanup(response); WebSocketException wex = new WebSocketException(SR.GetString(SR.net_webstatus_ConnectFailure), ex); if (Logging.On) { Logging.Exception(Logging.WebSockets, this, "ConnectAsync", wex); } throw wex; } catch (Exception ex) { ConnectExceptionCleanup(response); if (Logging.On) { Logging.Exception(Logging.WebSockets, this, "ConnectAsync", ex); } throw; } finally { // We successfully connected (or failed trying), disengage from this token. // Otherwise any timeout/cancellation would apply to the full session. // In the failure case we need to release the reference to HWR. connectCancellation.Dispose(); } }
private async ValueTask <FlushResult> FlushAsyncInternal(CancellationToken cancellationToken = default) { // Write all completed segments and whatever remains in the current segment // and flush the result. CancellationTokenRegistration reg = new CancellationTokenRegistration(); if (cancellationToken.CanBeCanceled) { reg = cancellationToken.Register(state => ((StreamPipeWriter)state).Cancel(), this); } using (reg) { var localToken = InternalTokenSource.Token; try { if (_completedSegments != null && _completedSegments.Count > 0) { var count = _completedSegments.Count; for (var i = 0; i < count; i++) { var segment = _completedSegments[0]; #if NETCOREAPP3_0 await _writingStream.WriteAsync(segment.Buffer.Slice(0, segment.Length), localToken); #elif NETSTANDARD2_0 MemoryMarshal.TryGetArray <byte>(segment.Buffer, out var arraySegment); await _writingStream.WriteAsync(arraySegment.Array, 0, segment.Length, localToken); #else #error Target frameworks need to be updated. #endif _bytesWritten -= segment.Length; segment.Return(); _completedSegments.RemoveAt(0); } } if (!_currentSegment.IsEmpty) { #if NETCOREAPP3_0 await _writingStream.WriteAsync(_currentSegment.Slice(0, _position), localToken); #elif NETSTANDARD2_0 MemoryMarshal.TryGetArray <byte>(_currentSegment, out var arraySegment); await _writingStream.WriteAsync(arraySegment.Array, 0, _position, localToken); #else #error Target frameworks need to be updated. #endif _bytesWritten -= _position; _position = 0; } await _writingStream.FlushAsync(localToken); return(new FlushResult(isCanceled: false, IsCompletedOrThrow())); } catch (OperationCanceledException) { // Remove the cancellation token such that the next time Flush is called // A new CTS is created. lock (_lockObject) { _internalTokenSource = null; } if (cancellationToken.IsCancellationRequested) { throw; } // Catch any cancellation and translate it into setting isCanceled = true return(new FlushResult(isCanceled: true, IsCompletedOrThrow())); } } }