private uint ReadPageDataFromOffset()

in src/Microsoft.Diagnostics.Runtime/src/Windows/CacheEntryBase.cs [175:270]


        private uint ReadPageDataFromOffset(int pageIndex, uint inPageOffset, uint byteCount, IntPtr buffer, Func<UIntPtr, uint, uint> dataReader)
        {
            bool notifyCacheOfSizeUpdate = false;

            uint sizeRead = 0;
            int addedSize = 0;

            ReaderWriterLockSlim pageLock = _pageLocks[pageIndex];

            pageLock.EnterReadLock();
            bool holdsReadLock = true;
            try
            {
                // THREADING: If the data is not null we can just read it directly as we hold the read lock, if it is null we must acquire the write lock in
                // preparation to fetch the data from physical memory
                if (_pages[pageIndex] != null)
                {
                    UpdateLastAccessTimstamp();

                    if (dataReader == null)
                    {
                        sizeRead = CopyDataFromPage(_pages[pageIndex], buffer, inPageOffset, byteCount);
                    }
                    else
                    {
                        sizeRead = InvokeCallbackWithDataPtr(_pages[pageIndex], dataReader);
                    }
                }
                else
                {
                    pageLock.ExitReadLock();
                    holdsReadLock = false;

                    pageLock.EnterWriteLock();
                    try
                    {
                        // THREADING: Double check it's still null (i.e. no other thread beat us to paging this data in between dropping our read lock and acquiring
                        // the write lock)
                        if (_pages[pageIndex] == null)
                        {
                            uint dataRange;
                            T data;
                            (data, dataRange) = GetPageDataAtOffset((uint)pageIndex * EntryPageSize);

                            _pages[pageIndex] = new CachePage<T>(data, dataRange);

                            Interlocked.Add(ref _entrySize, (int)dataRange);

                            UpdateLastAccessTimstamp();

                            if (dataReader == null)
                            {
                                sizeRead = CopyDataFromPage(_pages[pageIndex], buffer, inPageOffset, byteCount);
                            }
                            else
                            {
                                sizeRead = InvokeCallbackWithDataPtr(_pages[pageIndex], dataReader);
                            }

                            addedSize = (int)dataRange;
                            notifyCacheOfSizeUpdate = true;
                        }
                        else
                        {
                            // Someone else beat us to retrieving the data, so we can just read
                            UpdateLastAccessTimstamp();

                            if (dataReader == null)
                            {
                                sizeRead = CopyDataFromPage(_pages[pageIndex], buffer, inPageOffset, byteCount);
                            }
                            else
                            {
                                sizeRead = InvokeCallbackWithDataPtr(_pages[pageIndex], dataReader);
                            }
                        }
                    }
                    finally
                    {
                        pageLock.ExitWriteLock();
                    }
                }
            }
            finally
            {
                if (holdsReadLock)
                    pageLock.ExitReadLock();
            }

            if (notifyCacheOfSizeUpdate)
            {
                _updateOwningCacheForAddedChunk((uint)addedSize);
            }

            return sizeRead;
        }