Inside Bitcoin
Opening the selected file…
Opening the selected file…
The code behind the network, with room to understand it.
Release published 2026-10-28 · Snapshot fetched 2026-11-01. Latest stable release at fetch time; development branches and Git history are excluded. Only the selected code window and visible folders load here.
1// Copyright (c) 2016-present The Bitcoin Core developers2// Distributed under the MIT software license, see the accompanying3// file COPYING or http://www.opensource.org/licenses/mit-license.php.5#ifndef BITCOIN_SUPPORT_LOCKEDPOOL_H6#define BITCOIN_SUPPORT_LOCKEDPOOL_H8#include <cstddef>9#include <list>10#include <map>11#include <memory>12#include <mutex>13#include <unordered_map>15/**16* OS-dependent allocation and deallocation of locked/pinned memory pages.17* Abstract base class.18*/19class LockedPageAllocator20{21public:22virtual ~LockedPageAllocator() = default;23/** Allocate and lock memory pages.24* If len is not a multiple of the system page size, it is rounded up.25* Returns nullptr in case of allocation failure.26*27* If locking the memory pages could not be accomplished it will still28* return the memory, however the lockingSuccess flag will be false.29* lockingSuccess is undefined if the allocation fails.30*/31virtual void* AllocateLocked(size_t len, bool *lockingSuccess) = 0;33/** Unlock and free memory pages.34* Clear the memory before unlocking.35*/36virtual void FreeLocked(void* addr, size_t len) = 0;38/** Get the total limit on the amount of memory that may be locked by this39* process, in bytes. Return size_t max if there is no limit or the limit40* is unknown. Return 0 if no memory can be locked at all.41*/42virtual size_t GetLimit() = 0;43};45/* An arena manages a contiguous region of memory by dividing it into46* chunks.47*/48class Arena49{50public:51Arena(void *base, size_t size, size_t alignment);52virtual ~Arena();54Arena(const Arena& other) = delete; // non construction-copyable55Arena& operator=(const Arena&) = delete; // non copyable57/** Memory statistics. */58struct Stats59{60size_t used;61size_t free;62size_t total;63size_t chunks_used;64size_t chunks_free;65};67/** Allocate size bytes from this arena.68* Returns pointer on success, or 0 if memory is full or69* the application tried to allocate 0 bytes.70*/71void* alloc(size_t size);73/** Free a previously allocated chunk of memory.74* Freeing the zero pointer has no effect.75* Raises std::runtime_error in case of error.76*/77void free(void *ptr);79/** Get arena usage statistics */80Stats stats() const;82#ifdef ARENA_DEBUG83void walk() const;84#endif86/** Return whether a pointer points inside this arena.87* This returns base <= ptr < (base+size) so only use it for (inclusive)88* chunk starting addresses.89*/90bool addressInArena(void *ptr) const { return ptr >= base && ptr < end; }91private:92typedef std::multimap<size_t, void*> SizeToChunkSortedMap;93/** Map to enable O(log(n)) best-fit allocation, as it's sorted by size */94SizeToChunkSortedMap size_to_free_chunk;96typedef std::unordered_map<void*, SizeToChunkSortedMap::const_iterator> ChunkToSizeMap;97/** Map from begin of free chunk to its node in size_to_free_chunk */98ChunkToSizeMap chunks_free;99/** Map from end of free chunk to its node in size_to_free_chunk */100ChunkToSizeMap chunks_free_end;102/** Map from begin of used chunk to its size */103std::unordered_map<void*, size_t> chunks_used;105/** Base address of arena */106void* base;107/** End address of arena */108void* end;109/** Minimum chunk alignment */110size_t alignment;111};113/** Pool for locked memory chunks.114*115* To avoid sensitive key data from being swapped to disk, the memory in this pool116* is locked/pinned.117*118* An arena manages a contiguous region of memory. The pool starts out with one arena119* but can grow to multiple arenas if the need arises.120*121* Unlike a normal C heap, the administrative structures are separate from the managed122* memory. This has been done as the sizes and bases of objects are not in themselves sensitive123* information, as to conserve precious locked memory. In some operating systems124* the amount of memory that can be locked is small.125*/126class LockedPool127{128public:129/** Size of one arena of locked memory. This is a compromise.130* Do not set this too low, as managing many arenas will increase131* allocation and deallocation overhead. Setting it too high allocates132* more locked memory from the OS than strictly necessary.133*/134static constexpr size_t ARENA_SIZE{256*1024};135/** Chunk alignment. Another compromise. Setting this too high will waste136* memory, setting it too low will facilitate fragmentation.137*/138static constexpr size_t ARENA_ALIGN{16};140/** Callback when allocation succeeds but locking fails.141*/142typedef bool (*LockingFailed_Callback)();144/** Memory statistics. */145struct Stats146{147size_t used;148size_t free;149size_t total;150size_t locked;151size_t chunks_used;152size_t chunks_free;153};155/** Create a new LockedPool. This takes ownership of the MemoryPageLocker,156* you can only instantiate this with LockedPool(std::move(...)).157*158* The second argument is an optional callback when locking a newly allocated arena failed.159* If this callback is provided and returns false, the allocation fails (hard fail), if160* it returns true the allocation proceeds, but it could warn.161*/162explicit LockedPool(std::unique_ptr<LockedPageAllocator> allocator, LockingFailed_Callback lf_cb_in = nullptr);163~LockedPool();165LockedPool(const LockedPool& other) = delete; // non construction-copyable166LockedPool& operator=(const LockedPool&) = delete; // non copyable168/** Allocate size bytes from this arena.169* Returns pointer on success, or 0 if memory is full or170* the application tried to allocate 0 bytes.171*/172void* alloc(size_t size);174/** Free a previously allocated chunk of memory.175* Freeing the zero pointer has no effect.176* Raises std::runtime_error in case of error.177*/178void free(void *ptr);180/** Get pool usage statistics */181Stats stats() const;182private:183std::unique_ptr<LockedPageAllocator> allocator;185/** Create an arena from locked pages */186class LockedPageArena: public Arena187{188public:189LockedPageArena(LockedPageAllocator *alloc_in, void *base_in, size_t size, size_t align);190~LockedPageArena();191private:192void *base;193size_t size;194LockedPageAllocator *allocator;195};197bool new_arena(size_t size, size_t align);199std::list<LockedPageArena> arenas;200LockingFailed_Callback lf_cb;201size_t cumulative_bytes_locked{0};202/** Mutex protects access to this pool's data structures, including arenas.203*/204mutable std::mutex mutex;205};207/**208* Singleton class to keep track of locked (ie, non-swappable) memory, for use in209* std::allocator templates.210*211* Some implementations of the STL allocate memory in some constructors (i.e., see212* MSVC's vector<T> implementation where it allocates 1 byte of memory in the allocator.)213* Due to the unpredictable order of static initializers, we have to make sure the214* LockedPoolManager instance exists before any other STL-based objects that use215* secure_allocator are created. So instead of having LockedPoolManager also be216* static-initialized, it is created on demand.217*/218class LockedPoolManager : public LockedPool219{220public:221/** Return the current instance, or create it once */222static LockedPoolManager& Instance();224private:225explicit LockedPoolManager(std::unique_ptr<LockedPageAllocator> allocator);227/** Create a new LockedPoolManager specialized to the OS */228static void CreateInstance();229/** Called when locking fails, warn the user here */230static bool LockingFailed();232static LockedPoolManager* _instance;233};235#endif // BITCOIN_SUPPORT_LOCKEDPOOL_H
Independent explanations by MyBitcoinExplorer. Not affiliated with or endorsed by Bitcoin Core. Guides are educational and do not replace the source or its tests.
Bitcoin Core source © its contributors, distributed under the MIT license. Original notices and bundled third-party licenses are retained in the source tree.