mirror of
https://github.com/FirebirdSQL/firebird.git
synced 2025-02-02 10:00:38 +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:
parent
21307a7bf8
commit
ab42db972a
@ -21,7 +21,7 @@
|
|||||||
# Notes:
|
# Notes:
|
||||||
|
|
||||||
# Firebird requires the HP-UX Atomic APIs ("AtomicAPI" bundle), released as an
|
# 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
|
# Before attempting the HPUX build, you must export necessary
|
||||||
# CFLAGS and CXXFLAGS to be picked up by the configure process and
|
# 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...
|
# Flags specific to production or debug build...
|
||||||
# -z, disallow dereferencing of null pointers at runtime
|
# -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)
|
ifeq ($(shell uname -m),ia64)
|
||||||
# ...for IA-64
|
# ...for IA-64
|
||||||
PROD_FLAGS= +O2 +Onolimit +Ofltacc=strict +Ofenvaccess \
|
PROD_FLAGS= +O2 +Onolimit +Ofltacc=strict +Ofenvaccess \
|
||||||
$(COMMON_FLAGS)
|
$(COMMON_FLAGS)
|
||||||
DEV_FLAGS= -g -z -DLIBC_CALLS_NEW \
|
DEV_FLAGS= -g -z \
|
||||||
$(COMMON_FLAGS)
|
$(COMMON_FLAGS)
|
||||||
else
|
else
|
||||||
# ...for PA-RISC
|
# ...for PA-RISC
|
||||||
|
@ -40,12 +40,22 @@
|
|||||||
#include "firebird.h"
|
#include "firebird.h"
|
||||||
#include "../common/classes/alloc.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 <unistd.h>
|
||||||
#include <sys/types.h>
|
#include <sys/types.h>
|
||||||
#include <sys/stat.h>
|
#include <sys/stat.h>
|
||||||
#include <fcntl.h>
|
#include <fcntl.h>
|
||||||
#include <sys/mman.h>
|
#include <sys/mman.h>
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include "../common/classes/fb_tls.h"
|
#include "../common/classes/fb_tls.h"
|
||||||
@ -68,25 +78,10 @@
|
|||||||
#define VALGRIND_FIX_IT // overrides suspicious valgrind behavior
|
#define VALGRIND_FIX_IT // overrides suspicious valgrind behavior
|
||||||
#endif // USE_VALGRIND
|
#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 {
|
namespace {
|
||||||
|
|
||||||
|
///#define MEM_DEBUG_EXTERNAL
|
||||||
|
|
||||||
/*** emergency debugging stuff
|
/*** emergency debugging stuff
|
||||||
static const char* lastFileName;
|
static const char* lastFileName;
|
||||||
static int lastLine;
|
static int lastLine;
|
||||||
@ -147,7 +142,14 @@ typedef Firebird::AtomicCounter::counter_type StatInt;
|
|||||||
const int MAP_CACHE_SIZE = 16; // == 1 MB
|
const int MAP_CACHE_SIZE = 16; // == 1 MB
|
||||||
const size_t DEFAULT_ALLOCATION = 65536;
|
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
|
#ifndef WIN_NT
|
||||||
struct FailedBlock
|
struct FailedBlock
|
||||||
@ -191,7 +193,7 @@ inline size_t get_map_page_size()
|
|||||||
static volatile size_t map_page_size = 0;
|
static volatile size_t map_page_size = 0;
|
||||||
if (!map_page_size)
|
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)
|
if (!map_page_size)
|
||||||
map_page_size = get_page_size();
|
map_page_size = get_page_size();
|
||||||
}
|
}
|
||||||
@ -1731,10 +1733,22 @@ private:
|
|||||||
public:
|
public:
|
||||||
static MemPool* defaultMemPool;
|
static MemPool* defaultMemPool;
|
||||||
|
|
||||||
MemPool();
|
MemPool(MemoryStats& stats, ExtentsCache* extentsCache);
|
||||||
MemPool(MemPool& parent, MemoryStats& stats);
|
MemPool(MemPool& parent, MemoryStats& stats, ExtentsCache* extentsCache);
|
||||||
virtual ~MemPool(void);
|
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:
|
private:
|
||||||
static const size_t minAllocation = 65536;
|
static const size_t minAllocation = 65536;
|
||||||
static const size_t roundingSize = ALLOC_ALIGNMENT;
|
static const size_t roundingSize = ALLOC_ALIGNMENT;
|
||||||
@ -1749,12 +1763,10 @@ private:
|
|||||||
int blocksActive;
|
int blocksActive;
|
||||||
bool pool_destroying, parent_redirect;
|
bool pool_destroying, parent_redirect;
|
||||||
|
|
||||||
// Statistics group for the pool
|
MemoryStats* stats; // Statistics group for the pool
|
||||||
MemoryStats* stats;
|
MemPool* parent; // Parent pool if present
|
||||||
// Parent pool if present
|
ExtentsCache* extentsCache;
|
||||||
MemPool* parent;
|
AtomicCounter used_memory, mapped_memory; // Memory used
|
||||||
// Memory used
|
|
||||||
AtomicCounter used_memory, mapped_memory;
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
@ -1810,7 +1822,7 @@ private:
|
|||||||
virtual void memoryIsExhausted(void);
|
virtual void memoryIsExhausted(void);
|
||||||
void* allocRaw(size_t length);
|
void* allocRaw(size_t length);
|
||||||
static void releaseMemory(void* block, bool flagExtent) noexcept;
|
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);
|
void* getExtent(size_t from, size_t& to);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
@ -1843,23 +1855,36 @@ public:
|
|||||||
void setStatsGroup(MemoryStats& stats) noexcept;
|
void setStatsGroup(MemoryStats& stats) noexcept;
|
||||||
|
|
||||||
// Initialize and finalize global memory pool
|
// Initialize and finalize global memory pool
|
||||||
static MemPool* init()
|
static MemPool* initDefaultPool()
|
||||||
{
|
{
|
||||||
fb_assert(!defaultMemPool);
|
fb_assert(!defaultMemPool);
|
||||||
|
|
||||||
static char mpBuffer[sizeof(MemPool) + ALLOC_ALIGNMENT];
|
alignas(alignof(MemPool)) static char mpBuffer[sizeof(MemPool)];
|
||||||
defaultMemPool = new((void*)(IPTR) MEM_ALIGN((size_t)(IPTR) mpBuffer)) MemPool();
|
defaultMemPool = new(mpBuffer) MemPool(*MemoryPool::default_stats_group, &defaultExtentsCache);
|
||||||
return defaultMemPool;
|
return defaultMemPool;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void cleanup()
|
static void cleanupDefaultPool()
|
||||||
{
|
{
|
||||||
defaultMemPool->~MemPool();
|
defaultMemPool->~MemPool();
|
||||||
defaultMemPool = NULL;
|
defaultMemPool = NULL;
|
||||||
|
|
||||||
while (extents_cache.getCount())
|
while (defaultExtentsCache.count)
|
||||||
releaseRaw(true, extents_cache.pop(), DEFAULT_ALLOCATION, false);
|
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
|
#ifndef WIN_NT
|
||||||
unsigned oldCount = 0;
|
unsigned oldCount = 0;
|
||||||
|
|
||||||
@ -1880,7 +1905,7 @@ public:
|
|||||||
++newCount;
|
++newCount;
|
||||||
FailedBlock* fb = oldList;
|
FailedBlock* fb = oldList;
|
||||||
SemiDoubleLink::pop(oldList);
|
SemiDoubleLink::pop(oldList);
|
||||||
releaseRaw(true, fb, fb->blockSize, false);
|
releaseRaw(true, fb, fb->blockSize, nullptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (newCount == oldCount)
|
if (newCount == oldCount)
|
||||||
@ -1889,7 +1914,6 @@ public:
|
|||||||
oldCount = newCount;
|
oldCount = newCount;
|
||||||
}
|
}
|
||||||
#endif // WIN_NT
|
#endif // WIN_NT
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Statistics
|
// Statistics
|
||||||
@ -2012,28 +2036,28 @@ GlobalPtr<Mutex> forceCreationOfDefaultMemoryPool;
|
|||||||
|
|
||||||
MemoryPool* MemoryPool::defaultMemoryManager = NULL;
|
MemoryPool* MemoryPool::defaultMemoryManager = NULL;
|
||||||
MemoryStats* MemoryPool::default_stats_group = NULL;
|
MemoryStats* MemoryPool::default_stats_group = NULL;
|
||||||
|
MemoryPool* MemoryPool::externalMemoryManager = NULL;
|
||||||
MemPool* MemPool::defaultMemPool = NULL;
|
MemPool* MemPool::defaultMemPool = NULL;
|
||||||
|
|
||||||
|
|
||||||
// Initialize process memory pool (called from InstanceControl).
|
// Initialize process memory pool (called from InstanceControl).
|
||||||
|
|
||||||
void MemoryPool::init()
|
void MemoryPool::initDefaultPool()
|
||||||
{
|
{
|
||||||
static char mtxBuffer[sizeof(Mutex) + ALLOC_ALIGNMENT];
|
alignas(alignof(Mutex)) static char mtxBuffer[sizeof(Mutex)];
|
||||||
cache_mutex = new((void*)(IPTR) MEM_ALIGN((size_t)(IPTR) mtxBuffer)) Mutex;
|
cache_mutex = new(mtxBuffer) Mutex;
|
||||||
|
|
||||||
static char msBuffer[sizeof(MemoryStats) + ALLOC_ALIGNMENT];
|
alignas(alignof(MemoryStats)) static char msBuffer[sizeof(MemoryStats)];
|
||||||
default_stats_group =
|
default_stats_group = new(msBuffer) MemoryStats;
|
||||||
new((void*)(IPTR) MEM_ALIGN((size_t)(IPTR) msBuffer)) MemoryStats;
|
|
||||||
|
|
||||||
static char mpBuffer[sizeof(MemoryPool) + ALLOC_ALIGNMENT];
|
alignas(alignof(MemoryPool)) static char mpBuffer[sizeof(MemoryPool)];
|
||||||
defaultMemoryManager = new((void*)(IPTR) MEM_ALIGN((size_t)(IPTR) mpBuffer)) MemoryPool(MemPool::init());
|
defaultMemoryManager = new(mpBuffer) MemoryPool(MemPool::initDefaultPool());
|
||||||
}
|
}
|
||||||
|
|
||||||
// Should be last routine, called by InstanceControl,
|
// Should be last routine, called by InstanceControl,
|
||||||
// being therefore the very last routine in firebird module.
|
// being therefore the very last routine in firebird module.
|
||||||
|
|
||||||
void MemoryPool::cleanup()
|
void MemoryPool::cleanupDefaultPool()
|
||||||
{
|
{
|
||||||
#ifdef VALGRIND_FIX_IT
|
#ifdef VALGRIND_FIX_IT
|
||||||
VALGRIND_DISCARD(
|
VALGRIND_DISCARD(
|
||||||
@ -2047,7 +2071,7 @@ void MemoryPool::cleanup()
|
|||||||
if (defaultMemoryManager)
|
if (defaultMemoryManager)
|
||||||
{
|
{
|
||||||
//defaultMemoryManager->~MemoryPool();
|
//defaultMemoryManager->~MemoryPool();
|
||||||
MemPool::cleanup();
|
MemPool::cleanupDefaultPool();
|
||||||
defaultMemoryManager = NULL;
|
defaultMemoryManager = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2065,15 +2089,23 @@ void MemoryPool::cleanup()
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
MemPool::MemPool()
|
MemPool::MemPool(MemoryStats& s, ExtentsCache* cache)
|
||||||
: pool_destroying(false), parent_redirect(false), stats(MemoryPool::default_stats_group), parent(NULL)
|
: pool_destroying(false),
|
||||||
|
parent_redirect(false),
|
||||||
|
stats(&s),
|
||||||
|
parent(NULL),
|
||||||
|
extentsCache(cache)
|
||||||
{
|
{
|
||||||
fb_assert(offsetof(MemBlock, body) == MEM_ALIGN(offsetof(MemBlock, body)));
|
fb_assert(offsetof(MemBlock, body) == MEM_ALIGN(offsetof(MemBlock, body)));
|
||||||
initialize();
|
initialize();
|
||||||
}
|
}
|
||||||
|
|
||||||
MemPool::MemPool(MemPool& p, MemoryStats& s)
|
MemPool::MemPool(MemPool& p, MemoryStats& s, ExtentsCache* cache)
|
||||||
: pool_destroying(false), parent_redirect(true), stats(&s), parent(&p)
|
: pool_destroying(false),
|
||||||
|
parent_redirect(true),
|
||||||
|
stats(&s),
|
||||||
|
parent(&p),
|
||||||
|
extentsCache(cache)
|
||||||
{
|
{
|
||||||
initialize();
|
initialize();
|
||||||
}
|
}
|
||||||
@ -2133,7 +2165,7 @@ MemPool::~MemPool(void)
|
|||||||
{
|
{
|
||||||
MemBigHunk* hunk = bigHunks;
|
MemBigHunk* hunk = bigHunks;
|
||||||
bigHunks = hunk->next;
|
bigHunks = hunk->next;
|
||||||
releaseRaw(pool_destroying, hunk, hunk->length);
|
releaseRaw(pool_destroying, hunk, hunk->length, extentsCache);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (parent)
|
if (parent)
|
||||||
@ -2210,7 +2242,7 @@ MemoryPool* MemoryPool::createPool(MemoryPool* parentPool, MemoryStats& stats)
|
|||||||
if (!parentPool)
|
if (!parentPool)
|
||||||
parentPool = getDefaultMemoryPool();
|
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);
|
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());
|
MemBigHunk* hunk = (MemBigHunk*)(((UCHAR*)block) - MemBigHunk::hdrSize());
|
||||||
SemiDoubleLink::remove(hunk);
|
SemiDoubleLink::remove(hunk);
|
||||||
decrement_mapping(FB_ALIGN(hunk->length, get_map_page_size()));
|
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)
|
void MemPool::memoryIsExhausted(void)
|
||||||
@ -2474,12 +2506,12 @@ void* MemPool::allocRaw(size_t size)
|
|||||||
#ifndef USE_VALGRIND
|
#ifndef USE_VALGRIND
|
||||||
if (size == DEFAULT_ALLOCATION)
|
if (size == DEFAULT_ALLOCATION)
|
||||||
{
|
{
|
||||||
MutexLockGuard guard(*cache_mutex, "MemPool::allocRaw");
|
MutexLockGuard guard(cache_mutex, "MemPool::allocRaw");
|
||||||
if (extents_cache.hasData())
|
if (extentsCache->count)
|
||||||
{
|
{
|
||||||
// Use most recently used object to encourage caching
|
// Use most recently used object to encourage caching
|
||||||
increment_mapping(size);
|
increment_mapping(size);
|
||||||
return extents_cache.pop();
|
return extentsCache->data[--extentsCache->count];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
@ -2497,7 +2529,7 @@ void* MemPool::allocRaw(size_t size)
|
|||||||
void* result = NULL;
|
void* result = NULL;
|
||||||
if (failedList)
|
if (failedList)
|
||||||
{
|
{
|
||||||
MutexLockGuard guard(*cache_mutex, "MemPool::allocRaw");
|
MutexLockGuard guard(cache_mutex, "MemPool::allocRaw");
|
||||||
for (FailedBlock* fb = failedList; fb; fb = fb->next)
|
for (FailedBlock* fb = failedList; fb; fb = fb->next)
|
||||||
{
|
{
|
||||||
if (fb->blockSize == size)
|
if (fb->blockSize == size)
|
||||||
@ -2568,20 +2600,20 @@ void MemPool::releaseExtent(bool destroying, void* block, size_t size, MemPool*
|
|||||||
{
|
{
|
||||||
if (pool)
|
if (pool)
|
||||||
pool->decrement_mapping(size);
|
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
|
#ifndef USE_VALGRIND
|
||||||
if (use_cache && (size == DEFAULT_ALLOCATION))
|
if (extentsCache && (size == DEFAULT_ALLOCATION))
|
||||||
{
|
{
|
||||||
MutexLockGuard guard(*cache_mutex, "MemPool::releaseRaw");
|
MutexLockGuard guard(cache_mutex, "MemPool::releaseRaw");
|
||||||
if (extents_cache.getCount() < extents_cache.getCapacity())
|
if (extentsCache->count < MAP_CACHE_SIZE)
|
||||||
{
|
{
|
||||||
extents_cache.push(block);
|
extentsCache->data[extentsCache->count++] = block;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -2599,7 +2631,7 @@ void MemPool::releaseRaw(bool destroying, void* block, size_t size, bool use_cac
|
|||||||
if (destroying)
|
if (destroying)
|
||||||
{
|
{
|
||||||
// Synchronize delayed free queue using extents mutex
|
// Synchronize delayed free queue using extents mutex
|
||||||
MutexLockGuard guard(*cache_mutex, "MemPool::releaseRaw");
|
MutexLockGuard guard(cache_mutex, "MemPool::releaseRaw");
|
||||||
|
|
||||||
// Extend circular buffer if possible
|
// Extend circular buffer if possible
|
||||||
if (delayedExtentCount < FB_NELEM(delayedExtents))
|
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;
|
FailedBlock* failed = (FailedBlock*) block;
|
||||||
failed->blockSize = size;
|
failed->blockSize = size;
|
||||||
|
|
||||||
MutexLockGuard guard(*cache_mutex, "MemPool::releaseRaw");
|
MutexLockGuard guard(cache_mutex, "MemPool::releaseRaw");
|
||||||
SemiDoubleLink::push(&failedList, failed);
|
SemiDoubleLink::push(&failedList, failed);
|
||||||
|
|
||||||
return;
|
return;
|
||||||
@ -2817,25 +2849,6 @@ MemoryPool& AutoStorage::getAutoMemoryPool()
|
|||||||
return *p;
|
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)
|
void* MemoryPool::allocate(size_t size ALLOC_PARAMS)
|
||||||
{
|
{
|
||||||
return pool->allocate(size ALLOC_PASS_ARGS);
|
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)
|
#if defined(DEV_BUILD)
|
||||||
void AutoStorage::ProbeStack() const
|
void AutoStorage::ProbeStack() const
|
||||||
{
|
{
|
||||||
@ -2949,14 +3115,15 @@ void AutoStorage::ProbeStack() const
|
|||||||
// Global operator "delete" is always redefined by firebird,
|
// Global operator "delete" is always redefined by firebird,
|
||||||
// in a case when we actually need "new" only with file/line information
|
// in a case when we actually need "new" only with file/line information
|
||||||
// this version should be also present as a pair for "delete".
|
// this version should be also present as a pair for "delete".
|
||||||
#ifdef DEBUG_GDS_ALLOC
|
|
||||||
void* operator new(size_t s)
|
void* operator new(size_t s)
|
||||||
{
|
{
|
||||||
return MemoryPool::globalAlloc(s ALLOC_ARGS);
|
return getExternalMemoryPool()->allocate(s ALLOC_ARGS);
|
||||||
}
|
}
|
||||||
|
|
||||||
void* operator new[](size_t s)
|
void* operator new[](size_t s)
|
||||||
{
|
{
|
||||||
return MemoryPool::globalAlloc(s ALLOC_ARGS);
|
return getExternalMemoryPool()->allocate(s ALLOC_ARGS);
|
||||||
}
|
}
|
||||||
|
|
||||||
void operator delete(void* mem) noexcept
|
void operator delete(void* mem) noexcept
|
||||||
@ -2968,5 +3135,3 @@ void operator delete[](void* mem) noexcept
|
|||||||
{
|
{
|
||||||
MemoryPool::globalFree(mem);
|
MemoryPool::globalFree(mem);
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif // DEBUG_GDS_ALLOC
|
|
||||||
|
@ -59,11 +59,11 @@
|
|||||||
#include <memory.h>
|
#include <memory.h>
|
||||||
|
|
||||||
#ifdef DEBUG_GDS_ALLOC
|
#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_POOL(pool) new(pool, __FILE__, __LINE__)
|
||||||
#define FB_NEW_RPT(pool, count) new(pool, count, __FILE__, __LINE__)
|
#define FB_NEW_RPT(pool, count) new(pool, count, __FILE__, __LINE__)
|
||||||
#else // DEBUG_GDS_ALLOC
|
#else // DEBUG_GDS_ALLOC
|
||||||
#define FB_NEW new
|
#define FB_NEW new(*getDefaultMemoryPool())
|
||||||
#define FB_NEW_POOL(pool) new(pool)
|
#define FB_NEW_POOL(pool) new(pool)
|
||||||
#define FB_NEW_RPT(pool, count) new(pool, count)
|
#define FB_NEW_RPT(pool, count) new(pool, count)
|
||||||
#endif // DEBUG_GDS_ALLOC
|
#endif // DEBUG_GDS_ALLOC
|
||||||
@ -159,6 +159,8 @@ private:
|
|||||||
|
|
||||||
class MemoryPool
|
class MemoryPool
|
||||||
{
|
{
|
||||||
|
friend class ExternalMemoryHandler;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
MemPool* pool;
|
MemPool* pool;
|
||||||
|
|
||||||
@ -174,6 +176,7 @@ public:
|
|||||||
enum RecommendedBufferSize { MAX_MEDIUM_BLOCK_SIZE = 64384 }; // MediumLimits::TOP_LIMIT - 128
|
enum RecommendedBufferSize { MAX_MEDIUM_BLOCK_SIZE = 64384 }; // MediumLimits::TOP_LIMIT - 128
|
||||||
|
|
||||||
static MemoryPool* defaultMemoryManager;
|
static MemoryPool* defaultMemoryManager;
|
||||||
|
static MemoryPool* externalMemoryManager;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
// Create memory pool instance
|
// Create memory pool instance
|
||||||
@ -193,14 +196,10 @@ public:
|
|||||||
|
|
||||||
void* calloc(size_t size ALLOC_PARAMS);
|
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)
|
static void* globalAlloc(size_t s ALLOC_PARAMS)
|
||||||
{
|
{
|
||||||
return defaultMemoryManager->allocate(s ALLOC_PASS_ARGS);
|
return defaultMemoryManager->allocate(s ALLOC_PASS_ARGS);
|
||||||
}
|
}
|
||||||
#endif // LIBC_CALLS_NEW
|
|
||||||
|
|
||||||
void* allocate(size_t size ALLOC_PARAMS);
|
void* allocate(size_t size ALLOC_PARAMS);
|
||||||
|
|
||||||
@ -218,8 +217,8 @@ public:
|
|||||||
void setStatsGroup(MemoryStats& stats) noexcept;
|
void setStatsGroup(MemoryStats& stats) noexcept;
|
||||||
|
|
||||||
// Initialize and finalize global memory pool
|
// Initialize and finalize global memory pool
|
||||||
static void init();
|
static void initDefaultPool();
|
||||||
static void cleanup();
|
static void cleanupDefaultPool();
|
||||||
|
|
||||||
// Initialize context pool
|
// Initialize context pool
|
||||||
static void contextPoolInit();
|
static void contextPoolInit();
|
||||||
@ -282,6 +281,8 @@ private:
|
|||||||
friend class MemPool;
|
friend class MemPool;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
void initExternalMemoryPool();
|
||||||
|
|
||||||
} // namespace Firebird
|
} // namespace Firebird
|
||||||
|
|
||||||
static inline Firebird::MemoryPool* getDefaultMemoryPool() noexcept
|
static inline Firebird::MemoryPool* getDefaultMemoryPool() noexcept
|
||||||
@ -290,6 +291,16 @@ static inline Firebird::MemoryPool* getDefaultMemoryPool() noexcept
|
|||||||
return Firebird::MemoryPool::defaultMemoryManager;
|
return Firebird::MemoryPool::defaultMemoryManager;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static inline Firebird::MemoryPool* getExternalMemoryPool() noexcept
|
||||||
|
{
|
||||||
|
using namespace Firebird;
|
||||||
|
|
||||||
|
if (!MemoryPool::externalMemoryManager)
|
||||||
|
initExternalMemoryPool();
|
||||||
|
|
||||||
|
return MemoryPool::externalMemoryManager;
|
||||||
|
}
|
||||||
|
|
||||||
namespace Firebird {
|
namespace Firebird {
|
||||||
|
|
||||||
// Class intended to manage execution context pool stack
|
// Class intended to manage execution context pool stack
|
||||||
@ -341,16 +352,12 @@ private:
|
|||||||
using Firebird::MemoryPool;
|
using Firebird::MemoryPool;
|
||||||
|
|
||||||
// operators new and delete
|
// 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)
|
inline void* operator new(size_t s, Firebird::MemoryPool& pool ALLOC_PARAMS)
|
||||||
{
|
{
|
||||||
return pool.allocate(s ALLOC_PASS_ARGS);
|
return pool.allocate(s ALLOC_PASS_ARGS);
|
||||||
}
|
}
|
||||||
|
|
||||||
inline void* operator new[](size_t s, Firebird::MemoryPool& pool ALLOC_PARAMS)
|
inline void* operator new[](size_t s, Firebird::MemoryPool& pool ALLOC_PARAMS)
|
||||||
{
|
{
|
||||||
return pool.allocate(s ALLOC_PASS_ARGS);
|
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);
|
MemoryPool::globalFree(mem);
|
||||||
}
|
}
|
||||||
|
|
||||||
inline void operator delete[](void* mem, Firebird::MemoryPool& pool ALLOC_PARAMS) noexcept
|
inline void operator delete[](void* mem, Firebird::MemoryPool& pool ALLOC_PARAMS) noexcept
|
||||||
{
|
{
|
||||||
MemoryPool::globalFree(mem);
|
MemoryPool::globalFree(mem);
|
||||||
@ -370,6 +378,7 @@ inline void operator delete(void* mem, std::size_t s ALLOC_PARAMS) noexcept
|
|||||||
{
|
{
|
||||||
MemoryPool::globalFree(mem);
|
MemoryPool::globalFree(mem);
|
||||||
}
|
}
|
||||||
|
|
||||||
inline void operator delete[](void* mem, std::size_t s ALLOC_PARAMS) noexcept
|
inline void operator delete[](void* mem, std::size_t s ALLOC_PARAMS) noexcept
|
||||||
{
|
{
|
||||||
MemoryPool::globalFree(mem);
|
MemoryPool::globalFree(mem);
|
||||||
@ -390,16 +399,6 @@ namespace Firebird
|
|||||||
class GlobalStorage
|
class GlobalStorage
|
||||||
{
|
{
|
||||||
public:
|
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
|
MemoryPool& getPool() const
|
||||||
{
|
{
|
||||||
return *getDefaultMemoryPool();
|
return *getDefaultMemoryPool();
|
||||||
|
@ -31,12 +31,13 @@
|
|||||||
#include "../common/dllinst.h"
|
#include "../common/dllinst.h"
|
||||||
#include "../common/os/os_utils.h"
|
#include "../common/os/os_utils.h"
|
||||||
|
|
||||||
#ifdef HAVE_DLADDR
|
#ifdef WIN_NT
|
||||||
#ifndef _GNU_SOURCE
|
#include <windows.h>
|
||||||
#define _GNU_SOURCE
|
|
||||||
|
#ifndef PATH_MAX
|
||||||
|
#define PATH_MAX MAX_PATH
|
||||||
|
#endif
|
||||||
#endif
|
#endif
|
||||||
#include <dlfcn.h>
|
|
||||||
#endif // HAVE_DLADDR
|
|
||||||
|
|
||||||
// Setting this define helps (with AV at exit time) detect globals
|
// Setting this define helps (with AV at exit time) detect globals
|
||||||
// with destructors, declared not using InstanceControl.
|
// with destructors, declared not using InstanceControl.
|
||||||
@ -96,36 +97,14 @@ namespace
|
|||||||
Firebird::AutoPtr<FILE> file;
|
Firebird::AutoPtr<FILE> file;
|
||||||
|
|
||||||
{ // scope
|
{ // scope
|
||||||
Firebird::PathName name = "memdebug.log";
|
char name[PATH_MAX];
|
||||||
#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);
|
|
||||||
|
|
||||||
if (hmod)
|
if (os_utils::getCurrentModulePath(name, sizeof(name)))
|
||||||
{
|
strncat(name, ".memdebug.log", sizeof(name) - 1);
|
||||||
char moduleName[MAX_PATH];
|
else
|
||||||
DWORD len = GetModuleFileName(hmod, moduleName, MAX_PATH);
|
strcpy(name, "memdebug.log");
|
||||||
if (len < MAX_PATH)
|
|
||||||
{
|
file = os_utils::fopen(name, "w+t");
|
||||||
name = moduleName;
|
|
||||||
name += ".memdebug.log";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#endif // HAVE_DLADDR
|
|
||||||
file = os_utils::fopen(name.c_str(), "w+t");
|
|
||||||
}
|
}
|
||||||
#endif // DEBUG_GDS_ALLOC
|
#endif // DEBUG_GDS_ALLOC
|
||||||
|
|
||||||
@ -154,7 +133,7 @@ namespace
|
|||||||
file = NULL;
|
file = NULL;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
Firebird::MemoryPool::cleanup();
|
Firebird::MemoryPool::cleanupDefaultPool();
|
||||||
}
|
}
|
||||||
catch (...)
|
catch (...)
|
||||||
{
|
{
|
||||||
@ -193,7 +172,7 @@ namespace
|
|||||||
}
|
}
|
||||||
|
|
||||||
Firebird::Mutex::initMutexes();
|
Firebird::Mutex::initMutexes();
|
||||||
Firebird::MemoryPool::init();
|
Firebird::MemoryPool::initDefaultPool();
|
||||||
Firebird::StaticMutex::create();
|
Firebird::StaticMutex::create();
|
||||||
|
|
||||||
#ifdef DEBUG_INIT
|
#ifdef DEBUG_INIT
|
||||||
|
@ -304,12 +304,12 @@ template <typename T>
|
|||||||
class StaticInstanceAllocator
|
class StaticInstanceAllocator
|
||||||
{
|
{
|
||||||
private:
|
private:
|
||||||
char buf[sizeof(T) + FB_ALIGNMENT];
|
alignas(alignof(T)) char buf[sizeof(T)];
|
||||||
|
|
||||||
public:
|
public:
|
||||||
T* create()
|
T* create()
|
||||||
{
|
{
|
||||||
return new((void*) FB_ALIGN(buf, FB_ALIGNMENT)) T();
|
return new(buf) T();
|
||||||
}
|
}
|
||||||
|
|
||||||
static void destroy(T*)
|
static void destroy(T*)
|
||||||
|
@ -33,6 +33,7 @@
|
|||||||
|
|
||||||
#include "../../common/classes/locks.h"
|
#include "../../common/classes/locks.h"
|
||||||
#include "../../common/ThreadStart.h"
|
#include "../../common/ThreadStart.h"
|
||||||
|
#include <mutex>
|
||||||
|
|
||||||
|
|
||||||
namespace Firebird {
|
namespace Firebird {
|
||||||
@ -50,15 +51,18 @@ pthread_mutexattr_t Mutex::attr;
|
|||||||
|
|
||||||
void Mutex::initMutexes()
|
void Mutex::initMutexes()
|
||||||
{
|
{
|
||||||
// Throw exceptions on errors, but they will not be processed in init
|
static std::once_flag onceFlag;
|
||||||
// (first constructor). Better logging facilities are required here.
|
std::call_once(onceFlag, [] {
|
||||||
int rc = pthread_mutexattr_init(&attr);
|
// Throw exceptions on errors, but they will not be processed in init
|
||||||
if (rc < 0)
|
// (first constructor). Better logging facilities are required here.
|
||||||
system_call_failed::raise("pthread_mutexattr_init", rc);
|
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);
|
rc = pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE);
|
||||||
if (rc < 0)
|
if (rc < 0)
|
||||||
system_call_failed::raise("pthread_mutexattr_settype", rc);
|
system_call_failed::raise("pthread_mutexattr_settype", rc);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@ -331,6 +331,13 @@ public:
|
|||||||
lock->enter(aReason);
|
lock->enter(aReason);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
RaiiLockGuard(M* aLock, const char* aReason)
|
||||||
|
: lock(aLock)
|
||||||
|
{
|
||||||
|
if (lock)
|
||||||
|
lock->enter(aReason);
|
||||||
|
}
|
||||||
|
|
||||||
~RaiiLockGuard()
|
~RaiiLockGuard()
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
|
@ -81,6 +81,8 @@ namespace os_utils
|
|||||||
|
|
||||||
bool isIPv6supported();
|
bool isIPv6supported();
|
||||||
|
|
||||||
|
bool getCurrentModulePath(char* buffer, size_t bufferSize);
|
||||||
|
|
||||||
// force descriptor to have O_CLOEXEC set
|
// force descriptor to have O_CLOEXEC set
|
||||||
int open(const char* pathname, int flags, mode_t mode = DEFAULT_OPEN_MODE);
|
int open(const char* pathname, int flags, mode_t mode = DEFAULT_OPEN_MODE);
|
||||||
void setCloseOnExec(int fd); // posix only
|
void setCloseOnExec(int fd); // posix only
|
||||||
|
@ -43,6 +43,14 @@
|
|||||||
#ifdef HAVE_SYS_STAT_H
|
#ifdef HAVE_SYS_STAT_H
|
||||||
#include <sys/stat.h>
|
#include <sys/stat.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifdef HAVE_DLADDR
|
||||||
|
#ifndef _GNU_SOURCE
|
||||||
|
#define _GNU_SOURCE
|
||||||
|
#endif
|
||||||
|
#include <dlfcn.h>
|
||||||
|
#endif // HAVE_DLADDR
|
||||||
|
|
||||||
#ifdef HAVE_FCNTL_H
|
#ifdef HAVE_FCNTL_H
|
||||||
#include <fcntl.h>
|
#include <fcntl.h>
|
||||||
#endif
|
#endif
|
||||||
@ -335,6 +343,21 @@ bool isIPv6supported()
|
|||||||
#endif
|
#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
|
// setting flag is not absolutely required, therefore ignore errors here
|
||||||
void setCloseOnExec(int fd)
|
void setCloseOnExec(int fd)
|
||||||
{
|
{
|
||||||
|
@ -380,6 +380,23 @@ bool isIPv6supported()
|
|||||||
return false;
|
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)
|
int open(const char* pathname, int flags, mode_t mode)
|
||||||
{
|
{
|
||||||
return ::_open(pathname, flags, mode);
|
return ::_open(pathname, flags, mode);
|
||||||
|
@ -137,12 +137,8 @@ private:
|
|||||||
|
|
||||||
// Fool-proof requested by Alex
|
// Fool-proof requested by Alex
|
||||||
// Private memory operators to be sure that this class is used in heap only with launcher
|
// 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, Firebird::MemoryPool& pool ALLOC_PARAMS) { return pool.allocate(s ALLOC_PASS_ARGS); }
|
||||||
void* operator new (size_t s, const char* file, int line) { return MemoryPool::globalAlloc(s, file, line); }
|
void operator delete (void* mem, Firebird::MemoryPool& ALLOC_PARAMS) { MemoryPool::globalFree(mem); }
|
||||||
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 delete (void* mem) { MemoryPool::globalFree(mem); }
|
void operator delete (void* mem) { MemoryPool::globalFree(mem); }
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
Loading…
Reference in New Issue
Block a user