123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132 |
- // Copyright 2019 The Chromium Authors. All rights reserved.
- // Use of this source code is governed by a BSD-style license that can be
- // found in the LICENSE file.
- #ifndef BASE_MEMORY_MADV_FREE_DISCARDABLE_MEMORY_POSIX_H_
- #define BASE_MEMORY_MADV_FREE_DISCARDABLE_MEMORY_POSIX_H_
- #include <stddef.h>
- #include <stdint.h>
- #include <atomic>
- #include <vector>
- #include "base/base_export.h"
- #include "base/callback.h"
- #include "base/memory/discardable_memory.h"
- #include "base/memory/raw_ptr.h"
- #include "base/sequence_checker.h"
- #include "base/threading/thread_collision_warner.h"
- #include "build/build_config.h"
- namespace base {
- // Discardable memory backed by the MADV_FREE advice value, available since
- // Linux 4.5.
- //
- // When unlocked, this implementation of discardable memory will
- // apply the MADV_FREE advice value to all pages within the allocated range,
- // causing pages to be discarded instead of swapped upon memory pressure.
- // When pages are discarded, they become zero-fill-on-demand pages.
- // Attempting to unlock an already-unlocked instance is undefined behaviour.
- //
- // When locked, all pages will be checked for eviction. If any page has
- // been discarded, the entire allocated range is unmapped and the lock fails.
- // After a failed lock, the instance remains unlocked but any further attempts
- // to lock will fail. Additionally, the discardable memory instance is
- // invalidated and access to memory obtained via data() is undefined behaviour.
- // Attempting to lock an already-locked instance is undefined behaviour. If no
- // page in the allocated range has been discarded, then lock succeeds and the
- // allocated range of memory is available for use without any page fault,
- // additional allocations, or memory zeroing.
- //
- // If DCHECK_IS_ON(), additional checks are added to ensure that the discardable
- // memory instance is being used correctly. These checks are not present by
- // default, as some incur a significant performance penalty or do not warrant
- // crashing the process. These checks are:
- // - Do not allow lock while already locked or unlock while already unlocked
- // - Do not allow memory access via data() if instance is deallocated after
- // Lock() (although invalid memory can still be accessed through existing
- // pointers)
- // - After Unlock(), disallow read or write of memory pointed to by data()
- // with PROT_NONE until next Lock()
- //
- // Caveats:
- // [1]: The smallest allocation unit is the size of a page, so it is
- // unsuitable for small allocations.
- //
- // [2]: The size of a discardable memory instance must be greater than 0 bytes.
- //
- class BASE_EXPORT MadvFreeDiscardableMemoryPosix : public DiscardableMemory {
- public:
- MadvFreeDiscardableMemoryPosix(size_t size_in_pages,
- std::atomic<size_t>* allocator_byte_count);
- MadvFreeDiscardableMemoryPosix(const MadvFreeDiscardableMemoryPosix&) =
- delete;
- MadvFreeDiscardableMemoryPosix& operator=(
- const MadvFreeDiscardableMemoryPosix&) = delete;
- ~MadvFreeDiscardableMemoryPosix() override;
- bool Lock() override;
- void Unlock() override;
- void* data() const override;
- bool IsLockedForTesting() const;
- void DiscardForTesting() override;
- trace_event::MemoryAllocatorDump* CreateMemoryAllocatorDump(
- const char* name,
- trace_event::ProcessMemoryDump* pmd) const override;
- protected:
- size_t GetPageCount() const { return allocated_pages_; }
- bool IsValid() const;
- void SetKeepMemoryForTesting(bool keep_memory);
- // Force page discard by applying MADV_DONTNEED hint on a page.
- // Has the same effect as if the page was naturally discarded during
- // memory pressure due to MADV_FREE (i.e. zero-fill-on-demand pages for
- // anonymous private mappings).
- // Note that MADV_DONTNEED takes effect immediately for non-shared mappings.
- void DiscardPage(size_t page_index);
- private:
- bool LockPage(size_t page_index);
- void UnlockPage(size_t page_index);
- bool Deallocate();
- // Gets whether this instance has been discarded (but not yet unmapped).
- bool IsDiscarded() const;
- // Get whether all pages in this discardable memory instance are resident.
- bool IsResident() const;
- const size_t size_in_bytes_;
- const size_t allocated_pages_;
- // Pointer to allocator memory usage metric for updating upon allocation and
- // destruction.
- raw_ptr<std::atomic<size_t>> allocator_byte_count_;
- raw_ptr<void> data_;
- bool is_locked_ = true;
- // If true, MADV_FREE will not be set on Unlock().
- bool keep_memory_for_testing_ = false;
- // Stores the first word of a page for use during locking.
- std::vector<std::atomic<intptr_t>> page_first_word_;
- DFAKE_MUTEX(thread_collision_warner_);
- };
- enum class MadvFreeSupport { kUnsupported, kSupported };
- BASE_EXPORT MadvFreeSupport GetMadvFreeSupport();
- } // namespace base
- #endif // BASE_MEMORY_MADV_FREE_DISCARDABLE_MEMORY_POSIX_H_
|