// Decompiled with JetBrains decompiler // Type: Microsoft.Iris.Render.Protocol.MessageHeap // Assembly: UIX.RenderApi, Version=4.8.0.0, Culture=neutral, PublicKeyToken=ddd0da4d3e678217 // MVID: D47658B8-A8EA-43D6-8837-ECE823BFFFC1 // Assembly location: C:\Program Files\Zune\UIX.RenderApi.dll using Microsoft.Iris.Render.Common; using System; using System.Runtime.InteropServices; namespace Microsoft.Iris.Render.Protocol { internal class MessageHeap : RenderObject { private MessageHeap.BlockInfo headBlock; private MessageHeap.BlockInfo tailBlock; private uint nextBlockId; private uint smallBlockSize; private uint blockHeaderSize; private uint allocExtraSize; private uint key; public MessageHeap(uint blockSize, uint headerSize, uint allocationExtra) { Debug2.Validate(blockSize > headerSize, typeof(ArgumentException), "Blocks must be larger than their headers"); this.smallBlockSize = blockSize; this.blockHeaderSize = headerSize; this.allocExtraSize = allocationExtra; this.nextBlockId = 1U; this.CreateBlock(BlockType.First, this.smallBlockSize); } protected override void Dispose(bool inDispose) { try { if (this.IsDisposed) return; this.ReleaseAll(true); } finally { base.Dispose(inDispose); } } internal bool IsDisposed => this.headBlock == null; public unsafe void* Alloc(uint size) { size += this.allocExtraSize; int num = sizeof(void*) - 1; size = (uint)((int)size + num & ~num); MessageHeap.BlockInfo block = this.tailBlock; if (size > block.size - block.used) { MessageHeap.BlockType type = BlockType.Normal; uint actualSize = this.smallBlockSize; if (size > this.smallBlockSize - this.blockHeaderSize) { type = BlockType.Large; actualSize = this.blockHeaderSize + size; } block = this.CreateBlock(type, actualSize); } this.ZeroMemoryBlock(block, block.used, allocExtraSize); void* voidPtr = (void*)((nint)block.data + (block.used + allocExtraSize)); block.used += size; ++this.key; return voidPtr; } public unsafe MessageHeap.Block LookupBlock(void* p) { MessageHeap.BlockInfo blockInfo = this.LookupBlockWorker(p); return new MessageHeap.Block(blockInfo.id, blockInfo.data, blockInfo.used); } public void Reset() => this.ReleaseAll(false); public int BlockCount { get { int num = 0; MessageHeap.BlockInfo blockInfo = this.headBlock; while (blockInfo != null) { blockInfo = blockInfo.next; ++num; } return num; } } public MessageHeap.Enumerator GetEnumerator() => new MessageHeap.Enumerator(this); private unsafe MessageHeap.BlockInfo CreateBlock( MessageHeap.BlockType type, uint actualSize) { ++this.key; MessageHeap.BlockInfo block = new MessageHeap.BlockInfo(); block.data = Marshal.AllocCoTaskMem((int)actualSize).ToPointer(); block.id = this.nextBlockId++; block.type = type; block.size = actualSize; switch (type) { case BlockType.First: block.next = null; this.headBlock = block; this.tailBlock = block; break; case BlockType.Normal: case BlockType.Large: block.next = this.tailBlock.next; this.tailBlock.next = block; this.tailBlock = block; break; } block.used = this.blockHeaderSize; this.ZeroMemoryBlock(block, 0U, this.blockHeaderSize); return block; } private unsafe void DestroyBlock(MessageHeap.BlockInfo block) { Marshal.FreeCoTaskMem(new IntPtr(block.data)); block.data = null; } private void ReleaseAll(bool finalRelease) { ++this.key; MessageHeap.BlockInfo block; if (finalRelease) { block = this.headBlock; this.headBlock = null; this.tailBlock = null; } else { this.ZeroMemoryBlock(this.headBlock, 0U, this.blockHeaderSize); block = this.headBlock.next; this.headBlock.next = null; this.headBlock.used = this.blockHeaderSize; this.tailBlock = this.headBlock; this.nextBlockId = 2U; } MessageHeap.BlockInfo next; for (; block != null; block = next) { next = block.next; switch (block.type) { case BlockType.First: case BlockType.Normal: case BlockType.Large: this.DestroyBlock(block); break; } } } private unsafe MessageHeap.BlockInfo LookupBlockWorker(void* p) { for (MessageHeap.BlockInfo blockInfo = this.headBlock; blockInfo != null; blockInfo = blockInfo.next) { if (p >= blockInfo.data) { void* voidPtr = (void*)((nint)blockInfo.data + blockInfo.used); if (p < voidPtr) return blockInfo; } } throw new ArgumentException("pointer is not on this heap"); } private unsafe void ZeroMemoryBlock(MessageHeap.BlockInfo block, uint offset, uint size) { Debug2.Validate(offset + size <= block.size, typeof(ArgumentOutOfRangeException), "Invalid memory range for block"); byte* start = (byte*)block.data + offset; for (byte* current = start + size; start < current; ++start) *start = 0; } protected override void Invariant() => Debug2.Validate(!this.IsDisposed, typeof(InvalidOperationException), "MessageHeap has already been disposed"); internal struct Enumerator { private MessageHeap heap; private MessageHeap.BlockInfo current; private uint key; public Enumerator(MessageHeap heap) { this.heap = heap; this.current = null; this.key = heap.key; } public bool MoveNext() { if ((int)this.key != (int)this.heap.key) throw new InvalidOperationException("heap modified while enumerator is in use"); this.current = this.current != null ? this.current.next : this.heap.headBlock; return this.current != null; } public unsafe MessageHeap.Block Current { get { if ((int)this.key != (int)this.heap.key) throw new InvalidOperationException("heap modified while enumerator in use"); return new MessageHeap.Block(this.current.id, this.current.data, this.current.used); } } } internal struct Block { public uint id; public unsafe void* data; public uint size; public unsafe Block(uint id, void* data, uint size) { this.id = id; this.data = data; this.size = size; } } private enum BlockType { First, Normal, Large, } private class BlockInfo { public MessageHeap.BlockInfo next; public MessageHeap.BlockType type; public uint id; public unsafe void* data; public uint size; public uint used; } } }