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#include <support/lockedpool.h>6#include <support/cleanse.h>8#ifdef WIN329#include <windows.h>10#else11#include <sys/mman.h>12#include <sys/resource.h>13#include <unistd.h>14#endif16#include <algorithm>17#include <limits>18#include <stdexcept>19#include <utility>20#ifdef ARENA_DEBUG21#include <iomanip>22#include <iostream>23#endif25LockedPoolManager* LockedPoolManager::_instance = nullptr;27/*******************************************************************************/28// Utilities29//30/** Align up to power of 2 */31static inline size_t align_up(size_t x, size_t align)32{33return (x + align - 1) & ~(align - 1);34}36/*******************************************************************************/37// Implementation: Arena39Arena::Arena(void *base_in, size_t size_in, size_t alignment_in):40base(base_in), end(static_cast<char*>(base_in) + size_in), alignment(alignment_in)41{42// Start with one free chunk that covers the entire arena43auto it = size_to_free_chunk.emplace(size_in, base);44chunks_free.emplace(base, it);45chunks_free_end.emplace(static_cast<char*>(base) + size_in, it);46}48Arena::~Arena() = default;50void* Arena::alloc(size_t size)51{52// Round to next multiple of alignment53size = align_up(size, alignment);55// Don't handle zero-sized chunks56if (size == 0)57return nullptr;59// Pick a large enough free-chunk. Returns an iterator pointing to the first element that is not less than key.60// This allocation strategy is best-fit. According to "Dynamic Storage Allocation: A Survey and Critical Review",61// Wilson et. al. 1995, https://www.scs.stanford.edu/14wi-cs140/sched/readings/wilson.pdf, best-fit and first-fit62// policies seem to work well in practice.63auto size_ptr_it = size_to_free_chunk.lower_bound(size);64if (size_ptr_it == size_to_free_chunk.end())65return nullptr;67// Create the used-chunk, taking its space from the end of the free-chunk68const size_t size_remaining = size_ptr_it->first - size;69char* const free_chunk = static_cast<char*>(size_ptr_it->second);70auto allocated = chunks_used.emplace(free_chunk + size_remaining, size).first;71chunks_free_end.erase(free_chunk + size_ptr_it->first);72if (size_ptr_it->first == size) {73// whole chunk is used up74chunks_free.erase(size_ptr_it->second);75} else {76// still some memory left in the chunk77auto it_remaining = size_to_free_chunk.emplace(size_remaining, size_ptr_it->second);78chunks_free[size_ptr_it->second] = it_remaining;79chunks_free_end.emplace(free_chunk + size_remaining, it_remaining);80}81size_to_free_chunk.erase(size_ptr_it);83return allocated->first;84}86void Arena::free(void *ptr)87{88// Freeing the nullptr pointer is OK.89if (ptr == nullptr) {90return;91}93// Remove chunk from used map94auto i = chunks_used.find(ptr);95if (i == chunks_used.end()) {96throw std::runtime_error("Arena: invalid or double free");97}98auto freed = std::make_pair(static_cast<char*>(i->first), i->second);99chunks_used.erase(i);101// coalesce freed with previous chunk102auto prev = chunks_free_end.find(freed.first);103if (prev != chunks_free_end.end()) {104freed.first -= prev->second->first;105freed.second += prev->second->first;106size_to_free_chunk.erase(prev->second);107chunks_free_end.erase(prev);108}110// coalesce freed with chunk after freed111auto next = chunks_free.find(freed.first + freed.second);112if (next != chunks_free.end()) {113freed.second += next->second->first;114size_to_free_chunk.erase(next->second);115chunks_free.erase(next);116}118// Add/set space with coalesced free chunk119auto it = size_to_free_chunk.emplace(freed.second, freed.first);120chunks_free[freed.first] = it;121chunks_free_end[freed.first + freed.second] = it;122}124Arena::Stats Arena::stats() const125{126Arena::Stats r{ 0, 0, 0, chunks_used.size(), chunks_free.size() };127for (const auto& chunk: chunks_used)128r.used += chunk.second;129for (const auto& chunk: chunks_free)130r.free += chunk.second->first;131r.total = r.used + r.free;132return r;133}135#ifdef ARENA_DEBUG136static void printchunk(void* base, size_t sz, bool used) {137std::cout <<138"0x" << std::hex << std::setw(16) << std::setfill('0') << base <<139" 0x" << std::hex << std::setw(16) << std::setfill('0') << sz <<140" 0x" << used << std::endl;141}142void Arena::walk() const143{144for (const auto& chunk: chunks_used)145printchunk(chunk.first, chunk.second, true);146std::cout << std::endl;147for (const auto& chunk: chunks_free)148printchunk(chunk.first, chunk.second->first, false);149std::cout << std::endl;150}151#endif153/*******************************************************************************/154// Implementation: Win32LockedPageAllocator156#ifdef WIN32157/** LockedPageAllocator specialized for Windows.158*/159class Win32LockedPageAllocator: public LockedPageAllocator160{161public:162Win32LockedPageAllocator();163void* AllocateLocked(size_t len, bool *lockingSuccess) override;164void FreeLocked(void* addr, size_t len) override;165size_t GetLimit() override;166private:167size_t page_size;168};170Win32LockedPageAllocator::Win32LockedPageAllocator()171{172// Determine system page size in bytes173SYSTEM_INFO sSysInfo;174GetSystemInfo(&sSysInfo);175page_size = sSysInfo.dwPageSize;176}177void *Win32LockedPageAllocator::AllocateLocked(size_t len, bool *lockingSuccess)178{179len = align_up(len, page_size);180void *addr = VirtualAlloc(nullptr, len, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE);181if (addr) {182// VirtualLock is used to attempt to keep keying material out of swap. Note183// that it does not provide this as a guarantee, but, in practice, memory184// that has been VirtualLock'd almost never gets written to the pagefile185// except in rare circumstances where memory is extremely low.186*lockingSuccess = VirtualLock(const_cast<void*>(addr), len) != 0;187}188return addr;189}190void Win32LockedPageAllocator::FreeLocked(void* addr, size_t len)191{192len = align_up(len, page_size);193memory_cleanse(addr, len);194VirtualUnlock(const_cast<void*>(addr), len);195}197size_t Win32LockedPageAllocator::GetLimit()198{199size_t min, max;200if(GetProcessWorkingSetSize(GetCurrentProcess(), &min, &max) != 0) {201return min;202}203return std::numeric_limits<size_t>::max();204}205#endif207/*******************************************************************************/208// Implementation: PosixLockedPageAllocator210#ifndef WIN32211/** LockedPageAllocator specialized for OSes that don't try to be212* special snowflakes.213*/214class PosixLockedPageAllocator: public LockedPageAllocator215{216public:217PosixLockedPageAllocator();218void* AllocateLocked(size_t len, bool *lockingSuccess) override;219void FreeLocked(void* addr, size_t len) override;220size_t GetLimit() override;221private:222size_t page_size;223};225PosixLockedPageAllocator::PosixLockedPageAllocator()226{227// Determine system page size in bytes228#if defined(PAGESIZE) // defined in limits.h229page_size = PAGESIZE;230#else // assume some POSIX OS231page_size = sysconf(_SC_PAGESIZE);232#endif233}235void *PosixLockedPageAllocator::AllocateLocked(size_t len, bool *lockingSuccess)236{237void *addr;238len = align_up(len, page_size);239addr = mmap(nullptr, len, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0);240if (addr == MAP_FAILED) {241return nullptr;242}243if (addr) {244*lockingSuccess = mlock(addr, len) == 0;245#if defined(MADV_DONTDUMP) // Linux246madvise(addr, len, MADV_DONTDUMP);247#elif defined(MADV_NOCORE) // FreeBSD248madvise(addr, len, MADV_NOCORE);249#endif250}
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.