// // Copyright (c) Microsoft Corporation. All rights reserved. // /*******************************************************************/ /* 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. */ /*******************************************************************/ 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"); } } } }