Skip to content

Commit b44492d

Browse files
wfurtTomas Weinfurt
andauthored
improve TLS perf on macOS (#32338)
* improve TLS perf on macOS * feedback from review * feedback from review * remove unnecesary locking Co-authored-by: Tomas Weinfurt <[email protected]>
1 parent a2527e9 commit b44492d

File tree

2 files changed

+43
-95
lines changed

2 files changed

+43
-95
lines changed

src/libraries/System.Net.Security/src/System/Net/Security/Pal.OSX/SafeDeleteSslContext.cs

Lines changed: 38 additions & 70 deletions
Original file line numberDiff line numberDiff line change
@@ -14,11 +14,12 @@ namespace System.Net
1414
{
1515
internal sealed class SafeDeleteSslContext : SafeDeleteContext
1616
{
17+
private const int InitialBufferSize = 2048;
1718
private SafeSslHandle _sslContext;
1819
private Interop.AppleCrypto.SSLReadFunc _readCallback;
1920
private Interop.AppleCrypto.SSLWriteFunc _writeCallback;
20-
private Queue<byte> _fromConnection = new Queue<byte>();
21-
private Queue<byte> _toConnection = new Queue<byte>();
21+
private ArrayBuffer _inputBuffer = new ArrayBuffer(InitialBufferSize);
22+
private ArrayBuffer _outputBuffer = new ArrayBuffer(InitialBufferSize);
2223

2324
public SafeSslHandle SslContext => _sslContext;
2425

@@ -141,10 +142,12 @@ protected override void Dispose(bool disposing)
141142
{
142143
if (disposing)
143144
{
144-
if (null != _sslContext)
145+
SafeSslHandle sslContext = _sslContext;
146+
if (null != sslContext)
145147
{
146-
_sslContext.Dispose();
147-
_sslContext = null!;
148+
_inputBuffer.Dispose();
149+
_outputBuffer.Dispose();
150+
sslContext.Dispose();
148151
}
149152
}
150153

@@ -153,18 +156,15 @@ protected override void Dispose(bool disposing)
153156

154157
private unsafe int WriteToConnection(void* connection, byte* data, void** dataLength)
155158
{
156-
ulong toWrite = (ulong)*dataLength;
157-
byte* readFrom = data;
159+
ulong length = (ulong)*dataLength;
160+
Debug.Assert(length <= int.MaxValue);
158161

159-
lock (_toConnection)
160-
{
161-
while (toWrite > 0)
162-
{
163-
_toConnection.Enqueue(*readFrom);
164-
readFrom++;
165-
toWrite--;
166-
}
167-
}
162+
int toWrite = (int)length;
163+
var inputBuffer = new ReadOnlySpan<byte>(data, toWrite);
164+
165+
_outputBuffer.EnsureAvailableSpace(toWrite);
166+
inputBuffer.CopyTo(_outputBuffer.AvailableSpan);
167+
_outputBuffer.Commit(toWrite);
168168

169169
// Since we can enqueue everything, no need to re-assign *dataLength.
170170
const int noErr = 0;
@@ -175,78 +175,51 @@ private unsafe int ReadFromConnection(void* connection, byte* data, void** dataL
175175
{
176176
const int noErr = 0;
177177
const int errSSLWouldBlock = -9803;
178-
179178
ulong toRead = (ulong)*dataLength;
180179

181180
if (toRead == 0)
182181
{
183-
184182
return noErr;
185183
}
186184

187185
uint transferred = 0;
188186

189-
lock (_fromConnection)
187+
if (_inputBuffer.ActiveLength == 0)
190188
{
189+
*dataLength = (void*)0;
190+
return errSSLWouldBlock;
191+
}
191192

192-
if (_fromConnection.Count == 0)
193-
{
194-
195-
*dataLength = (void*)0;
196-
return errSSLWouldBlock;
197-
}
193+
int limit = Math.Min((int)toRead, _inputBuffer.ActiveLength);
198194

199-
byte* writePos = data;
200-
201-
while (transferred < toRead && _fromConnection.Count > 0)
202-
{
203-
*writePos = _fromConnection.Dequeue();
204-
writePos++;
205-
transferred++;
206-
}
207-
}
195+
_inputBuffer.ActiveSpan.Slice(0, limit).CopyTo(new Span<byte>(data, limit));
196+
_inputBuffer.Discard(limit);
197+
transferred = (uint)limit;
208198

209199
*dataLength = (void*)transferred;
210200
return noErr;
211201
}
212202

213-
internal void Write(byte[] buf, int offset, int count)
214-
{
215-
Debug.Assert(buf != null);
216-
Debug.Assert(offset >= 0);
217-
Debug.Assert(count >= 0);
218-
Debug.Assert(count <= buf.Length - offset);
219-
220-
Write(buf.AsSpan(offset, count));
221-
}
222-
223203
internal void Write(ReadOnlySpan<byte> buf)
224204
{
225-
lock (_fromConnection)
226-
{
227-
foreach (byte b in buf)
228-
{
229-
_fromConnection.Enqueue(b);
230-
}
231-
}
205+
_inputBuffer.EnsureAvailableSpace(buf.Length);
206+
buf.CopyTo(_inputBuffer.AvailableSpan);
207+
_inputBuffer.Commit(buf.Length);
232208
}
233209

234-
internal int BytesReadyForConnection => _toConnection.Count;
210+
internal int BytesReadyForConnection => _outputBuffer.ActiveLength;
235211

236212
internal byte[]? ReadPendingWrites()
237213
{
238-
lock (_toConnection)
214+
if (_outputBuffer.ActiveLength == 0)
239215
{
240-
if (_toConnection.Count == 0)
241-
{
242-
return null;
243-
}
216+
return null;
217+
}
244218

245-
byte[] data = _toConnection.ToArray();
246-
_toConnection.Clear();
219+
byte[] buffer = _outputBuffer.ActiveSpan.ToArray();
220+
_outputBuffer.Discard(_outputBuffer.ActiveLength);
247221

248-
return data;
249-
}
222+
return buffer;
250223
}
251224

252225
internal int ReadPendingWrites(byte[] buf, int offset, int count)
@@ -256,17 +229,12 @@ internal int ReadPendingWrites(byte[] buf, int offset, int count)
256229
Debug.Assert(count >= 0);
257230
Debug.Assert(count <= buf.Length - offset);
258231

259-
lock (_toConnection)
260-
{
261-
int limit = Math.Min(count, _toConnection.Count);
232+
int limit = Math.Min(count, _outputBuffer.ActiveLength);
262233

263-
for (int i = 0; i < limit; i++)
264-
{
265-
buf[offset + i] = _toConnection.Dequeue();
266-
}
234+
_outputBuffer.ActiveSpan.Slice(0, limit).CopyTo(new Span<byte>(buf, offset, limit));
235+
_outputBuffer.Discard(limit);
267236

268-
return limit;
269-
}
237+
return limit;
270238
}
271239

272240
private static readonly SslProtocols[] s_orderedSslProtocols = new SslProtocols[5]

src/libraries/System.Net.Security/src/System/Net/Security/SslStreamPal.OSX.cs

Lines changed: 5 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -92,16 +92,11 @@ public static SecurityStatusPal EncryptMessage(
9292
MemoryHandle memHandle = input.Pin();
9393
try
9494
{
95-
PAL_TlsIo status;
96-
97-
lock (sslHandle)
98-
{
99-
status = Interop.AppleCrypto.SslWrite(
95+
PAL_TlsIo status = Interop.AppleCrypto.SslWrite(
10096
sslHandle,
10197
(byte*)memHandle.Pointer,
10298
input.Length,
10399
out int written);
104-
}
105100

106101
if (status < 0)
107102
{
@@ -154,19 +149,13 @@ public static SecurityStatusPal DecryptMessage(
154149
SafeDeleteSslContext sslContext = (SafeDeleteSslContext)securityContext;
155150
SafeSslHandle sslHandle = sslContext.SslContext;
156151

157-
sslContext.Write(buffer, offset, count);
152+
sslContext.Write(buffer.AsSpan(offset, count));
158153

159154
unsafe
160155
{
161156
fixed (byte* offsetInput = &buffer[offset])
162157
{
163-
int written;
164-
PAL_TlsIo status;
165-
166-
lock (sslHandle)
167-
{
168-
status = Interop.AppleCrypto.SslRead(sslHandle, offsetInput, count, out written);
169-
}
158+
PAL_TlsIo status = Interop.AppleCrypto.SslRead(sslHandle, offsetInput, count, out int written);
170159

171160
if (status < 0)
172161
{
@@ -266,12 +255,7 @@ private static SecurityStatusPal HandshakeInternal(
266255
}
267256

268257
SafeSslHandle sslHandle = sslContext!.SslContext;
269-
SecurityStatusPal status;
270-
271-
lock (sslHandle)
272-
{
273-
status = PerformHandshake(sslHandle);
274-
}
258+
SecurityStatusPal status = PerformHandshake(sslHandle);
275259

276260
outputBuffer = sslContext.ReadPendingWrites();
277261
return status;
@@ -329,12 +313,8 @@ public static SecurityStatusPal ApplyShutdownToken(
329313
{
330314
SafeDeleteSslContext sslContext = ((SafeDeleteSslContext)securityContext);
331315
SafeSslHandle sslHandle = sslContext.SslContext;
332-
int osStatus;
333316

334-
lock (sslHandle)
335-
{
336-
osStatus = Interop.AppleCrypto.SslShutdown(sslHandle);
337-
}
317+
int osStatus = Interop.AppleCrypto.SslShutdown(sslHandle);
338318

339319
if (osStatus == 0)
340320
{

0 commit comments

Comments
 (0)