238 lines
7.9 KiB
C#
238 lines
7.9 KiB
C#
/*******************************************************************/
|
|
/* WARNING */
|
|
/* This file should be identical in the Bartok and Singularity */
|
|
/* depots. Master copy resides in Bartok Depot. Changes should be */
|
|
/* made to Bartok Depot and propagated to Singularity Depot. */
|
|
/*******************************************************************/
|
|
|
|
//
|
|
// Copyright (c) Microsoft Corporation. All rights reserved.
|
|
//
|
|
|
|
namespace System.GCs {
|
|
|
|
using System.Runtime.CompilerServices;
|
|
using System.Threading;
|
|
|
|
internal unsafe struct UIntPtrQueue {
|
|
|
|
private UnmanagedPageList pageList;
|
|
private UIntPtr readPage;
|
|
private PageCursor readCursor;
|
|
private PageCursor writeCursor;
|
|
|
|
internal bool IsEmpty {
|
|
[Inline]
|
|
get { return (this.readCursor.cursor == this.writeCursor.cursor); }
|
|
}
|
|
|
|
internal void Write(UIntPtr value) {
|
|
if (this.writeCursor.IsEmpty) {
|
|
this.AdvanceWritePage();
|
|
}
|
|
if (this.readCursor.limit == this.writeCursor.cursor) {
|
|
this.writeCursor.Write(value);
|
|
this.readCursor.limit = this.writeCursor.cursor;
|
|
} else {
|
|
this.writeCursor.Write(value);
|
|
}
|
|
}
|
|
|
|
internal void Write(UIntPtr value1, UIntPtr value2) {
|
|
if (this.writeCursor.HasTwo) {
|
|
if (this.readCursor.limit == this.writeCursor.cursor) {
|
|
this.writeCursor.Write(value1);
|
|
this.writeCursor.Write(value2);
|
|
this.readCursor.limit = this.writeCursor.cursor;
|
|
} else {
|
|
this.writeCursor.Write(value1);
|
|
this.writeCursor.Write(value2);
|
|
}
|
|
} else {
|
|
this.Write(value1);
|
|
this.Write(value2);
|
|
}
|
|
}
|
|
|
|
internal UIntPtr Read() {
|
|
if (this.readCursor.IsEmpty) {
|
|
this.AdvanceReadPage();
|
|
}
|
|
return this.readCursor.Read();
|
|
}
|
|
|
|
internal UIntPtr Read(out UIntPtr value2) {
|
|
if (this.readCursor.HasTwo) {
|
|
UIntPtr value1 = this.readCursor.Read();
|
|
value2 = this.readCursor.Read();
|
|
return value1;
|
|
} else {
|
|
UIntPtr value1 = this.Read();
|
|
value2 = this.Read();
|
|
return value1;
|
|
}
|
|
}
|
|
|
|
internal void Cleanup(bool mustBeEmpty) {
|
|
if (mustBeEmpty) {
|
|
VTable.Assert(this.pageList.Head == this.pageList.Tail);
|
|
VTable.Assert(this.readCursor.cursor == this.writeCursor.cursor);
|
|
}
|
|
if (this.readPage != UIntPtr.Zero) {
|
|
UnmanagedPageList.pageCache.AddHead(this.readPage);
|
|
this.readPage = UIntPtr.Zero;
|
|
}
|
|
while (!this.pageList.IsEmpty) {
|
|
UIntPtr headPage = this.pageList.RemoveHead();
|
|
UnmanagedPageList.pageCache.AddHead(headPage);
|
|
}
|
|
this.writeCursor = new PageCursor(null, null);
|
|
this.readCursor = new PageCursor(null, null);
|
|
}
|
|
|
|
private void AdvanceReadPage() {
|
|
if (this.pageList.IsEmpty) {
|
|
return;
|
|
}
|
|
if (this.readPage != UIntPtr.Zero) {
|
|
UnmanagedPageList.pageCache.AddHead(this.readPage);
|
|
}
|
|
this.readPage = this.pageList.RemoveHead();
|
|
UIntPtr* startPtr = UnmanagedPageList.FirstPageAddr(this.readPage);
|
|
UIntPtr* limitPtr;
|
|
if (this.pageList.IsEmpty) {
|
|
limitPtr = this.writeCursor.cursor;
|
|
} else {
|
|
limitPtr = UnmanagedPageList.EndPageAddr(this.readPage);
|
|
}
|
|
this.readCursor = new PageCursor(startPtr, limitPtr);
|
|
}
|
|
|
|
private void AdvanceWritePage() {
|
|
UIntPtr pageAddr;
|
|
if (UnmanagedPageList.pageCache.IsEmpty) {
|
|
bool fCleanPages = true;
|
|
UIntPtr page = PageManager.EnsurePages(null, (UIntPtr) 1,
|
|
PageType.System,
|
|
ref fCleanPages);
|
|
pageAddr = PageTable.PageAddr(page);
|
|
} else {
|
|
pageAddr = UnmanagedPageList.pageCache.RemoveHead();
|
|
}
|
|
this.pageList.AddTail(pageAddr);
|
|
this.writeCursor =
|
|
new PageCursor(UnmanagedPageList.FirstPageAddr(pageAddr),
|
|
UnmanagedPageList.EndPageAddr(pageAddr));
|
|
}
|
|
|
|
private struct PageCursor {
|
|
internal UIntPtr *cursor;
|
|
internal UIntPtr *limit;
|
|
|
|
internal PageCursor(UIntPtr *start, UIntPtr *limit) {
|
|
this.cursor = start;
|
|
this.limit = limit;
|
|
}
|
|
|
|
internal bool IsEmpty {
|
|
[Inline]
|
|
get { return this.cursor == this.limit; }
|
|
}
|
|
|
|
internal bool HasTwo {
|
|
[Inline]
|
|
get { return (this.cursor + 2 <= this.limit); }
|
|
}
|
|
|
|
[Inline]
|
|
internal void Write(UIntPtr value) {
|
|
VTable.Deny(this.IsEmpty);
|
|
*this.cursor++ = value;
|
|
}
|
|
|
|
[Inline]
|
|
internal UIntPtr Read() {
|
|
VTable.Deny(this.IsEmpty);
|
|
return *this.cursor++;
|
|
}
|
|
|
|
internal bool MoveNext() {
|
|
if (this.IsEmpty) {
|
|
return false;
|
|
}
|
|
this.cursor++;
|
|
return (!this.IsEmpty);
|
|
}
|
|
|
|
internal UIntPtr Current {
|
|
get { return *this.cursor; }
|
|
}
|
|
|
|
internal UIntPtr* CurrentAddr {
|
|
get { return this.cursor; }
|
|
}
|
|
|
|
}
|
|
|
|
internal unsafe struct Enumerator {
|
|
|
|
private UnmanagedPageList.Enumerator pageEnumerator;
|
|
private UIntPtr lastPageStart;
|
|
private UIntPtr* lastPageLimit;
|
|
private PageCursor currentCursor;
|
|
|
|
internal Enumerator(ref UIntPtrQueue queue) {
|
|
this.pageEnumerator =
|
|
new UnmanagedPageList.Enumerator(ref queue.pageList);
|
|
this.lastPageLimit = queue.writeCursor.cursor;
|
|
this.lastPageStart =
|
|
PageTable.PageAlign((UIntPtr) lastPageLimit);
|
|
this.currentCursor = new PageCursor(null, null);
|
|
if (this.pageEnumerator.MoveNext()) {
|
|
UIntPtr currentPage = this.pageEnumerator.Current;
|
|
this.SetCursor(currentPage);
|
|
}
|
|
}
|
|
|
|
private void SetCursor(UIntPtr pageAddr) {
|
|
UIntPtr* preFirstAddr =
|
|
UnmanagedPageList.FirstPageAddr(pageAddr) - 1;
|
|
if (pageAddr == lastPageStart) {
|
|
this.currentCursor = new PageCursor(preFirstAddr,
|
|
this.lastPageLimit);
|
|
} else {
|
|
UIntPtr* endAddr = UnmanagedPageList.EndPageAddr(pageAddr);
|
|
this.currentCursor = new PageCursor(preFirstAddr, endAddr);
|
|
}
|
|
}
|
|
|
|
internal bool MoveNext() {
|
|
if (this.currentCursor.MoveNext()) {
|
|
return true;
|
|
}
|
|
if (!this.pageEnumerator.MoveNext()) {
|
|
return false;
|
|
}
|
|
UIntPtr currentPage = this.pageEnumerator.Current;
|
|
this.SetCursor(currentPage);
|
|
return this.currentCursor.MoveNext();
|
|
}
|
|
|
|
internal UIntPtr Current {
|
|
get { return this.currentCursor.Current; }
|
|
}
|
|
|
|
internal UIntPtr* CurrentAddr {
|
|
get { return this.currentCursor.CurrentAddr; }
|
|
}
|
|
|
|
internal void Reset() {
|
|
throw new Exception("No reset on UIntPtrQueue iterator");
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|