try
{
+ Debug.Assert(!Monitor.IsEntered(_state));
MsQuicApi.Api.SetCallbackHandlerDelegate(
_state.Handle,
s_connectionDelegate,
_state.StateGCHandle = GCHandle.Alloc(_state);
try
{
+ Debug.Assert(!Monitor.IsEntered(_state));
uint status = MsQuicApi.Api.ConnectionOpenDelegate(
MsQuicApi.Api.Registration,
s_connectionDelegate,
if (!state.Connected)
{
// Connected will already be true for connections accepted from a listener.
-
+ Debug.Assert(!Monitor.IsEntered(state));
SOCKADDR_INET inetAddress = MsQuicParameterHelpers.GetINetParam(MsQuicApi.Api, state.Handle, QUIC_PARAM_LEVEL.CONNECTION, (uint)QUIC_PARAM_CONN.LOCAL_ADDRESS);
Debug.Assert(state.Connection != null);
TaskCompletionSource? tcs = _state.NewUnidirectionalStreamsAvailable;
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 = GetRemoteAvailableUnidirectionalStreamCount();
lock (_state)
{
if (_state.NewUnidirectionalStreamsAvailable is null)
throw new QuicOperationAbortedException();
}
- if (GetRemoteAvailableUnidirectionalStreamCount() > 0)
+ if (count > 0)
{
return ValueTask.CompletedTask;
}
_state.NewUnidirectionalStreamsAvailable = new TaskCompletionSource(TaskCreationOptions.RunContinuationsAsynchronously);
}
+
tcs = _state.NewUnidirectionalStreamsAvailable;
}
}
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)
throw new QuicOperationAbortedException();
}
- if (GetRemoteAvailableBidirectionalStreamCount() > 0)
+ if (count > 0)
{
return ValueTask.CompletedTask;
}
internal override int GetRemoteAvailableUnidirectionalStreamCount()
{
+ Debug.Assert(!Monitor.IsEntered(_state));
return MsQuicParameterHelpers.GetUShortParam(MsQuicApi.Api, _state.Handle, QUIC_PARAM_LEVEL.CONNECTION, (uint)QUIC_PARAM_CONN.LOCAL_UNIDI_STREAM_COUNT);
}
internal override int GetRemoteAvailableBidirectionalStreamCount()
{
+ Debug.Assert(!Monitor.IsEntered(_state));
return MsQuicParameterHelpers.GetUShortParam(MsQuicApi.Api, _state.Handle, QUIC_PARAM_LEVEL.CONNECTION, (uint)QUIC_PARAM_CONN.LOCAL_BIDI_STREAM_COUNT);
}
SOCKADDR_INET address = MsQuicAddressHelpers.IPEndPointToINet((IPEndPoint)_remoteEndPoint);
unsafe
{
+ Debug.Assert(!Monitor.IsEntered(_state));
status = MsQuicApi.Api.SetParamDelegate(_state.Handle, QUIC_PARAM_LEVEL.CONNECTION, (uint)QUIC_PARAM_CONN.REMOTE_ADDRESS, (uint)sizeof(SOCKADDR_INET), (byte*)&address);
QuicExceptionHelpers.ThrowIfFailed(status, "Failed to connect to peer.");
}
try
{
+ Debug.Assert(!Monitor.IsEntered(_state));
status = MsQuicApi.Api.ConnectionStartDelegate(
_state.Handle,
_configuration,
try
{
+ Debug.Assert(!Monitor.IsEntered(_state));
MsQuicApi.Api.ConnectionShutdownDelegate(
_state.Handle,
Flags,
if (_state.Handle != null)
{
// Handle can be null if outbound constructor failed and we are called from finalizer.
+ Debug.Assert(!Monitor.IsEntered(_state));
MsQuicApi.Api.ConnectionShutdownDelegate(
_state.Handle,
QUIC_CONNECTION_SHUTDOWN_FLAGS.SILENT,