public void should_acquire_and_release_from_multiple_threads() { // Arrange using (var bufferManager = RioBufferManager.Allocate(128, 64)) { // Act var tasks = new Task[6]; for (var i = 0; i < tasks.Length; i++) { tasks[i] = Task.Run(() => { for (var j = 0; j < 50 * 1000; j++) { var buffers = new RioBuffer[10]; for (var k = 0; k < buffers.Length; k++) { buffers[k] = bufferManager.AcquireBuffer(TimeSpan.FromMilliseconds(100)); } for (var k = 0; k < buffers.Length; k++) { bufferManager.ReleaseBuffer(buffers[k]); } } }); } // Assert var allTaskAreCompleted = Task.WaitAll(tasks, TimeSpan.FromSeconds(3)); Assert.IsTrue(allTaskAreCompleted); } }
public void Reset() { _remainingFrameByteCount = ByteCount.Empty; _currentRegisteredSegmentEnd = (byte *)0; _currentBuffer = null; _currentFrame.Clear(); _pendingBuffers.Clear(); }
private int ReadFrom(RioBuffer buffer) { if (buffer.Length < sizeof(int)) { throw new ArgumentException("buffer is too small", nameof(buffer)); } return(*(int *)buffer.Data); }
private void WriteTo(RioBuffer buffer, int value) { if (buffer.Length < sizeof(int)) { throw new ArgumentException("buffer is too small", nameof(buffer)); } *(int *)buffer.Data = value; }
public unsafe void Send(RioBuffer buffer) { var requestContextKey = new RioRequestContextKey(buffer.Id, RioRequestType.Send); if (!WinSock.Extensions.Send(_handle, buffer.BufferDescriptor, 1, RIO_SEND_FLAGS.NONE, requestContextKey.ToRioRequestCorrelationId())) { WinSock.ThrowLastWsaError(); } }
private void OnReceiveComplete(RioBuffer buffer) { var receivingContext = _threadLocalReceivingContext.Value; List <BufferSegment> framedMessage; while (_messageFramer.TryFrameNextMessage(buffer, out framedMessage)) { var releasableMessage = _serializationEngine.DeserializeWithLengthPrefix(framedMessage, receivingContext.BinaryReader); try { MessageReceived(this, releasableMessage.MessageTypeId, releasableMessage.Message); } catch (Exception ex) { MessageHandlingFailed(this, releasableMessage.MessageTypeId, releasableMessage.Message, ex); } finally { releasableMessage.Releaser?.Release(releasableMessage.Message); } } }
private static List <RioBuffer> CreateBuffers(byte *buffer, RIO_BUF *segmentBuffer, int maxLength, int segmentLength = 10) { var segments = new List <RioBuffer>(); var pBuffer = buffer; var readDataLength = 0; var segmentId = 0; while (readDataLength != maxLength) { var dataLength = Math.Min(segmentLength, maxLength - readDataLength); segmentBuffer->Length = dataLength; var segment = new RioBuffer(segmentId++, pBuffer, segmentBuffer, segmentLength) { DataLength = dataLength }; segments.Add(segment); readDataLength += dataLength; pBuffer += segmentLength; segmentBuffer++; } return(segments); }
public bool TryFrameNextMessage(RioBuffer rioBuffer, out List <BufferSegment> frame) { frame = null; var currentSegmentIsCompleted = _currentRegisteredSegmentEnd == _currentBufferSegment.Data; if (_remainingFrameByteCount.IsEmpty) { // the previous frame was framed entirely, we can reset it _currentFrame.Clear(); // we can release all pending buffers, but the current one must be kept if it is not entirely read ReleasePendingBuffers(currentSegmentIsCompleted); if (currentSegmentIsCompleted && _currentBuffer != null) { _currentRegisteredSegmentEnd = rioBuffer.Data; return(false); } } if (rioBuffer != _currentBuffer) { // a new buffer is submitted, we initialize a new frame segment _currentBufferSegment = new BufferSegment(rioBuffer.Data); _currentBuffer = rioBuffer; _pendingBuffers.Add(_currentBuffer); } _currentRegisteredSegmentEnd = rioBuffer.Data + rioBuffer.DataLength; // we need to read the length prefix of the frame, so we loop until we have the 4 bytes of data we need while (!_remainingFrameByteCount.IsComplete) { if (_currentBufferSegment.Data >= _currentRegisteredSegmentEnd) { return(false); } _remainingFrameByteCount.Push(_currentBufferSegment.Data); _currentBufferSegment = new BufferSegment(_currentBufferSegment.Data + 1, _currentBufferSegment.Length); } // we just finished to read the frame length and the buffer is completed, we can release it right away if (_currentFrame.Count == 0) { ReleasePendingBuffers(_currentBufferSegment.Data == _currentRegisteredSegmentEnd); } // at this point, we know the actual frame length // if the frame bytes span beyond the end of the current buffer, we trim the current frame part // to the end of the buffer and we return so that we can be provided another buffer var frameEnd = _currentBufferSegment.Data + _remainingFrameByteCount.Value; if (frameEnd > _currentRegisteredSegmentEnd) { var segmentLength = _currentBufferSegment.Length + (int)(_currentRegisteredSegmentEnd - _currentBufferSegment.Data); _currentBufferSegment = new BufferSegment(_currentBufferSegment.Data, segmentLength); _remainingFrameByteCount.Value -= _currentBufferSegment.Length; _currentFrame.Add(_currentBufferSegment); return(false); } // if the buffer contains enough data, we take as much as we need and mark the frame as completed _currentBufferSegment = new BufferSegment(_currentBufferSegment.Data, _currentBufferSegment.Length + _remainingFrameByteCount.Value); _currentFrame.Add(_currentBufferSegment); _currentBufferSegment = new BufferSegment(_currentBufferSegment.Data + _currentBufferSegment.Length); _remainingFrameByteCount = ByteCount.Empty; frame = _currentFrame; return(true); }
public void ReleaseBuffer(RioBuffer buffer) { LastReleasedSegmentId = buffer.Id > LastReleasedSegmentId ? buffer.Id : LastReleasedSegmentId; }