Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
Use shared MsQuicBuffers struct
  • Loading branch information
rzikm committed May 12, 2022
commit d5feac52ab3795f1abafbdc92a6db52496d60c12
Original file line number Diff line number Diff line change
Expand Up @@ -39,35 +39,94 @@ private void FreeNativeMemory()
NativeMemory.Free(buffers);
}

private void Reserve(int count)
{
if (_handles.Length < count)
{
_handles = new MemoryHandle[count];
FreeNativeMemory();
_buffers = (QUIC_BUFFER*)NativeMemory.Alloc((nuint)count, (nuint)sizeof(QUIC_BUFFER));
}
}

private void SetBuffer(int index, ReadOnlyMemory<byte> buffer)
{
MemoryHandle handle = buffer.Pin();

_handles[index] = handle;
_buffers[index].Buffer = (byte*)handle.Pointer;
_buffers[index].Length = (uint)buffer.Length;
}

/// <summary>
/// The method initializes QUIC_BUFFER* with data from inputs, converted via toBuffer.
/// Initializes QUIC_BUFFER* with data from inputs, converted via toBuffer.
/// Note that the struct either needs to be freshly created via new or previously cleaned up with Reset.
/// </summary>
/// <param name="inputs">Inputs to get their byte array, pin them and pepare them to be passed to MsQuic as QUIC_BUFFER*.</param>
/// <param name="toBuffer">Method extracting byte array from the inputs, e.g. applicationProtocol.Protocol.</param>
/// <typeparam name="T">The type of the inputs.</typeparam>
public void Initialize<T>(IList<T> inputs, Func<T, ReadOnlyMemory<byte>> toBuffer)
{
if (_handles.Length < inputs.Count)
Reserve(inputs.Count);
_count = inputs.Count;

for (int i = 0; i < inputs.Count; ++i)
{
_handles = new MemoryHandle[inputs.Count];
ReadOnlyMemory<byte> buffer = toBuffer(inputs[i]);
SetBuffer(i, buffer);
}
if (_count < inputs.Count)
}

/// <summary>
/// Initializes QUIC_BUFFER* with the provided buffer.
/// Note that the struct either needs to be freshly created via new or previously cleaned up with Reset.
/// </summary>
/// <param name="buffer">Buffer to be passed to MsQuic as QUIC_BUFFER*.</param>
public void Initialize(ReadOnlyMemory<byte> buffer)
{
Reserve(1);
_count = 1;
SetBuffer(0, buffer);
}

/// <summary>
/// Initializes QUIC_BUFFER* with the provided buffers.
/// Note that the struct either needs to be freshly created via new or previously cleaned up with Reset.
/// </summary>
/// <param name="buffers">Buffers to be passed to MsQuic as QUIC_BUFFER*.</param>
public void Initialize(ReadOnlySequence<byte> buffers)
{
int count = 0;
foreach (ReadOnlyMemory<byte> _ in buffers)
{
FreeNativeMemory();
_buffers = (QUIC_BUFFER*)NativeMemory.Alloc((nuint)sizeof(QUIC_BUFFER), (nuint)inputs.Count);
++count;
}

_count = inputs.Count;
Reserve(count);
_count = count;
count = 0;

for (int i = 0; i < inputs.Count; ++i)
foreach (ReadOnlyMemory<byte> buffer in buffers)
{
ReadOnlyMemory<byte> buffer = toBuffer(inputs[i]);
MemoryHandle handle = buffer.Pin();
SetBuffer(count, buffer);
++count;
}
}

_handles[i] = handle;
_buffers[i].Buffer = (byte*)handle.Pointer;
_buffers[i].Length = (uint)buffer.Length;
/// <summary>
/// Initializes QUIC_BUFFER* with the provided buffers.
/// Note that the struct either needs to be freshly created via new or previously cleaned up with Reset.
/// </summary>
/// <param name="buffers">Buffers to be passed to MsQuic as QUIC_BUFFER*.</param>
public void Initialize(ReadOnlyMemory<ReadOnlyMemory<byte>> buffers)
{
int count = buffers.Length;
Reserve(count);
_count = count;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nit: I believe it is already part of Reserve(count)

Suggested change
_count = count;


for (int i = 0; i < buffers.Length; i++)
{
SetBuffer(i, buffers.Span[i]);
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -58,11 +58,7 @@ private sealed class State
public SendState SendState;
public long SendErrorCode = -1;

// Buffers to hold during a call to send.
public MemoryHandle[] BufferArrays = new MemoryHandle[1];
public IntPtr SendQuicBuffers;
public int SendBufferMaxCount;
public int SendBufferCount;
public MsQuicBuffers SendBuffers;

// Resettable completions to be used for multiple calls to send.
public readonly ResettableCompletionSource<int> SendResettableCompletionSource = new ResettableCompletionSource<int>();
Expand All @@ -85,15 +81,19 @@ private sealed class State
// Set once stream have been shutdown.
public readonly TaskCompletionSource ShutdownCompletionSource = new TaskCompletionSource(TaskCreationOptions.RunContinuationsAsynchronously);

public State()
{
SendBuffers = new MsQuicBuffers();
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Any specific reason it should be in a constructor and not assigned on declaration as other fields?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Putting = new MsQuicBuffers() in the field initializer triggers "Don't assign default values" or similar warning, and leaving it uninitialized breaks because the MsQuicBuffers._handles is null.

}

public void Cleanup()
{
if (NetEventSource.Log.IsEnabled()) NetEventSource.Info(this, $"{Handle} releasing handles.");

ShutdownState = ShutdownState.Finished;
CleanupSendState(this);
Handle?.Dispose();
Marshal.FreeHGlobal(SendQuicBuffers);
SendQuicBuffers = IntPtr.Zero;
SendBuffers.Dispose();
if (StateGCHandle.IsAllocated) StateGCHandle.Free();
ConnectionState?.RemoveStream(null);
}
Expand Down Expand Up @@ -323,10 +323,10 @@ private unsafe ValueTask WriteAsyncInternal<TAdapter>(TAdapter adapter, QUIC_SEN
adapter.SetupSendState(_state);

Debug.Assert(!Monitor.IsEntered(_state), "!Monitor.IsEntered(_state)");
uint status = MsQuicApi.Api.StreamSendDelegate(
_state.Handle,
(QuicBuffer*)_state.SendQuicBuffers,
(uint)_state.SendBufferCount,
int status = MsQuicApi.Api.ApiTable->StreamSend(
_state.Handle.QuicHandle,
_state.SendBuffers.Buffers,
(uint)_state.SendBuffers.Count,
flags,
IntPtr.Zero);

Expand Down Expand Up @@ -1416,12 +1416,7 @@ private static void CleanupSendState(State state)
lock (state)
{
Debug.Assert(state.SendState != SendState.Pending);
Debug.Assert(state.SendBufferCount <= state.BufferArrays.Length);

for (int i = 0; i < state.SendBufferCount; i++)
{
state.BufferArrays[i].Dispose();
}
state.SendBuffers.Reset();
}
}

Expand Down Expand Up @@ -1713,27 +1708,6 @@ private interface ISendBufferAdapter
void SetupSendState(State state);

bool IsEmpty { get; }

static unsafe void Reserve(State state, int count)
{
if (state.SendBufferMaxCount < count)
{
NativeMemory.Free((void*)state.SendQuicBuffers);
state.SendQuicBuffers = IntPtr.Zero;
state.SendQuicBuffers = (IntPtr)NativeMemory.Alloc((nuint)count, (nuint)sizeof(QuicBuffer));
state.SendBufferMaxCount = count;
state.BufferArrays = new MemoryHandle[count];
}
}

static unsafe void SetBuffer(State state, int index, ReadOnlyMemory<byte> buffer)
{
MemoryHandle handle = buffer.Pin();
QuicBuffer* quicBuffer = (QuicBuffer*)state.SendQuicBuffers + index;
quicBuffer->Length = (uint)buffer.Length;
quicBuffer->Buffer = (byte*)handle.Pointer;
state.BufferArrays[index] = handle;
}
}

private struct WriteMemoryAdapter : ISendBufferAdapter
Expand All @@ -1744,11 +1718,9 @@ private struct WriteMemoryAdapter : ISendBufferAdapter

public bool IsEmpty => _buffer.IsEmpty;

public unsafe void SetupSendState(State state)
public void SetupSendState(State state)
{
ISendBufferAdapter.Reserve(state, 1);
ISendBufferAdapter.SetBuffer(state, 0, _buffer);
state.SendBufferCount = 1;
state.SendBuffers.Initialize(_buffer);
}
}

Expand All @@ -1760,24 +1732,9 @@ private struct WriteSequenceAdapter : ISendBufferAdapter

public bool IsEmpty => _buffers.IsEmpty;

public unsafe void SetupSendState(State state)
public void SetupSendState(State state)
{
int count = 0;

foreach (ReadOnlyMemory<byte> _ in _buffers)
{
++count;
}

ISendBufferAdapter.Reserve(state, count);
state.SendBufferCount = count;
count = 0;

foreach (ReadOnlyMemory<byte> buffer in _buffers)
{
ISendBufferAdapter.SetBuffer(state, count, buffer);
++count;
}
state.SendBuffers.Initialize(_buffers);
}
}

Expand All @@ -1789,18 +1746,9 @@ private struct WriteMemoryOfMemoryAdapter : ISendBufferAdapter

public bool IsEmpty => _buffers.IsEmpty;

public unsafe void SetupSendState(State state)
public void SetupSendState(State state)
{
int count = _buffers.Length;
ISendBufferAdapter.Reserve(state, count);
state.SendBufferCount = count;
count = 0;

foreach (ReadOnlyMemory<byte> buffer in _buffers.Span)
{
ISendBufferAdapter.SetBuffer(state, count, buffer);
++count;
}
state.SendBuffers.Initialize(_buffers);
}
}
}
Expand Down