public override long PageOutData()

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;
        }