@@ -249,6 +249,7 @@ class MapAllocatorCache {
249249
250250 LRUEntries.clear ();
251251 LRUEntries.init (Entries, sizeof (Entries));
252+ OldestPresentEntry = nullptr ;
252253
253254 AvailEntries.clear ();
254255 AvailEntries.init (Entries, sizeof (Entries));
@@ -322,8 +323,6 @@ class MapAllocatorCache {
322323 }
323324 CachedBlock PrevEntry = Quarantine[QuarantinePos];
324325 Quarantine[QuarantinePos] = Entry;
325- if (OldestTime == 0 )
326- OldestTime = Entry.Time ;
327326 Entry = PrevEntry;
328327 }
329328
@@ -339,9 +338,6 @@ class MapAllocatorCache {
339338 }
340339
341340 insert (Entry);
342-
343- if (OldestTime == 0 )
344- OldestTime = Entry.Time ;
345341 } while (0 );
346342
347343 for (MemMapT &EvictMemMap : EvictionMemMaps)
@@ -355,7 +351,6 @@ class MapAllocatorCache {
355351 SCUDO_SCOPED_TRACE (
356352 GetSecondaryReleaseToOSTraceName (ReleaseToOS::Normal));
357353
358- // TODO: Add ReleaseToOS logic to LRU algorithm
359354 releaseOlderThan (Time - static_cast <u64 >(Interval) * 1000000 );
360355 Mutex.unlock ();
361356 } else
@@ -535,17 +530,28 @@ class MapAllocatorCache {
535530
536531 void unmapTestOnly () { empty (); }
537532
533+ void releaseOlderThanTestOnly (u64 ReleaseTime) {
534+ ScopedLock L (Mutex);
535+ releaseOlderThan (ReleaseTime);
536+ }
537+
538538private:
539539 void insert (const CachedBlock &Entry) REQUIRES(Mutex) {
540540 CachedBlock *AvailEntry = AvailEntries.front ();
541541 AvailEntries.pop_front ();
542542
543543 *AvailEntry = Entry;
544544 LRUEntries.push_front (AvailEntry);
545+ if (OldestPresentEntry == nullptr && AvailEntry->Time != 0 )
546+ OldestPresentEntry = AvailEntry;
545547 }
546548
547549 void remove (CachedBlock *Entry) REQUIRES(Mutex) {
548550 DCHECK (Entry->isValid ());
551+ if (OldestPresentEntry == Entry) {
552+ OldestPresentEntry = LRUEntries.getPrev (Entry);
553+ DCHECK (OldestPresentEntry == nullptr || OldestPresentEntry->Time != 0 );
554+ }
549555 LRUEntries.remove (Entry);
550556 Entry->invalidate ();
551557 AvailEntries.push_front (Entry);
@@ -560,43 +566,50 @@ class MapAllocatorCache {
560566 for (CachedBlock &Entry : LRUEntries)
561567 MapInfo[N++] = Entry.MemMap ;
562568 LRUEntries.clear ();
569+ OldestPresentEntry = nullptr ;
563570 }
564571 for (uptr I = 0 ; I < N; I++) {
565572 MemMapT &MemMap = MapInfo[I];
566573 unmapCallBack (MemMap);
567574 }
568575 }
569576
570- void releaseIfOlderThan (CachedBlock &Entry, u64 Time) REQUIRES(Mutex) {
571- if (!Entry.isValid () || !Entry.Time )
572- return ;
573- if (Entry.Time > Time) {
574- if (OldestTime == 0 || Entry.Time < OldestTime)
575- OldestTime = Entry.Time ;
576- return ;
577+ void releaseOlderThan (u64 ReleaseTime) REQUIRES(Mutex) {
578+ SCUDO_SCOPED_TRACE (GetSecondaryReleaseOlderThanTraceName ());
579+
580+ if (!Config::getQuarantineDisabled ()) {
581+ for (uptr I = 0 ; I < Config::getQuarantineSize (); I++) {
582+ auto &Entry = Quarantine[I];
583+ if (!Entry.isValid () || Entry.Time == 0 || Entry.Time > ReleaseTime)
584+ continue ;
585+ Entry.MemMap .releaseAndZeroPagesToOS (Entry.CommitBase ,
586+ Entry.CommitSize );
587+ Entry.Time = 0 ;
588+ }
577589 }
578- Entry.MemMap .releaseAndZeroPagesToOS (Entry.CommitBase , Entry.CommitSize );
579- Entry.Time = 0 ;
580- }
581590
582- void releaseOlderThan (u64 Time) REQUIRES(Mutex) {
583- SCUDO_SCOPED_TRACE (GetSecondaryReleaseOlderThanTraceName ());
591+ for (CachedBlock *Entry = OldestPresentEntry; Entry != nullptr ;
592+ Entry = LRUEntries.getPrev (Entry)) {
593+ DCHECK (Entry->isValid ());
594+ DCHECK (Entry->Time != 0 );
595+
596+ if (Entry->Time > ReleaseTime) {
597+ // All entries are newer than this, so no need to keep scanning.
598+ OldestPresentEntry = Entry;
599+ return ;
600+ }
584601
585- if (!LRUEntries.size () || OldestTime == 0 || OldestTime > Time)
586- return ;
587- OldestTime = 0 ;
588- if (!Config::getQuarantineDisabled ())
589- for (uptr I = 0 ; I < Config::getQuarantineSize (); I++)
590- releaseIfOlderThan (Quarantine[I], Time);
591- for (uptr I = 0 ; I < Config::getEntriesArraySize (); I++)
592- releaseIfOlderThan (Entries[I], Time);
602+ Entry->MemMap .releaseAndZeroPagesToOS (Entry->CommitBase ,
603+ Entry->CommitSize );
604+ Entry->Time = 0 ;
605+ }
606+ OldestPresentEntry = nullptr ;
593607 }
594608
595609 HybridMutex Mutex;
596610 u32 QuarantinePos GUARDED_BY (Mutex) = 0;
597611 atomic_u32 MaxEntriesCount = {};
598612 atomic_uptr MaxEntrySize = {};
599- u64 OldestTime GUARDED_BY (Mutex) = 0;
600613 atomic_s32 ReleaseToOsIntervalMs = {};
601614 u32 CallsToRetrieve GUARDED_BY (Mutex) = 0;
602615 u32 SuccessfulRetrieves GUARDED_BY (Mutex) = 0;
@@ -606,6 +619,8 @@ class MapAllocatorCache {
606619 NonZeroLengthArray<CachedBlock, Config::getQuarantineSize()>
607620 Quarantine GUARDED_BY (Mutex) = {};
608621
622+ // The oldest entry in the LRUEntries that has Time non-zero.
623+ CachedBlock *OldestPresentEntry GUARDED_BY (Mutex) = nullptr;
609624 // Cached blocks stored in LRU order
610625 DoublyLinkedList<CachedBlock> LRUEntries GUARDED_BY (Mutex);
611626 // The unused Entries
0 commit comments