Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Use System.Threading.Lock in Kestrel #57236

Open
wants to merge 1 commit into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
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
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ internal sealed partial class CertificatePathWatcher : IDisposable
private readonly string _contentRootDir;
private readonly ILogger<CertificatePathWatcher> _logger;

private readonly object _metadataLock = new();
private readonly Lock _metadataLock = new();

/// <remarks>Acquire <see cref="_metadataLock"/> before accessing.</remarks>
private readonly Dictionary<string, DirectoryWatchMetadata> _metadataForDirectory = new();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ internal class Http1OutputProducer : IHttpOutputProducer, IDisposable
private readonly TimingPipeFlusher _flusher;

// This locks access to all of the below fields
private readonly object _contextLock = new object();
private readonly Lock _contextLock = new();

private bool _pipeWriterCompleted;
private bool _aborted;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ internal abstract partial class HttpProtocol : IHttpResponseControl
private Stack<KeyValuePair<Func<object, Task>, object>>? _onStarting;
private Stack<KeyValuePair<Func<object, Task>, object>>? _onCompleted;

private readonly object _abortLock = new object();
private readonly Lock _abortLock = new();
protected volatile bool _connectionAborted;
private bool _preventRequestAbortedCancellation;
private CancellationTokenSource? _abortedCts;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ internal sealed class InputFlowControl
private FlowControl _flow;
ladeak marked this conversation as resolved.
Show resolved Hide resolved
private int _pendingUpdateSize;
private bool _windowUpdatesDisabled;
private readonly object _flowLock = new object();
private readonly Lock _flowLock = new();

public InputFlowControl(uint initialWindowSize, uint minWindowSizeIncrement)
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,7 @@ internal sealed class Http2FrameWriter

private bool IsFlowControlQueueLimitEnabled => _maximumFlowControlQueueSize > 0;

private readonly object _writeLock = new object();
private readonly Lock _writeLock = new();
private readonly Http2Frame _outgoingFrame;
private readonly Http2HeadersEnumerator _headersEnumerator = new Http2HeadersEnumerator();
private readonly ConcurrentPipeWriter _outputWriter;
Expand Down Expand Up @@ -99,7 +99,7 @@ internal sealed class Http2FrameWriter
private bool _completed;
private bool _aborted;

private readonly object _windowUpdateLock = new();
private readonly Lock _windowUpdateLock = new();
private long _connectionWindow;
private readonly Queue<Http2OutputProducer> _waitingForMoreConnectionWindow = new();
// This is the stream that consumed the last set of connection window
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ internal sealed class Http2OutputProducer : IHttpOutputProducer, IHttpOutputAbor

private readonly MemoryPool<byte> _memoryPool;
private readonly Http2Stream _stream;
private readonly object _dataWriterLock = new object();
private readonly Lock _dataWriterLock = new();
private readonly Pipe _pipe;
private readonly ConcurrentPipeWriter _pipeWriter;
private readonly PipeReader _pipeReader;
Expand Down Expand Up @@ -599,7 +599,7 @@ public void Reset()

internal void OnRequestProcessingEnded()
{
var shouldCompleteStream = false;
bool shouldCompleteStream;
lock (_dataWriterLock)
{
if (_requestProcessingComplete)
Expand All @@ -625,7 +625,7 @@ internal void OnRequestProcessingEnded()

internal ValueTask<FlushResult> CompleteResponseAsync()
{
var shouldCompleteStream = false;
bool shouldCompleteStream;
ValueTask<FlushResult> task = default;

lock (_dataWriterLock)
Expand Down Expand Up @@ -705,8 +705,7 @@ internal Memory<byte> GetFakeMemory(int minSize)

public bool TryUpdateStreamWindow(int bytes)
{
var schedule = false;

bool schedule;
lock (_dataWriterLock)
{
var maxUpdate = Http2PeerSettings.MaxWindowSize - _streamWindow;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ internal abstract partial class Http2Stream : HttpProtocol, IThreadPoolWorkItem,
internal long DrainExpirationTimestamp { get; set; }

private StreamCompletionFlags _completionState;
private readonly object _completionLock = new object();
private readonly Lock _completionLock = new();

public void Initialize(Http2StreamContext context)
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,9 +35,9 @@ internal sealed class Http3Connection : IHttp3StreamLifetimeHandler, IRequestPro
// so start highest opened request stream ID at -4.
private const long DefaultHighestOpenedRequestStreamId = -4;

private readonly object _sync = new();
private readonly Lock _sync = new();
private readonly HttpMultiplexedConnectionContext _context;
private readonly object _protocolSelectionLock = new();
private readonly Lock _protocolSelectionLock = new();
private readonly StreamCloseAwaitable _streamCompletionAwaitable = new();
private readonly IProtocolErrorCodeFeature _errorCodeFeature;
private readonly Dictionary<long, WebTransportSession>? _webtransportSessions;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ internal abstract class Http3ControlStream : IHttp3Stream, IThreadPoolWorkItem
private readonly Http3RawFrame _incomingFrame = new Http3RawFrame();
private volatile int _isClosed;
private long _headerType;
private readonly object _completionLock = new();
private readonly Lock _completionLock = new();

private bool _haveReceivedSettingsFrame;
private StreamCompletionFlags _completionState;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ internal sealed class Http3FrameWriter
private const int MaxDataFrameSize = 16 * 1024;
private const int HeaderBufferSize = 16 * 1024;

private readonly object _writeLock = new object();
private readonly Lock _writeLock = new();

private readonly int _maxTotalHeaderSize;
private readonly ConnectionContext _connectionContext;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ internal sealed class Http3OutputProducer : IHttpOutputProducer, IHttpOutputAbor
private readonly Pipe _pipe;
private readonly PipeWriter _pipeWriter;
private readonly PipeReader _pipeReader;
private readonly object _dataWriterLock = new object();
private readonly Lock _dataWriterLock = new();
private ValueTask<FlushResult> _dataWriteProcessingTask;
private bool _startedWritingDataFrames;
private bool _streamCompleted;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ internal abstract partial class Http3Stream : HttpProtocol, IHttp3Stream, IHttpS
private Http3MessageBody? _messageBody;

private readonly ManualResetValueTaskSource<object?> _appCompletedTaskSource = new();
private readonly object _completionLock = new();
private readonly Lock _completionLock = new();

protected RequestHeaderParsingState _requestHeaderParsingState;
protected readonly Http3RawFrame _incomingFrame = new();
Expand Down
2 changes: 1 addition & 1 deletion src/Servers/Kestrel/Core/src/Internal/HttpConnection.cs
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ internal sealed class HttpConnection : ITimeoutHandler
private readonly TimeProvider _timeProvider;
private readonly TimeoutControl _timeoutControl;

private readonly object _protocolSelectionLock = new object();
private readonly Lock _protocolSelectionLock = new();
private ProtocolSelectionState _protocolSelectionState = ProtocolSelectionState.Initializing;
private Http1Connection? _http1Connection;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Infrastructure;
internal abstract class KestrelConnection : IConnectionHeartbeatFeature, IConnectionCompleteFeature, IConnectionLifetimeNotificationFeature, IConnectionMetricsContextFeature
{
private List<(Action<object> handler, object state)>? _heartbeatHandlers;
private readonly object _heartbeatLock = new object();
private readonly Lock _heartbeatLock = new();

private Stack<KeyValuePair<Func<object, Task>, object>>? _onCompleted;
private bool _completed;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ internal sealed class ConcurrentPipeWriter : PipeWriter

private static readonly Exception _successfullyCompletedSentinel = new UnreachableException();

private readonly object _sync;
private readonly Lock _sync;
private readonly PipeWriter _innerPipeWriter;
private readonly MemoryPool<byte> _pool;
private readonly BufferSegmentStack _bufferSegmentPool = new BufferSegmentStack(InitialSegmentPoolSize);
Expand Down Expand Up @@ -50,7 +50,7 @@ internal sealed class ConcurrentPipeWriter : PipeWriter
// If an Complete() is called while a flush is in progress, we clean up after the flush loop completes, and call Complete() on the inner PipeWriter.
private Exception? _completeException;

public ConcurrentPipeWriter(PipeWriter innerPipeWriter, MemoryPool<byte> pool, object sync)
public ConcurrentPipeWriter(PipeWriter innerPipeWriter, MemoryPool<byte> pool, Lock sync)
{
_innerPipeWriter = innerPipeWriter;
_pool = pool;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ internal sealed class TimeoutControl : ITimeoutControl, IConnectionTimeoutFeatur
private long _lastTimestamp;
private long _timeoutTimestamp = long.MaxValue;

private readonly object _readTimingLock = new object();
private readonly Lock _readTimingLock = new();
private MinDataRate? _minReadRate;
private long _minReadRateGracePeriodTicks;
private bool _readTimingEnabled;
Expand All @@ -28,7 +28,7 @@ internal sealed class TimeoutControl : ITimeoutControl, IConnectionTimeoutFeatur
private int _concurrentIncompleteRequestBodies;
private int _concurrentAwaitingReads;

private readonly object _writeTimingLock = new object();
private readonly Lock _writeTimingLock = new();
private int _concurrentAwaitingWrites;
private long _writeTimingTimeoutTimestamp;

Expand Down Expand Up @@ -142,8 +142,7 @@ private void CheckForReadDataRateTimeout(long timestamp)

private void CheckForWriteDataRateTimeout(long timestamp)
{
var timeout = false;

bool timeout;
lock (_writeTimingLock)
{
// Assume overly long tick intervals are the result of server resource starvation.
Expand Down
10 changes: 5 additions & 5 deletions src/Servers/Kestrel/Core/test/ConcurrentPipeWriterTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ public async Task PassthroughIfAllFlushesAreAwaited()
new TaskCompletionSource<FlushResult>(TaskCreationOptions.RunContinuationsAsynchronously),
};

var sync = new object();
var sync = new Lock();
var mockPipeWriter = new MockPipeWriter(pipeWriterFlushTcsArray);
var concurrentPipeWriter = new ConcurrentPipeWriter(mockPipeWriter, diagnosticPool, sync);

Expand Down Expand Up @@ -89,7 +89,7 @@ public async Task QueuesIfFlushIsNotAwaited()
new TaskCompletionSource<FlushResult>(TaskCreationOptions.RunContinuationsAsynchronously),
};

var sync = new object();
var sync = new Lock();
var mockPipeWriter = new MockPipeWriter(pipeWriterFlushTcsArray);
var concurrentPipeWriter = new ConcurrentPipeWriter(mockPipeWriter, diagnosticPool, sync);
var flushTask0 = default(ValueTask<FlushResult>);
Expand Down Expand Up @@ -186,7 +186,7 @@ public async Task KeepsQueueIfInnerFlushFinishesBetweenGetMemoryAndAdvance()
new TaskCompletionSource<FlushResult>(TaskCreationOptions.RunContinuationsAsynchronously),
};

var sync = new object();
var sync = new Lock();
var mockPipeWriter = new MockPipeWriter(pipeWriterFlushTcsArray);
var concurrentPipeWriter = new ConcurrentPipeWriter(mockPipeWriter, diagnosticPool, sync);
var memory = default(Memory<byte>);
Expand Down Expand Up @@ -270,7 +270,7 @@ public async Task CompleteFlushesQueuedBytes()
new TaskCompletionSource<FlushResult>(TaskCreationOptions.RunContinuationsAsynchronously),
};

var sync = new object();
var sync = new Lock();
var mockPipeWriter = new MockPipeWriter(pipeWriterFlushTcsArray);
var concurrentPipeWriter = new ConcurrentPipeWriter(mockPipeWriter, diagnosticPool, sync);
var memory = default(Memory<byte>);
Expand Down Expand Up @@ -338,7 +338,7 @@ public async Task CancelPendingFlushInterruptsFlushLoop()
new TaskCompletionSource<FlushResult>(TaskCreationOptions.RunContinuationsAsynchronously),
};

var sync = new object();
var sync = new Lock();
var mockPipeWriter = new MockPipeWriter(pipeWriterFlushTcsArray);
var concurrentPipeWriter = new ConcurrentPipeWriter(mockPipeWriter, diagnosticPool, sync);
var flushTask0 = default(ValueTask<FlushResult>);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ internal sealed class NamedPipeConnection : TransportConnection, IConnectionName
private bool _connectionShutdown;
private bool _streamDisconnected;
private Exception? _shutdownReason;
private readonly object _shutdownLock = new object();
private readonly Lock _shutdownLock = new();

// Internal for testing.
internal Task _receivingTask = Task.CompletedTask;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,9 +20,9 @@ internal partial class QuicConnectionContext : TransportMultiplexedConnection
private bool _streamPoolHeartbeatInitialized;
// Ticks updated once per-second in heartbeat event.
private long _heartbeatTimestamp;
private readonly object _poolLock = new object();
private readonly Lock _poolLock = new();

private readonly object _shutdownLock = new object();
private readonly Lock _shutdownLock = new();
private readonly QuicConnection _connection;
private readonly QuicTransportContext _context;
private readonly ILogger _log;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ internal partial class QuicStreamContext : TransportConnection, IPooledStream, I
private bool _streamClosed;
private bool _serverAborted;
private bool _clientAbort;
private readonly object _shutdownLock = new object();
private readonly Lock _shutdownLock = new();

public QuicStreamContext(QuicConnectionContext connection, QuicTransportContext context)
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ internal sealed partial class SocketConnection : TransportConnection
private readonly IDuplexPipe _originalTransport;
private readonly CancellationTokenSource _connectionClosedTokenSource = new CancellationTokenSource();

private readonly object _shutdownLock = new object();
private readonly Lock _shutdownLock = new();
private volatile Exception? _shutdownReason;
private Task? _sendingTask;
private Task? _receivingTask;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Microbenchmarks;

public class MockHttpContextFactory : IHttpContextFactory
{
private readonly object _lock = new object();
private readonly Lock _lock = new();
private readonly Queue<DefaultHttpContext> _cache = new Queue<DefaultHttpContext>();

public HttpContext Create(IFeatureCollection featureCollection)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -423,7 +423,7 @@ private class TestEventListener : EventListener
private readonly ConcurrentQueue<EventSnapshot> _events = new ConcurrentQueue<EventSnapshot>();
private readonly ILogger _logger;

private readonly object _disposeLock = new object();
private readonly Lock _disposeLock = new();
private bool _disposed;

public TestEventListener()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -131,7 +131,7 @@ protected static IEnumerable<KeyValuePair<string, string>> ReadRateRequestHeader
protected readonly Dictionary<string, string> _decodedHeaders = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase);
protected readonly RequestFields _receivedRequestFields = new RequestFields();
protected readonly HashSet<int> _abortedStreamIds = new HashSet<int>();
protected readonly object _abortedStreamIdsLock = new object();
protected readonly Lock _abortedStreamIdsLock = new();
protected readonly TaskCompletionSource _closingStateReached = new TaskCompletionSource(TaskCreationOptions.RunContinuationsAsynchronously);
protected readonly TaskCompletionSource _closedStateReached = new TaskCompletionSource(TaskCreationOptions.RunContinuationsAsynchronously);

Expand Down
2 changes: 1 addition & 1 deletion src/Shared/ServerInfrastructure/DuplexPipeStreamAdapter.cs
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal;
internal class DuplexPipeStreamAdapter<TStream> : DuplexPipeStream, IDuplexPipe where TStream : Stream
{
private bool _disposed;
private readonly object _disposeLock = new object();
private readonly Lock _disposeLock = new();

public DuplexPipeStreamAdapter(IDuplexPipe duplexPipe, Func<Stream, TStream> createStream) :
this(duplexPipe, new StreamPipeReaderOptions(leaveOpen: true), new StreamPipeWriterOptions(leaveOpen: true), createStream)
Expand Down
Loading