in src/Microsoft.Diagnostics.Runtime/src/Windows/AWEBasedCacheEntry.cs [47:133]
public override long PageOutData()
{
ThrowIfDisposed();
if (HeapSegmentCacheEventSource.Instance.IsEnabled())
HeapSegmentCacheEventSource.Instance.PageOutDataStart();
long sizeRemoved = 0;
int maxLoopCount = 5;
int pass = 0;
for (; pass < maxLoopCount; pass++)
{
// Assume we will be able to evict all non-null pages
bool encounteredBusyPage = false;
for (int i = 0; i < _pages.Length; i++)
{
ReaderWriterLockSlim pageLock = _pageLocks[i];
if (!pageLock.TryEnterWriteLock(timeout: TimeSpan.Zero))
{
// Someone holds the writelock on this page, skip it and try to get it in another pass, this prevent us from blocking page out
// on someone currently reading a page, they will likely be done by our next pass
encounteredBusyPage = true;
continue;
}
try
{
CachePage<UIntPtr> page = _pages[i];
if (page != null)
{
uint pagesToUnMap = (uint)(page.DataExtent / SystemPageSize) + (uint)((page.DataExtent % SystemPageSize) != 0 ? 1 : 0);
// We need to unmap the physical memory from this VM range and then free the VM range
bool unmapPhysicalPagesResult = CacheNativeMethods.AWE.MapUserPhysicalPages(page.Data, pagesToUnMap, pageArray: UIntPtr.Zero);
if (!unmapPhysicalPagesResult)
{
Debug.Fail("MapUserPhysicalPage failed to unmap a physical page");
// this is an error but we don't want to remove the ptr entry since we apparently didn't unmap the physical memory
continue;
}
sizeRemoved += page.DataExtent;
bool virtualFreeRes = CacheNativeMethods.Memory.VirtualFree(page.Data, sizeToFree: UIntPtr.Zero, CacheNativeMethods.Memory.VirtualFreeType.Release);
if (!virtualFreeRes)
{
Debug.Fail("MapUserPhysicalPage failed to unmap a physical page");
// this is an error but we already unmapped the physical memory so also throw away our VM pointer
_pages[i] = null;
continue;
}
// Done, throw away our VM pointer
_pages[i] = null;
}
}
finally
{
pageLock.ExitWriteLock();
}
}
// We are done if we didn't encounter any busy (locked) pages
if (!encounteredBusyPage)
break;
}
// Correct our size based on how much data we could remove
int oldCurrent;
int newCurrent;
do
{
oldCurrent = _entrySize;
newCurrent = Math.Max(MinSize, oldCurrent - (int)sizeRemoved);
} while (Interlocked.CompareExchange(ref _entrySize, newCurrent, oldCurrent) != oldCurrent);
if (HeapSegmentCacheEventSource.Instance.IsEnabled())
HeapSegmentCacheEventSource.Instance.PageOutDataEnd(sizeRemoved);
return sizeRemoved;
}