Example #1
0
        /// <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();
            }
        }
Example #2
0
        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));
        }
Example #3
0
        /// <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();
            }
        }
Example #4
0
        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);
            }
        }
Example #5
0
        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));
        }
Example #6
0
        /// <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();
            }
        }