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

Introduce the external memory pool.

Standard new operator will alloc memory from the external pool.

FB_NEW will alloc memory from the default pool.

The difference of the external pool to the default pool is that
the external pool is only freed during unload when there is no
memory allocated from it.

If the external pool destructor is called before objects that
allocated memory from it, it's placed in special DYING state.

When in DYING state its desallocation is deferred to the moment
the last memory allocated is freed from it.
This commit is contained in:
Adriano dos Santos Fernandes 2021-10-05 11:24:08 -03:00
parent 21307a7bf8
commit ab42db972a
11 changed files with 359 additions and 170 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

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

@ -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: