Files
MicrosoftIris/UIX.RenderApi/Microsoft/Iris/Render/Protocol/MessageHeap.cs
T

255 lines
8.4 KiB
C#

// 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*)((nint)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;
}
}
}