/// <summary> /// Convenience extension to cheaply have only a single task running an operation, by using a semaphore as a latch. /// /// It will run <paramref name="operation"/> if the gate allows it to, or <paramref name="duplicated"/> otherwise. /// </summary> public static async Task <TResult> DeduplicatedOperationAsync <TResult>(this SemaphoreSlim gate, Func <TimeSpan, int, Task <TResult> > operation, Func <TimeSpan, int, Task <TResult> > duplicated, CancellationToken token = default) { Contract.RequiresNotNull(gate); Contract.RequiresNotNull(operation); Contract.RequiresNotNull(duplicated); var sw = Stopwatch.StartNew(); var taken = await gate.WaitAsync(millisecondsTimeout : 0, token); if (!taken) { var currentCount = gate.CurrentCount; return(await duplicated(sw.Elapsed, currentCount)); } try { var currentCount = gate.CurrentCount; return(await operation(sw.Elapsed, currentCount)); } finally { gate.Release(); } }
public Task WriteAsync(char messageTypePrefix, string message) { Contract.Requires(IsConnected); int writeBufferStart = 4; int totalSize = writeBufferStart + (1 + message.Length) * s_messageEncodingBytesPerChar; if (m_writeBuffer.Length < totalSize) { m_writeBuffer = new byte[totalSize]; } unsafe { fixed(byte *pBuf = &m_writeBuffer[0]) { *(int *)pBuf = totalSize - writeBufferStart; } } writeBufferStart += s_messageEncoding.GetBytes(new[] { messageTypePrefix }, 0, 1, m_writeBuffer, writeBufferStart); writeBufferStart += s_messageEncoding.GetBytes(message, 0, message.Length, m_writeBuffer, writeBufferStart); return(m_networkStream.WriteAsync(m_writeBuffer, 0, totalSize, m_cancellationToken)); }
/// <summary> /// Convenience extension to allow tracing the time it takes to Wait a semaphore /// </summary> public static async Task <TResult> GatedOperationAsync <TResult>( this SemaphoreSlim gate, Func <TimeSpan, int, Task <TResult> > operation, CancellationToken token = default, TimeSpan?ioGateTimeout = null) { Contract.RequiresNotNull(gate); Contract.RequiresNotNull(operation); var sw = Stopwatch.StartNew(); var acquired = await gate.WaitAsync(ioGateTimeout ?? Timeout.InfiniteTimeSpan, token); if (!acquired) { throw new TimeoutException($"IO gate timed out after {ioGateTimeout}"); } try { var currentCount = gate.CurrentCount; return(await operation(sw.Elapsed, currentCount)); } finally { gate.Release(); } }
internal async Task ConnectAsync() { try { await m_tcpClient.ConnectAsync(m_endPoint.Address, m_endPoint.Port); Contract.Assert(m_tcpClient.Connected); m_networkStream = m_tcpClient.GetStream(); } catch (Exception e) { throw new BuildXLException($"{nameof(RemotingClient)}: Failed to connect", e); } }
internal async Task <string> ReceiveStringAsync() { Contract.Requires(IsConnected); int offset = 0; int payloadSize = -1; // Get the first 4 bytes containing the payload size. while (payloadSize < 0) { int bytesRead = await m_networkStream.ReadAsync(m_readBuffer, offset, 4 - offset, m_cancellationToken); if (bytesRead == 0) { // Socket closed. Unexpected if we have not received data yet. if (offset > 0) { throw new BuildXLException($"{nameof(RemotingClient)}: Unexpected close during message receive"); } } offset += bytesRead; if (offset == 4) { payloadSize = BitConverter.ToInt32(m_readBuffer, 0); } } if (payloadSize > m_readBuffer.Length) { m_readBuffer = new byte[payloadSize]; } offset = 0; while (offset < payloadSize) { int bytesRead = await m_networkStream.ReadAsync(m_readBuffer, offset, payloadSize - offset, m_cancellationToken); if (bytesRead == 0) { // Socket closed. throw new BuildXLException($"{nameof(RemotingClient)}: Unexpected close during message receive"); } offset += bytesRead; } return(s_messageEncoding.GetString(m_readBuffer, 0, payloadSize)); }
/// <summary> /// Convenience extension to allow tracing the time it takes to Wait a semaphore /// </summary> public static async Task <TResult> GatedOperationAsync <TResult>(this SemaphoreSlim gate, Func <TimeSpan, int, Task <TResult> > operation, CancellationToken token = default) { Contract.RequiresNotNull(gate); Contract.RequiresNotNull(operation); var sw = Stopwatch.StartNew(); await gate.WaitAsync(token); try { var currentCount = gate.CurrentCount; return(await operation(sw.Elapsed, currentCount)); } finally { gate.Release(); } }