8
0
mirror of https://github.com/FirebirdSQL/firebird.git synced 2025-01-22 16:43:03 +01:00

Merge pull request #6991 from FirebirdSQL/work/external-pool

Introduce the external memory pool.
This commit is contained in:
Adriano dos Santos Fernandes 2021-10-30 20:08:24 -03:00 committed by GitHub
commit e64c3aacad
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
14 changed files with 375 additions and 185 deletions

View File

@ -21,7 +21,7 @@
# Notes:
# Firebird requires the HP-UX Atomic APIs ("AtomicAPI" bundle), released as an
# optional Software Pack (SPK) for HP-UX 11i v2 or v3.
# optional Software Pack (SPK) for HP-UX 11i v2 or v3.
# Before attempting the HPUX build, you must export necessary
# CFLAGS and CXXFLAGS to be picked up by the configure process and
@ -60,15 +60,12 @@ COMMON_FLAGS= -DHP11 -DHPUX -D_XOPEN_SOURCE_EXTENDED -D_HP_ATOMIC_INLINE \
# Flags specific to production or debug build...
# -z, disallow dereferencing of null pointers at runtime
# -DLIBC_CALLS_NEW, Firebird macro, used when C++ runtime can call
# redefined by us operator new before initialization of global variables.
# Required on IA-64, but evidently only by debug build!?
ifeq ($(shell uname -m),ia64)
# ...for IA-64
PROD_FLAGS= +O2 +Onolimit +Ofltacc=strict +Ofenvaccess \
$(COMMON_FLAGS)
DEV_FLAGS= -g -z -DLIBC_CALLS_NEW \
DEV_FLAGS= -g -z \
$(COMMON_FLAGS)
else
# ...for PA-RISC

25
extern/re2/re2/re2.cc vendored
View File

@ -21,6 +21,7 @@
#include <algorithm>
#include <atomic>
#include <iterator>
#include <memory>
#include <mutex>
#include <string>
#include <utility>
@ -60,9 +61,9 @@ RE2::Options::Options(RE2::CannedOptions opt)
// static empty objects for use as const references.
// To avoid global constructors, allocated in RE2::Init().
static const std::string* empty_string;
static const std::map<std::string, int>* empty_named_groups;
static const std::map<int, std::string>* empty_group_names;
static std::unique_ptr<const std::string> empty_string;
static std::unique_ptr<const std::map<std::string, int>> empty_named_groups;
static std::unique_ptr<const std::map<int, std::string>> empty_group_names;
// Converts from Regexp error code to RE2 error code.
// Maybe some day they will diverge. In any event, this
@ -173,15 +174,15 @@ int RE2::Options::ParseFlags() const {
void RE2::Init(const StringPiece& pattern, const Options& options) {
static std::once_flag empty_once;
std::call_once(empty_once, []() {
empty_string = new std::string;
empty_named_groups = new std::map<std::string, int>;
empty_group_names = new std::map<int, std::string>;
empty_string.reset(new std::string);
empty_named_groups.reset(new std::map<std::string, int>);
empty_group_names.reset(new std::map<int, std::string>);
});
pattern_.assign(pattern.data(), pattern.size());
options_.Copy(options);
entire_regexp_ = NULL;
error_ = empty_string;
error_ = empty_string.get();
error_code_ = NoError;
error_arg_.clear();
prefix_.clear();
@ -267,11 +268,11 @@ RE2::~RE2() {
entire_regexp_->Decref();
delete prog_;
delete rprog_;
if (error_ != empty_string)
if (error_ != empty_string.get())
delete error_;
if (named_groups_ != NULL && named_groups_ != empty_named_groups)
if (named_groups_ != NULL && named_groups_ != empty_named_groups.get())
delete named_groups_;
if (group_names_ != NULL && group_names_ != empty_group_names)
if (group_names_ != NULL && group_names_ != empty_group_names.get())
delete group_names_;
}
@ -352,7 +353,7 @@ const std::map<std::string, int>& RE2::NamedCapturingGroups() const {
if (re->suffix_regexp_ != NULL)
re->named_groups_ = re->suffix_regexp_->NamedCaptures();
if (re->named_groups_ == NULL)
re->named_groups_ = empty_named_groups;
re->named_groups_ = empty_named_groups.get();
}, this);
return *named_groups_;
}
@ -363,7 +364,7 @@ const std::map<int, std::string>& RE2::CapturingGroupNames() const {
if (re->suffix_regexp_ != NULL)
re->group_names_ = re->suffix_regexp_->CaptureNames();
if (re->group_names_ == NULL)
re->group_names_ = empty_group_names;
re->group_names_ = empty_group_names.get();
}, this);
return *group_names_;
}

View File

@ -234,7 +234,7 @@ private:
{
unsigned l = aMeta->getMessageLength(&statusWrapper);
check(&statusWrapper);
buffer = new unsigned char[l];
buffer = FB_NEW unsigned char[l];
}
public:
@ -336,7 +336,7 @@ public:
if (!charBuffer)
{
charBuffer = new char[size + 1];
charBuffer = FB_NEW char[size + 1];
}
getStrValue(charBuffer);
return charBuffer;

View File

@ -40,12 +40,22 @@
#include "firebird.h"
#include "../common/classes/alloc.h"
#ifndef WIN_NT
#ifdef WIN_NT
#include <windows.h>
#ifndef PATH_MAX
#define PATH_MAX MAX_PATH
#endif
#else
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <sys/mman.h>
#endif
#include "../common/classes/fb_tls.h"
@ -68,25 +78,10 @@
#define VALGRIND_FIX_IT // overrides suspicious valgrind behavior
#endif // USE_VALGRIND
void* operator new(size_t s ALLOC_PARAMS)
{
return MemoryPool::globalAlloc(s ALLOC_PASS_ARGS);
}
void* operator new[](size_t s ALLOC_PARAMS)
{
return MemoryPool::globalAlloc(s ALLOC_PASS_ARGS);
}
void operator delete(void* mem ALLOC_PARAMS) noexcept
{
MemoryPool::globalFree(mem);
}
void operator delete[](void* mem ALLOC_PARAMS) noexcept
{
MemoryPool::globalFree(mem);
}
namespace {
///#define MEM_DEBUG_EXTERNAL
/*** emergency debugging stuff
static const char* lastFileName;
static int lastLine;
@ -147,7 +142,14 @@ typedef Firebird::AtomicCounter::counter_type StatInt;
const int MAP_CACHE_SIZE = 16; // == 1 MB
const size_t DEFAULT_ALLOCATION = 65536;
Firebird::Vector<void*, MAP_CACHE_SIZE> extents_cache;
struct ExtentsCache // C++ aggregate - members are statically initialized to zeros
{
unsigned count;
void* data[MAP_CACHE_SIZE];
};
ExtentsCache defaultExtentsCache;
ExtentsCache externalExtentsCache;
#ifndef WIN_NT
struct FailedBlock
@ -191,7 +193,7 @@ inline size_t get_map_page_size()
static volatile size_t map_page_size = 0;
if (!map_page_size)
{
Firebird::MutexLockGuard guard(*cache_mutex, "get_map_page_size");
Firebird::MutexLockGuard guard(cache_mutex, "get_map_page_size");
if (!map_page_size)
map_page_size = get_page_size();
}
@ -1731,10 +1733,22 @@ private:
public:
static MemPool* defaultMemPool;
MemPool();
MemPool(MemPool& parent, MemoryStats& stats);
MemPool(MemoryStats& stats, ExtentsCache* extentsCache);
MemPool(MemPool& parent, MemoryStats& stats, ExtentsCache* extentsCache);
virtual ~MemPool(void);
public:
static inline constexpr MemPool* getPoolFromPointer(void* ptr) noexcept
{
if (ptr)
{
auto block = (MemBlock*) ((UCHAR*) ptr - offsetof(MemBlock, body));
return block->pool;
}
return nullptr;
}
private:
static const size_t minAllocation = 65536;
static const size_t roundingSize = ALLOC_ALIGNMENT;
@ -1749,12 +1763,10 @@ private:
int blocksActive;
bool pool_destroying, parent_redirect;
// Statistics group for the pool
MemoryStats* stats;
// Parent pool if present
MemPool* parent;
// Memory used
AtomicCounter used_memory, mapped_memory;
MemoryStats* stats; // Statistics group for the pool
MemPool* parent; // Parent pool if present
ExtentsCache* extentsCache;
AtomicCounter used_memory, mapped_memory; // Memory used
private:
@ -1810,7 +1822,7 @@ private:
virtual void memoryIsExhausted(void);
void* allocRaw(size_t length);
static void releaseMemory(void* block, bool flagExtent) noexcept;
static void releaseRaw(bool destroying, void *block, size_t size, bool use_cache = true) noexcept;
static void releaseRaw(bool destroying, void *block, size_t size, ExtentsCache* extentsCache) noexcept;
void* getExtent(size_t from, size_t& to);
public:
@ -1843,23 +1855,36 @@ public:
void setStatsGroup(MemoryStats& stats) noexcept;
// Initialize and finalize global memory pool
static MemPool* init()
static MemPool* initDefaultPool()
{
fb_assert(!defaultMemPool);
static char mpBuffer[sizeof(MemPool) + ALLOC_ALIGNMENT];
defaultMemPool = new((void*)(IPTR) MEM_ALIGN((size_t)(IPTR) mpBuffer)) MemPool();
alignas(alignof(MemPool)) static char mpBuffer[sizeof(MemPool)];
defaultMemPool = new(mpBuffer) MemPool(*MemoryPool::default_stats_group, &defaultExtentsCache);
return defaultMemPool;
}
static void cleanup()
static void cleanupDefaultPool()
{
defaultMemPool->~MemPool();
defaultMemPool = NULL;
while (extents_cache.getCount())
releaseRaw(true, extents_cache.pop(), DEFAULT_ALLOCATION, false);
while (defaultExtentsCache.count)
releaseRaw(true, defaultExtentsCache.data[--defaultExtentsCache.count], DEFAULT_ALLOCATION, nullptr);
cleanupFailedList();
}
static void cleanupExternalPool()
{
while (externalExtentsCache.count)
releaseRaw(true, externalExtentsCache.data[--externalExtentsCache.count], DEFAULT_ALLOCATION, nullptr);
cleanupFailedList();
}
static void cleanupFailedList()
{
#ifndef WIN_NT
unsigned oldCount = 0;
@ -1880,7 +1905,7 @@ public:
++newCount;
FailedBlock* fb = oldList;
SemiDoubleLink::pop(oldList);
releaseRaw(true, fb, fb->blockSize, false);
releaseRaw(true, fb, fb->blockSize, nullptr);
}
if (newCount == oldCount)
@ -1889,7 +1914,6 @@ public:
oldCount = newCount;
}
#endif // WIN_NT
}
// Statistics
@ -2012,28 +2036,28 @@ GlobalPtr<Mutex> forceCreationOfDefaultMemoryPool;
MemoryPool* MemoryPool::defaultMemoryManager = NULL;
MemoryStats* MemoryPool::default_stats_group = NULL;
MemoryPool* MemoryPool::externalMemoryManager = NULL;
MemPool* MemPool::defaultMemPool = NULL;
// Initialize process memory pool (called from InstanceControl).
void MemoryPool::init()
void MemoryPool::initDefaultPool()
{
static char mtxBuffer[sizeof(Mutex) + ALLOC_ALIGNMENT];
cache_mutex = new((void*)(IPTR) MEM_ALIGN((size_t)(IPTR) mtxBuffer)) Mutex;
alignas(alignof(Mutex)) static char mtxBuffer[sizeof(Mutex)];
cache_mutex = new(mtxBuffer) Mutex;
static char msBuffer[sizeof(MemoryStats) + ALLOC_ALIGNMENT];
default_stats_group =
new((void*)(IPTR) MEM_ALIGN((size_t)(IPTR) msBuffer)) MemoryStats;
alignas(alignof(MemoryStats)) static char msBuffer[sizeof(MemoryStats)];
default_stats_group = new(msBuffer) MemoryStats;
static char mpBuffer[sizeof(MemoryPool) + ALLOC_ALIGNMENT];
defaultMemoryManager = new((void*)(IPTR) MEM_ALIGN((size_t)(IPTR) mpBuffer)) MemoryPool(MemPool::init());
alignas(alignof(MemoryPool)) static char mpBuffer[sizeof(MemoryPool)];
defaultMemoryManager = new(mpBuffer) MemoryPool(MemPool::initDefaultPool());
}
// Should be last routine, called by InstanceControl,
// being therefore the very last routine in firebird module.
void MemoryPool::cleanup()
void MemoryPool::cleanupDefaultPool()
{
#ifdef VALGRIND_FIX_IT
VALGRIND_DISCARD(
@ -2047,7 +2071,7 @@ void MemoryPool::cleanup()
if (defaultMemoryManager)
{
//defaultMemoryManager->~MemoryPool();
MemPool::cleanup();
MemPool::cleanupDefaultPool();
defaultMemoryManager = NULL;
}
@ -2065,15 +2089,23 @@ void MemoryPool::cleanup()
}
MemPool::MemPool()
: pool_destroying(false), parent_redirect(false), stats(MemoryPool::default_stats_group), parent(NULL)
MemPool::MemPool(MemoryStats& s, ExtentsCache* cache)
: pool_destroying(false),
parent_redirect(false),
stats(&s),
parent(NULL),
extentsCache(cache)
{
fb_assert(offsetof(MemBlock, body) == MEM_ALIGN(offsetof(MemBlock, body)));
initialize();
}
MemPool::MemPool(MemPool& p, MemoryStats& s)
: pool_destroying(false), parent_redirect(true), stats(&s), parent(&p)
MemPool::MemPool(MemPool& p, MemoryStats& s, ExtentsCache* cache)
: pool_destroying(false),
parent_redirect(true),
stats(&s),
parent(&p),
extentsCache(cache)
{
initialize();
}
@ -2133,7 +2165,7 @@ MemPool::~MemPool(void)
{
MemBigHunk* hunk = bigHunks;
bigHunks = hunk->next;
releaseRaw(pool_destroying, hunk, hunk->length);
releaseRaw(pool_destroying, hunk, hunk->length, extentsCache);
}
if (parent)
@ -2210,7 +2242,7 @@ MemoryPool* MemoryPool::createPool(MemoryPool* parentPool, MemoryStats& stats)
if (!parentPool)
parentPool = getDefaultMemoryPool();
MemPool* p = FB_NEW_POOL(*parentPool) MemPool(*(parentPool->pool), stats);
MemPool* p = FB_NEW_POOL(*parentPool) MemPool(*(parentPool->pool), stats, &defaultExtentsCache);
return FB_NEW_POOL(*parentPool) MemoryPool(p);
}
@ -2461,7 +2493,7 @@ void MemPool::releaseBlock(MemBlock* block, bool decrUsage) noexcept
MemBigHunk* hunk = (MemBigHunk*)(((UCHAR*)block) - MemBigHunk::hdrSize());
SemiDoubleLink::remove(hunk);
decrement_mapping(FB_ALIGN(hunk->length, get_map_page_size()));
releaseRaw(pool_destroying, hunk, hunk->length, false);
releaseRaw(pool_destroying, hunk, hunk->length, nullptr);
}
void MemPool::memoryIsExhausted(void)
@ -2474,12 +2506,12 @@ void* MemPool::allocRaw(size_t size)
#ifndef USE_VALGRIND
if (size == DEFAULT_ALLOCATION)
{
MutexLockGuard guard(*cache_mutex, "MemPool::allocRaw");
if (extents_cache.hasData())
MutexLockGuard guard(cache_mutex, "MemPool::allocRaw");
if (extentsCache->count)
{
// Use most recently used object to encourage caching
increment_mapping(size);
return extents_cache.pop();
return extentsCache->data[--extentsCache->count];
}
}
#endif
@ -2497,7 +2529,7 @@ void* MemPool::allocRaw(size_t size)
void* result = NULL;
if (failedList)
{
MutexLockGuard guard(*cache_mutex, "MemPool::allocRaw");
MutexLockGuard guard(cache_mutex, "MemPool::allocRaw");
for (FailedBlock* fb = failedList; fb; fb = fb->next)
{
if (fb->blockSize == size)
@ -2568,20 +2600,20 @@ void MemPool::releaseExtent(bool destroying, void* block, size_t size, MemPool*
{
if (pool)
pool->decrement_mapping(size);
releaseRaw(true, block, size, pool);
releaseRaw(true, block, size, (pool ? pool->extentsCache : nullptr));
}
}
void MemPool::releaseRaw(bool destroying, void* block, size_t size, bool use_cache) noexcept
void MemPool::releaseRaw(bool destroying, void* block, size_t size, ExtentsCache* extentsCache) noexcept
{
#ifndef USE_VALGRIND
if (use_cache && (size == DEFAULT_ALLOCATION))
if (extentsCache && (size == DEFAULT_ALLOCATION))
{
MutexLockGuard guard(*cache_mutex, "MemPool::releaseRaw");
if (extents_cache.getCount() < extents_cache.getCapacity())
MutexLockGuard guard(cache_mutex, "MemPool::releaseRaw");
if (extentsCache->count < MAP_CACHE_SIZE)
{
extents_cache.push(block);
extentsCache->data[extentsCache->count++] = block;
return;
}
}
@ -2599,7 +2631,7 @@ void MemPool::releaseRaw(bool destroying, void* block, size_t size, bool use_cac
if (destroying)
{
// Synchronize delayed free queue using extents mutex
MutexLockGuard guard(*cache_mutex, "MemPool::releaseRaw");
MutexLockGuard guard(cache_mutex, "MemPool::releaseRaw");
// Extend circular buffer if possible
if (delayedExtentCount < FB_NELEM(delayedExtents))
@ -2656,7 +2688,7 @@ void MemPool::releaseRaw(bool destroying, void* block, size_t size, bool use_cac
FailedBlock* failed = (FailedBlock*) block;
failed->blockSize = size;
MutexLockGuard guard(*cache_mutex, "MemPool::releaseRaw");
MutexLockGuard guard(cache_mutex, "MemPool::releaseRaw");
SemiDoubleLink::push(&failedList, failed);
return;
@ -2817,25 +2849,6 @@ MemoryPool& AutoStorage::getAutoMemoryPool()
return *p;
}
#ifdef LIBC_CALLS_NEW
void* MemoryPool::globalAlloc(size_t s ALLOC_PARAMS)
{
if (!defaultMemoryManager)
{
// this will do all required init, including processMemoryPool creation
static Firebird::InstanceControl dummy;
fb_assert(defaultMemoryManager);
}
return defaultMemoryManager->allocate(s ALLOC_PASS_ARGS);
}
#endif // LIBC_CALLS_NEW
void MemoryPool::globalFree(void* block) noexcept
{
MemPool::globalFree(block);
}
void* MemoryPool::allocate(size_t size ALLOC_PARAMS)
{
return pool->allocate(size ALLOC_PASS_ARGS);
@ -2924,6 +2937,159 @@ void MemoryPool::unregisterFinalizer(Finalizer*& finalizer)
}
class ExternalMemoryHandler
{
friend class MemoryPool;
private:
struct Objects
{
MemoryStats memoryStats;
MemPool memPool{memoryStats, &externalExtentsCache};
MemoryPool memoryPool{&memPool};
};
static ExternalMemoryHandler* instance;
public:
enum class State : UCHAR
{
ALIVE,
DEAD,
DYING
};
public:
ExternalMemoryHandler()
{
Mutex::initMutexes();
#ifdef MEM_DEBUG_EXTERNAL
printf("ExternalMemoryHandler::ExternalMemoryHandler()\n");
#endif
instance = this;
new(objectsBuffer) Objects();
MemoryPool::externalMemoryManager = &objects().memoryPool;
atexit([] {
const auto currentUsage = instance->objects().memoryStats.getCurrentUsage();
#ifdef MEM_DEBUG_EXTERNAL
printf("ExternalMemoryHandler atexit: %" SIZEFORMAT "\n", currentUsage);
#endif
ExternalMemoryHandler::printContents("atexit");
if (currentUsage == 0)
ExternalMemoryHandler::free();
else
instance->state = State::DYING;
});
}
void revive()
{
#ifdef MEM_DEBUG_EXTERNAL
printf("ExternalMemoryHandler::revive()\n");
#endif
new(this) ExternalMemoryHandler();
}
static void printContents(const char* moment)
{
#if defined(MEM_DEBUG) && defined(DEBUG_GDS_ALLOC)
if (!MemoryPool::externalMemoryManager)
return;
static bool alreadyPrinted = false;
Firebird::AutoPtr<FILE> file;
{ // scope
char name[PATH_MAX];
if (os_utils::getCurrentModulePath(name, sizeof(name)))
strncat(name, ".memdebug.external.log", sizeof(name) - 1);
else
strcpy(name, "memdebug.external.log");
file = os_utils::fopen(name, alreadyPrinted ? "at" : "w+t");
}
if (file)
{
fprintf(file, "********* Moment: %s\n", moment);
MemoryPool::externalMemoryManager->print_contents(file,
Firebird::MemoryPool::PRINT_USED_ONLY | Firebird::MemoryPool::PRINT_RECURSIVE);
file = NULL;
alreadyPrinted = true;
}
#endif
}
static void free()
{
if (instance->state != State::DEAD)
{
instance->state = State::DEAD;
instance->objects().~Objects();
instance->~ExternalMemoryHandler();
instance = nullptr;
MemPool::cleanupExternalPool();
}
MemoryPool::externalMemoryManager = nullptr;
}
inline Objects& objects()
{
return *(Objects*) objectsBuffer;
}
alignas(alignof(Objects)) char objectsBuffer[sizeof(Objects)];
State state = State::ALIVE;
};
ExternalMemoryHandler* ExternalMemoryHandler::instance = nullptr;
void initExternalMemoryPool()
{
static ExternalMemoryHandler handler;
if (handler.state == ExternalMemoryHandler::State::DEAD)
handler.revive();
}
void MemoryPool::globalFree(void* block) noexcept
{
auto pool = MemPool::getPoolFromPointer(block);
MemPool::globalFree(block);
if (auto externalMemoryHandler = ExternalMemoryHandler::instance;
externalMemoryHandler &&
externalMemoryHandler->state == ExternalMemoryHandler::State::DYING &&
pool == &externalMemoryHandler->objects().memPool)
{
const auto currentUsage = externalMemoryHandler->objects().memoryStats.getCurrentUsage();
#ifdef MEM_DEBUG_EXTERNAL
printf("MemoryPool::globalFree() - dying ExternalMemoryHandler: %" SIZEFORMAT "\n", currentUsage);
#endif
ExternalMemoryHandler::printContents("globalFree");
if (currentUsage == 0)
ExternalMemoryHandler::free();
}
}
#if defined(DEV_BUILD)
void AutoStorage::ProbeStack() const
{
@ -2949,14 +3115,15 @@ void AutoStorage::ProbeStack() const
// Global operator "delete" is always redefined by firebird,
// in a case when we actually need "new" only with file/line information
// this version should be also present as a pair for "delete".
#ifdef DEBUG_GDS_ALLOC
void* operator new(size_t s)
{
return MemoryPool::globalAlloc(s ALLOC_ARGS);
return getExternalMemoryPool()->allocate(s ALLOC_ARGS);
}
void* operator new[](size_t s)
{
return MemoryPool::globalAlloc(s ALLOC_ARGS);
return getExternalMemoryPool()->allocate(s ALLOC_ARGS);
}
void operator delete(void* mem) noexcept
@ -2968,5 +3135,3 @@ void operator delete[](void* mem) noexcept
{
MemoryPool::globalFree(mem);
}
#endif // DEBUG_GDS_ALLOC

View File

@ -59,11 +59,11 @@
#include <memory.h>
#ifdef DEBUG_GDS_ALLOC
#define FB_NEW new(__FILE__, __LINE__)
#define FB_NEW new(*getDefaultMemoryPool(), __FILE__, __LINE__)
#define FB_NEW_POOL(pool) new(pool, __FILE__, __LINE__)
#define FB_NEW_RPT(pool, count) new(pool, count, __FILE__, __LINE__)
#else // DEBUG_GDS_ALLOC
#define FB_NEW new
#define FB_NEW new(*getDefaultMemoryPool())
#define FB_NEW_POOL(pool) new(pool)
#define FB_NEW_RPT(pool, count) new(pool, count)
#endif // DEBUG_GDS_ALLOC
@ -159,6 +159,8 @@ private:
class MemoryPool
{
friend class ExternalMemoryHandler;
private:
MemPool* pool;
@ -174,6 +176,7 @@ public:
enum RecommendedBufferSize { MAX_MEDIUM_BLOCK_SIZE = 64384 }; // MediumLimits::TOP_LIMIT - 128
static MemoryPool* defaultMemoryManager;
static MemoryPool* externalMemoryManager;
public:
// Create memory pool instance
@ -193,14 +196,10 @@ public:
void* calloc(size_t size ALLOC_PARAMS);
#ifdef LIBC_CALLS_NEW
static void* globalAlloc(size_t s ALLOC_PARAMS);
#else
static void* globalAlloc(size_t s ALLOC_PARAMS)
{
return defaultMemoryManager->allocate(s ALLOC_PASS_ARGS);
}
#endif // LIBC_CALLS_NEW
void* allocate(size_t size ALLOC_PARAMS);
@ -218,8 +217,8 @@ public:
void setStatsGroup(MemoryStats& stats) noexcept;
// Initialize and finalize global memory pool
static void init();
static void cleanup();
static void initDefaultPool();
static void cleanupDefaultPool();
// Initialize context pool
static void contextPoolInit();
@ -282,6 +281,8 @@ private:
friend class MemPool;
};
void initExternalMemoryPool();
} // namespace Firebird
static inline Firebird::MemoryPool* getDefaultMemoryPool() noexcept
@ -290,6 +291,16 @@ static inline Firebird::MemoryPool* getDefaultMemoryPool() noexcept
return Firebird::MemoryPool::defaultMemoryManager;
}
static inline Firebird::MemoryPool* getExternalMemoryPool() noexcept
{
using namespace Firebird;
if (!MemoryPool::externalMemoryManager)
initExternalMemoryPool();
return MemoryPool::externalMemoryManager;
}
namespace Firebird {
// Class intended to manage execution context pool stack
@ -341,16 +352,12 @@ private:
using Firebird::MemoryPool;
// operators new and delete
extern void* operator new(size_t s ALLOC_PARAMS);
extern void* operator new[](size_t s ALLOC_PARAMS);
extern void operator delete(void* mem ALLOC_PARAMS) noexcept;
extern void operator delete[](void* mem ALLOC_PARAMS) noexcept;
inline void* operator new(size_t s, Firebird::MemoryPool& pool ALLOC_PARAMS)
{
return pool.allocate(s ALLOC_PASS_ARGS);
}
inline void* operator new[](size_t s, Firebird::MemoryPool& pool ALLOC_PARAMS)
{
return pool.allocate(s ALLOC_PASS_ARGS);
@ -360,6 +367,7 @@ inline void operator delete(void* mem, Firebird::MemoryPool& pool ALLOC_PARAMS)
{
MemoryPool::globalFree(mem);
}
inline void operator delete[](void* mem, Firebird::MemoryPool& pool ALLOC_PARAMS) noexcept
{
MemoryPool::globalFree(mem);
@ -370,6 +378,7 @@ inline void operator delete(void* mem, std::size_t s ALLOC_PARAMS) noexcept
{
MemoryPool::globalFree(mem);
}
inline void operator delete[](void* mem, std::size_t s ALLOC_PARAMS) noexcept
{
MemoryPool::globalFree(mem);
@ -390,16 +399,6 @@ namespace Firebird
class GlobalStorage
{
public:
void* operator new(size_t size ALLOC_PARAMS)
{
return getDefaultMemoryPool()->allocate(size ALLOC_PASS_ARGS);
}
void operator delete(void* mem)
{
getDefaultMemoryPool()->deallocate(mem);
}
MemoryPool& getPool() const
{
return *getDefaultMemoryPool();

View File

@ -31,12 +31,13 @@
#include "../common/dllinst.h"
#include "../common/os/os_utils.h"
#ifdef HAVE_DLADDR
#ifndef _GNU_SOURCE
#define _GNU_SOURCE
#ifdef WIN_NT
#include <windows.h>
#ifndef PATH_MAX
#define PATH_MAX MAX_PATH
#endif
#endif
#include <dlfcn.h>
#endif // HAVE_DLADDR
// Setting this define helps (with AV at exit time) detect globals
// with destructors, declared not using InstanceControl.
@ -96,36 +97,14 @@ namespace
Firebird::AutoPtr<FILE> file;
{ // scope
Firebird::PathName name = "memdebug.log";
#ifdef HAVE_DLADDR
Dl_info path;
if (dladdr((void*) &allClean, &path))
{
name = path.dli_fname;
name += ".memdebug.log";
}
else
{
fprintf(stderr, "dladdr: %s\n", dlerror());
}
#elif defined(WIN_NT)
HMODULE hmod = 0;
GetModuleHandleEx(GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS | GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT,
(LPCTSTR) &allClean,
&hmod);
char name[PATH_MAX];
if (hmod)
{
char moduleName[MAX_PATH];
DWORD len = GetModuleFileName(hmod, moduleName, MAX_PATH);
if (len < MAX_PATH)
{
name = moduleName;
name += ".memdebug.log";
}
}
#endif // HAVE_DLADDR
file = os_utils::fopen(name.c_str(), "w+t");
if (os_utils::getCurrentModulePath(name, sizeof(name)))
strncat(name, ".memdebug.log", sizeof(name) - 1);
else
strcpy(name, "memdebug.log");
file = os_utils::fopen(name, "w+t");
}
#endif // DEBUG_GDS_ALLOC
@ -154,7 +133,7 @@ namespace
file = NULL;
}
#endif
Firebird::MemoryPool::cleanup();
Firebird::MemoryPool::cleanupDefaultPool();
}
catch (...)
{
@ -193,7 +172,7 @@ namespace
}
Firebird::Mutex::initMutexes();
Firebird::MemoryPool::init();
Firebird::MemoryPool::initDefaultPool();
Firebird::StaticMutex::create();
#ifdef DEBUG_INIT

View File

@ -304,12 +304,12 @@ template <typename T>
class StaticInstanceAllocator
{
private:
char buf[sizeof(T) + FB_ALIGNMENT];
alignas(alignof(T)) char buf[sizeof(T)];
public:
T* create()
{
return new((void*) FB_ALIGN(buf, FB_ALIGNMENT)) T();
return new(buf) T();
}
static void destroy(T*)

View File

@ -33,6 +33,7 @@
#include "../../common/classes/locks.h"
#include "../../common/ThreadStart.h"
#include <mutex>
namespace Firebird {
@ -50,15 +51,18 @@ pthread_mutexattr_t Mutex::attr;
void Mutex::initMutexes()
{
// Throw exceptions on errors, but they will not be processed in init
// (first constructor). Better logging facilities are required here.
int rc = pthread_mutexattr_init(&attr);
if (rc < 0)
system_call_failed::raise("pthread_mutexattr_init", rc);
static std::once_flag onceFlag;
std::call_once(onceFlag, [] {
// Throw exceptions on errors, but they will not be processed in init
// (first constructor). Better logging facilities are required here.
int rc = pthread_mutexattr_init(&attr);
if (rc < 0)
system_call_failed::raise("pthread_mutexattr_init", rc);
rc = pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE);
if (rc < 0)
system_call_failed::raise("pthread_mutexattr_settype", rc);
rc = pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE);
if (rc < 0)
system_call_failed::raise("pthread_mutexattr_settype", rc);
});
}
#endif

View File

@ -331,6 +331,13 @@ public:
lock->enter(aReason);
}
RaiiLockGuard(M* aLock, const char* aReason)
: lock(aLock)
{
if (lock)
lock->enter(aReason);
}
~RaiiLockGuard()
{
try

View File

@ -81,6 +81,8 @@ namespace os_utils
bool isIPv6supported();
bool getCurrentModulePath(char* buffer, size_t bufferSize);
// force descriptor to have O_CLOEXEC set
int open(const char* pathname, int flags, mode_t mode = DEFAULT_OPEN_MODE);
void setCloseOnExec(int fd); // posix only

View File

@ -43,6 +43,14 @@
#ifdef HAVE_SYS_STAT_H
#include <sys/stat.h>
#endif
#ifdef HAVE_DLADDR
#ifndef _GNU_SOURCE
#define _GNU_SOURCE
#endif
#include <dlfcn.h>
#endif // HAVE_DLADDR
#ifdef HAVE_FCNTL_H
#include <fcntl.h>
#endif
@ -335,6 +343,21 @@ bool isIPv6supported()
#endif
}
bool getCurrentModulePath(char* buffer, size_t bufferSize)
{
#ifdef HAVE_DLADDR
Dl_info path;
if (dladdr((void*) &getCurrentModulePath, &path))
{
strncpy(buffer, path.dli_fname, bufferSize);
return true;
}
#endif
return false;
}
// setting flag is not absolutely required, therefore ignore errors here
void setCloseOnExec(int fd)
{

View File

@ -380,6 +380,23 @@ bool isIPv6supported()
return false;
}
bool getCurrentModulePath(char* buffer, size_t bufferSize)
{
HMODULE hmod = 0;
GetModuleHandleEx(GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS | GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT,
(LPCTSTR) &getCurrentModulePath,
&hmod);
if (hmod)
{
GetModuleFileName(hmod, buffer, bufferSize);
return true;
}
return false;
}
int open(const char* pathname, int flags, mode_t mode)
{
return ::_open(pathname, flags, mode);

View File

@ -11519,7 +11519,7 @@ void GrantRevokeNode::grantRevoke(thread_db* tdbb, jrd_tra* transaction, const G
const MetaName objName(object ? object->second : "");
bool crdb = false;
AutoPtr<char, ArrayDelete> privileges(new char[MAX(strlen(ALL_PRIVILEGES), strlen(privs ? privs : "")) + 1]);
AutoPtr<char, ArrayDelete> privileges(FB_NEW char[MAX(strlen(ALL_PRIVILEGES), strlen(privs ? privs : "")) + 1]);
strcpy(privileges, privs ? privs : "");
if (strcmp(privileges, "A") == 0)

View File

@ -137,12 +137,8 @@ private:
// Fool-proof requested by Alex
// Private memory operators to be sure that this class is used in heap only with launcher
#ifdef DEBUG_GDS_ALLOC
void* operator new (size_t s, const char* file, int line) { return MemoryPool::globalAlloc(s, file, line); }
void operator delete (void* mem, const char* file, int line) { MemoryPool::globalFree(mem); }
#else
void* operator new (size_t s) { return MemoryPool::globalAlloc(s); }
#endif
void* operator new (size_t s, Firebird::MemoryPool& pool ALLOC_PARAMS) { return pool.allocate(s ALLOC_PASS_ARGS); }
void operator delete (void* mem, Firebird::MemoryPool& ALLOC_PARAMS) { MemoryPool::globalFree(mem); }
void operator delete (void* mem) { MemoryPool::globalFree(mem); }
public: