private static uint HandleEventShutdownComplete(State state, ref ConnectionEvent connectionEvent) { // This is the final event on the connection, so free the GCHandle used by the event callback. state.StateGCHandle.Free(); state.Connection = null; state.ShutdownTcs.SetResult(MsQuicStatusCodes.Success); // Stop accepting new streams. state.AcceptQueue.Writer.TryComplete(); // Stop notifying about available streams. TaskCompletionSource?unidirectionalTcs = null; TaskCompletionSource?bidirectionalTcs = null; lock (state) { unidirectionalTcs = state.NewUnidirectionalStreamsAvailable; bidirectionalTcs = state.NewBidirectionalStreamsAvailable; state.NewUnidirectionalStreamsAvailable = null; state.NewBidirectionalStreamsAvailable = null; } if (unidirectionalTcs is not null) { unidirectionalTcs.SetException(ExceptionDispatchInfo.SetCurrentStackTrace(new QuicOperationAbortedException())); } if (bidirectionalTcs is not null) { bidirectionalTcs.SetException(ExceptionDispatchInfo.SetCurrentStackTrace(new QuicOperationAbortedException())); } return(MsQuicStatusCodes.Success); }
private static uint HandleEventStreamsAvailable(State state, ref ConnectionEvent connectionEvent) { TaskCompletionSource?unidirectionalTcs = null; TaskCompletionSource?bidirectionalTcs = null; lock (state) { if (connectionEvent.Data.StreamsAvailable.UniDirectionalCount > 0) { unidirectionalTcs = state.NewUnidirectionalStreamsAvailable; state.NewUnidirectionalStreamsAvailable = null; } if (connectionEvent.Data.StreamsAvailable.BiDirectionalCount > 0) { bidirectionalTcs = state.NewBidirectionalStreamsAvailable; state.NewBidirectionalStreamsAvailable = null; } } if (unidirectionalTcs is not null) { unidirectionalTcs.SetResult(); } if (bidirectionalTcs is not null) { bidirectionalTcs.SetResult(); } return(MsQuicStatusCodes.Success); }
internal override ValueTask WaitForAvailableBidirectionalStreamsAsync(CancellationToken cancellationToken = default) { TaskCompletionSource?tcs = _state.NewBidirectionalStreamsAvailable; if (tcs is null) { // We need to avoid calling MsQuic under lock. // This is not atomic but it won't be anyway as counts can change between when task is completed // and before somebody may try to allocate new stream. int count = GetRemoteAvailableBidirectionalStreamCount(); lock (_state) { if (_state.NewBidirectionalStreamsAvailable is null) { if (_state.ShutdownTcs.Task.IsCompleted) { throw new QuicOperationAbortedException(); } if (count > 0) { return(ValueTask.CompletedTask); } _state.NewBidirectionalStreamsAvailable = new TaskCompletionSource(TaskCreationOptions.RunContinuationsAsynchronously); } tcs = _state.NewBidirectionalStreamsAvailable; } } return(new ValueTask(tcs.Task.WaitAsync(cancellationToken))); }
internal override ValueTask WaitForAvailableBidirectionalStreamsAsync(CancellationToken cancellationToken = default) { TaskCompletionSource?tcs = _state.NewBidirectionalStreamsAvailable; if (tcs is null) { lock (_state) { if (_state.NewBidirectionalStreamsAvailable is null) { if (_state.ShutdownTcs.Task.IsCompleted) { throw new QuicOperationAbortedException(); } if (GetRemoteAvailableBidirectionalStreamCount() > 0) { return(ValueTask.CompletedTask); } _state.NewBidirectionalStreamsAvailable = new TaskCompletionSource(TaskCreationOptions.RunContinuationsAsynchronously); } tcs = _state.NewBidirectionalStreamsAvailable; } } return(new ValueTask(tcs.Task.WaitAsync(cancellationToken))); }
public static async Task <T> AttachAndRun <T>(this FrameworkElement view, Func <Task <T> > action) { if (view.Parent is Border wrapper) { view = wrapper; } TaskCompletionSource?tcs = null; if (view.Parent == null) { // prepare to wait for element to be in the UI tcs = new TaskCompletionSource(); view.Loaded += OnViewLoaded; // attach to the UI Grid grid; var window = new Window { Content = new Grid { HorizontalAlignment = HorizontalAlignment.Center, VerticalAlignment = VerticalAlignment.Center, Children = { (grid = new Grid { Width = view.Width, Height = view.Height, Children = { view } }) } } }; window.Activate(); // wait for element to be loaded await tcs.Task; // continue with the run try { return(await Run(action)); } finally { grid.Children.Clear(); window.Close(); } } else { return(await Run(action)); }
/// <inheritdoc /> public async Task Start() { logger.LogInformation("Starting Timer."); cancellationTokenSource = new CancellationTokenSource(); cancellationToken = cancellationTokenSource.Token; startPromise = new TaskCompletionSource(); stopPromise = new TaskCompletionSource(); thread = new Thread(RunAsync); thread.Start(); await startPromise.Task; }
public void Initialize(Http3StreamContext context) { base.Initialize(context); InputRemaining = null; _context = context; _errorCodeFeature = _context.ConnectionFeatures.Get <IProtocolErrorCodeFeature>() !; _streamIdFeature = _context.ConnectionFeatures.Get <IStreamIdFeature>() !; _streamAbortFeature = _context.ConnectionFeatures.Get <IStreamAbortFeature>() !; _appCompleted = null; _isClosed = 0; _requestHeaderParsingState = default; _parsedPseudoHeaderFields = default; _totalParsedHeaderSize = 0; _isMethodConnect = false; _completionState = default; StreamTimeoutTicks = 0; if (_frameWriter == null) { _frameWriter = new Http3FrameWriter( context.StreamContext, context.TimeoutControl, context.ServiceContext.ServerOptions.Limits.MinResponseDataRate, context.MemoryPool, context.ServiceContext.Log, _streamIdFeature, context.ClientPeerSettings, this); _http3Output = new Http3OutputProducer( _frameWriter, context.MemoryPool, this, context.ServiceContext.Log); Output = _http3Output; RequestBodyPipe = CreateRequestBodyPipe(64 * 1024); // windowSize? QPackDecoder = new QPackDecoder(_context.ServiceContext.ServerOptions.Limits.Http3.MaxRequestHeaderFieldSize); } else { _http3Output.StreamReset(); RequestBodyPipe.Reset(); QPackDecoder.Reset(); } _frameWriter.Reset(context.Transport.Output, context.ConnectionId); }
private static uint HandleEventShutdownComplete(State state, ref ConnectionEvent connectionEvent) { // This is the final event on the connection, so free the GCHandle used by the event callback. state.StateGCHandle.Free(); if (state.ListenerState != null) { // This is inbound connection that never got connected - becasue of TLS validation or some other reason. // Remove connection from pending queue and dispose it. if (state.ListenerState.PendingConnections.TryRemove(state.Handle.DangerousGetHandle(), out MsQuicConnection? connection)) { connection.Dispose(); } state.ListenerState = null; } state.Connection = null; state.ShutdownTcs.SetResult(MsQuicStatusCodes.Success); // Stop accepting new streams. state.AcceptQueue.Writer.TryComplete(); // Stop notifying about available streams. TaskCompletionSource?unidirectionalTcs = null; TaskCompletionSource?bidirectionalTcs = null; lock (state) { unidirectionalTcs = state.NewUnidirectionalStreamsAvailable; bidirectionalTcs = state.NewBidirectionalStreamsAvailable; state.NewUnidirectionalStreamsAvailable = null; state.NewBidirectionalStreamsAvailable = null; } if (unidirectionalTcs is not null) { unidirectionalTcs.SetException(ExceptionDispatchInfo.SetCurrentStackTrace(new QuicOperationAbortedException())); } if (bidirectionalTcs is not null) { bidirectionalTcs.SetException(ExceptionDispatchInfo.SetCurrentStackTrace(new QuicOperationAbortedException())); } return(MsQuicStatusCodes.Success); }
private async Task WriteAsyncCore(byte[] buffer, int offset, int count, CancellationToken cancellationToken) { CancellationTokenRegistration cancellationTokenRegistration = default; try { if (cancellationToken.CanBeCanceled) { cancellationTokenRegistration = cancellationToken.Register(s_OnCancel, this, false); } if (!_inOpaqueMode) { await _outputStream.WriteAsync(buffer, offset, count, cancellationToken).SuppressContextFlow(); } else { #if DEBUG // When using fast path only one outstanding read is permitted. By switching into opaque mode // via IWebSocketStream.SwitchToOpaqueMode (see more detailed comments in interface definition) // caller takes responsibility for enforcing this constraint. Debug.Assert(Interlocked.Increment(ref _outstandingOperations._writes) == 1, "Only one outstanding write allowed at any given time."); #endif _writeTaskCompletionSource = new TaskCompletionSource(); _writeEventArgs !.BufferList = null; _writeEventArgs.SetBuffer(buffer, offset, count); if (WriteAsyncFast(_writeEventArgs)) { await _writeTaskCompletionSource.Task.SuppressContextFlow(); } } } catch (Exception error) { if (s_CanHandleException(error)) { cancellationToken.ThrowIfCancellationRequested(); } throw; } finally { cancellationTokenRegistration.Dispose(); } }
public async ValueTask SendAsync( object message, Action <MessageMetadata>?metadataSetter, AcknowledgementType acknowledgementType, CancellationToken cancellationToken) { string?subscriptionId = null; // For acknowledgement. if (!IsConnected) { throw new InvalidOperationException("Not connected."); } var metadata = _metadataFactory.CreateFor(message); metadataSetter?.Invoke(metadata); metadata.AcknowledgementType = acknowledgementType; var reconnectedTimes = 0; while (reconnectedTimes < _reconnectRetryCount) { // This creates a deadlock. Come up with another solution. // Do not allow starting new operations while reconnect is happening. // await WaitForReconnectAsync(cancellationToken).ConfigureAwait(false); var resource = GetConnectionResource(); try { TaskCompletionSource?tcs = null; if (acknowledgementType == AcknowledgementType.Received) { // Setup subscription for acknowledgement. tcs = new TaskCompletionSource(TaskCreationOptions.RunContinuationsAsynchronously); ValueTask Handler(AcknowledgeReceived acknowledgeReceived) { if (acknowledgeReceived.MessageId == metadata.MessageId) { tcs.SetResult(); } return(default);
public void Decrement() { TaskCompletionSource?availableTcs = null; lock (_syncRoot) { --_actualCount; if (!_availableTcs.Task.IsCompleted) { availableTcs = _availableTcs; _availableTcs = new TaskCompletionSource(TaskCreationOptions.RunContinuationsAsynchronously); } } if (availableTcs is not null) { availableTcs.SetResult(); } }
public async Task CloseNetworkConnectionAsync(CancellationToken cancellationToken) { // need to yield here to make sure that we don't get any exception synchronously await Task.Yield(); CancellationTokenRegistration cancellationTokenRegistration = default; try { if (cancellationToken.CanBeCanceled) { cancellationTokenRegistration = cancellationToken.Register(s_OnCancel, this, false); } #if DEBUG // When using fast path only one outstanding read is permitted. By switching into opaque mode // via IWebSocketStream.SwitchToOpaqueMode (see more detailed comments in interface definition) // caller takes responsibility for enforcing this constraint. Debug.Assert(Interlocked.Increment(ref _outstandingOperations._writes) == 1, "Only one outstanding write allowed at any given time."); #endif _writeTaskCompletionSource = new TaskCompletionSource(); _writeEventArgs !.SetShouldCloseOutput(); if (WriteAsyncFast(_writeEventArgs)) { await _writeTaskCompletionSource.Task.SuppressContextFlow(); } } catch (Exception error) { if (!s_CanHandleException(error)) { throw; } // throw OperationCancelledException when canceled by the caller // otherwise swallow the exception cancellationToken.ThrowIfCancellationRequested(); } finally { cancellationTokenRegistration.Dispose(); } }
private async Task MultipleWriteAsyncCore(IList <ArraySegment <byte> > sendBuffers, CancellationToken cancellationToken) { Debug.Assert(sendBuffers != null, "'sendBuffers' MUST NOT be NULL."); Debug.Assert(sendBuffers.Count == 2, "'sendBuffers.Count' MUST be '2' at this point."); CancellationTokenRegistration cancellationTokenRegistration = default; try { if (cancellationToken.CanBeCanceled) { cancellationTokenRegistration = cancellationToken.Register(s_OnCancel, this, false); } #if DEBUG // When using fast path only one outstanding read is permitted. By switching into opaque mode // via IWebSocketStream.SwitchToOpaqueMode (see more detailed comments in interface definition) // caller takes responsibility for enforcing this constraint. Debug.Assert(Interlocked.Increment(ref _outstandingOperations._writes) == 1, "Only one outstanding write allowed at any given time."); #endif _writeTaskCompletionSource = new TaskCompletionSource(); _writeEventArgs !.SetBuffer(null, 0, 0); _writeEventArgs.BufferList = sendBuffers; if (WriteAsyncFast(_writeEventArgs)) { await _writeTaskCompletionSource.Task.SuppressContextFlow(); } } catch (Exception error) { if (s_CanHandleException(error)) { cancellationToken.ThrowIfCancellationRequested(); } throw; } finally { cancellationTokenRegistration.Dispose(); } }
public async ValueTask <ConnectionContext> AcceptAsync(CancellationToken cancellationToken = default) { if (_currentConnection != null && _connectionClosed != null) { await _connectionClosed.Task; } if (_unbound) { return(null); } while (!cancellationToken.IsCancellationRequested && !_unbound) { try { var newContext = await _client.ConnectToServer(cancellationToken); var connectionClosed = new TaskCompletionSource(); newContext.ConnectionClosed.Register(() => { _logger.LogInformation("Server connection to {0} lost", _client.ServerEndPoint); connectionClosed.SetResult(); }); _currentConnection = newContext; _connectionClosed = connectionClosed; _logger.LogInformation("Server connection to {0} established", _client.ServerEndPoint); return(newContext); } catch (Exception ex) { _logger.LogError(ex, "Error establishing connection to {0}", _client.ServerEndPoint); } } return(null); }
private PendingMessage(ReadOnlyOwnedMemory <byte, IMemoryOwner <byte> > content, TaskCompletionSource?messageSentTaskSource, CancellationToken cancellationToken) { Content = content; CancellationToken = cancellationToken; this.messageSentTaskSource = messageSentTaskSource; }
public ToDo(Action?action, TaskCompletionSource?tcs) { Action = action; Complete = tcs; Task = null; }
public ToDo(Func <Task>?action, TaskCompletionSource?tcs) { Action = null; Complete = tcs; Task = action; }