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