//////////////////////////////////////////////////////////////////////////////// // // Microsoft Research Singularity // // Copyright (c) Microsoft Corporation. All rights reserved. // // Note: // A utility class that can store vectors of bytes from the shared heap without // duplicating them, then copy them out later as though they were a single // uninterrupted array of bytes. // using Microsoft.SingSharp; using Microsoft.SingSharp.Runtime; using Microsoft.Singularity; using Microsoft.Singularity.Channels; using System.Collections; using System.Collections.Generic; using System.Diagnostics; namespace System.Net.Sockets { internal class TrackedBytesBuffer { private class BytesPlusCount : ITracked { int nextOffset; // Offset of the next byte to use byte[]! in ExHeap bytes; // The bytes public BytesPlusCount([Claims]byte[]! in ExHeap data) { bytes = data; nextOffset = 0; base(); } #region ITracked members void ITracked.Release() {} void ITracked.Acquire() {} public void Dispose() { delete bytes; } void ITracked.Expose() {} void ITracked.UnExpose() {} #endregion public int Length { get { expose(this) { return bytes.Length - nextOffset; } } } public bool Empty { get { expose(this) { return nextOffset >= bytes.Length; } } } // Copy out as many bytes as possible public int CopyOut(byte[]! buff, int offset, int length, bool fPeek) { if (Length <= 0) { return 0; } int numToCopy = Math.Min(length, Length); expose (this) { for (int i = 0; i < numToCopy; ++i) { buff[offset + i] = bytes[nextOffset + i]; } } if (!fPeek) { nextOffset += numToCopy; } // else it's as if the copy never happened return numToCopy; } } // Contains TContainer private Queue m_DataQueue; // Count of the total bytes that we (logically) contain private int m_Count; public TrackedBytesBuffer() { m_DataQueue = new Queue(); m_Count = 0; } public void AddToTail([Claims] byte[]! in ExHeap bytes) { m_Count += bytes.Length; BytesPlusCount! holder = new BytesPlusCount(bytes); m_DataQueue.Enqueue(new TContainer(holder)); } // Copy data out into a supplied buffer. If fPeek is true, it means we // would copy out the exact same bytes if called again. public int CopyFromHead(byte[]! buffer, int offset, int length, bool fPeek) { int bytesCopied = 0; while ((m_DataQueue.Count > 0) && (bytesCopied < length)) { // Don't dequeue just yet, just peek TContainer wrapper = (TContainer)m_DataQueue.Peek(); assert wrapper != null; // Because we checked the count BytesPlusCount! topChunk = wrapper.Acquire(); int copied = topChunk.CopyOut(buffer, offset + bytesCopied, length - bytesCopied, fPeek); bytesCopied += copied; if ((!fPeek) && (topChunk.Empty)) { // We want to throw away the top chunk. To take pressure off // the finalizer, we'll explicitly free the ExHeap data vector. topChunk.Dispose(); m_DataQueue.Dequeue(); } else if ((!fPeek) && (!topChunk.Empty)) { // This should only happen because we filled up the // caller's buffer Debug.Assert(bytesCopied == length); // Put the data back into its wrapper wrapper.Release(topChunk); } else { // Release topChunk back wrapper.Release(topChunk); } } if (!fPeek) { m_Count -= bytesCopied; Debug.Assert(m_Count >= 0); } return bytesCopied; } public int Count { get { return m_Count; } } } }