mirror of
https://github.com/FirebirdSQL/firebird.git
synced 2025-01-22 17:23:03 +01:00
New C++ memory pool
This commit is contained in:
parent
73147b110b
commit
6b0113844e
224
src/common/memory/allocators.cpp
Normal file
224
src/common/memory/allocators.cpp
Normal file
@ -0,0 +1,224 @@
|
||||
/*
|
||||
* PROGRAM: Client/Server Common Code
|
||||
* MODULE: memory_pool.cpp
|
||||
* DESCRIPTION: Memory Pool Manager
|
||||
*
|
||||
* The contents of this file are subject to the Interbase Public
|
||||
* License Version 1.0 (the "License"); you may not use this file
|
||||
* except in compliance with the License. You may obtain a copy
|
||||
* of the License at http://www.Inprise.com/IPL.html
|
||||
*
|
||||
* Software distributed under the License is distributed on an
|
||||
* "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, either express
|
||||
* or implied. See the License for the specific language governing
|
||||
* rights and limitations under the License.
|
||||
*
|
||||
* The Original Code was created by Inprise Corporation
|
||||
* and its predecessors. Portions created by Inprise Corporation are
|
||||
* Copyright (C) Inprise Corporation.
|
||||
*
|
||||
* All Rights Reserved.
|
||||
* Contributor(s): ______________________________________.
|
||||
*
|
||||
* 2001.11.29 John Bellardo: Reworked all routines to create the MemoryPool
|
||||
* class as part of the C++ conversion. Additionally the class now handles
|
||||
* generic memory allocations instead of typed-only allocations.
|
||||
*/
|
||||
|
||||
#include "../../common/memory/allocators.h"
|
||||
#include "../../include/fb_exception.h"
|
||||
#include "../../jrd/gds.h"
|
||||
#include "../../jrd/gdsassert.h"
|
||||
#include <new>
|
||||
|
||||
class InitMemoryPool
|
||||
{
|
||||
public:
|
||||
InitMemoryPool() { loadPool(); }
|
||||
static void loadPool()
|
||||
{
|
||||
if (!FB_MemoryPool)
|
||||
FB_MemoryPool = new BootstrapMemoryPool;
|
||||
}
|
||||
private:
|
||||
class BootstrapMemoryPool : public MemoryPool
|
||||
{
|
||||
public:
|
||||
BootstrapMemoryPool() : MemoryPool(102400) {}
|
||||
void* operator new(size_t s)
|
||||
{
|
||||
void* mem = malloc(s);
|
||||
if (!mem) {
|
||||
throw std::bad_alloc();
|
||||
}
|
||||
return mem;
|
||||
}
|
||||
void operator delete(void *mem) { free(mem); }
|
||||
};
|
||||
};
|
||||
|
||||
MemoryPool *FB_MemoryPool = 0;
|
||||
static InitMemoryPool poolLoader;
|
||||
static int badNewCount = 0;
|
||||
|
||||
extern "C" {
|
||||
|
||||
#ifdef DEBUG_GDS_ALLOC
|
||||
|
||||
void* API_ROUTINE gds__alloc_debug(SLONG size_request,
|
||||
TEXT* filename,
|
||||
ULONG lineno)
|
||||
#else
|
||||
|
||||
void* API_ROUTINE gds__alloc(SLONG size_request)
|
||||
#endif
|
||||
{
|
||||
try
|
||||
{
|
||||
poolLoader.loadPool();
|
||||
return FB_MemoryPool->allocate(size_request);
|
||||
} catch(...) {}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
ULONG API_ROUTINE gds__free(void* blk)
|
||||
{
|
||||
try
|
||||
{
|
||||
poolLoader.loadPool();
|
||||
return FB_MemoryPool->deallocate(blk);
|
||||
} catch(...) {}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
} // extern "C"
|
||||
|
||||
|
||||
// Our implementations for the global operators new/delete.
|
||||
|
||||
/** operator new[] implementation to trap all calls to the default operator
|
||||
new. You MUST allocate all memory from a pool. Since there is no way
|
||||
to specifiy a pool to the default operator new it just throws an assert.
|
||||
If you are using std::* classes you need to use allocators.
|
||||
**/
|
||||
void* operator new(size_t s)
|
||||
{
|
||||
// We MUST have a pool to allocate from, otherwise there is
|
||||
// an error.
|
||||
// TMN: No it's not. The Dinkum C++ library as shipped with
|
||||
// MSVC (5 & 6) allocates a few small objects from the global heap.
|
||||
#if defined(DEV_BUILD)
|
||||
if (++badNewCount > 1)
|
||||
{
|
||||
printf("You MUST allocate all memory from a pool. Don't use the default global new().\n");
|
||||
#if !defined(_MSC_VER)
|
||||
throw std::bad_alloc();
|
||||
#endif
|
||||
}
|
||||
#endif // DEV_BUILD
|
||||
poolLoader.loadPool();
|
||||
return FB_MemoryPool->allocate(s);
|
||||
}
|
||||
|
||||
/** operator new[] implementation to trap all calls to the default operator
|
||||
new. You MUST allocate all memory from a pool. Since there is no way
|
||||
to specifiy a pool to the default operator new it just throws an assert.
|
||||
If you are using std::* classes you need to use allocators.
|
||||
**/
|
||||
void* operator new[](size_t s)
|
||||
{
|
||||
// We MUST have a pool to allocate from, otherwise there is
|
||||
// an error
|
||||
#ifdef DEV_BUILD
|
||||
if (++badNewCount > 1)
|
||||
{
|
||||
printf("You MUST allocate all memory from a pool. Don't use the default global new[]().\n");
|
||||
throw std::bad_alloc();
|
||||
}
|
||||
#endif
|
||||
poolLoader.loadPool();
|
||||
return FB_MemoryPool->allocate(s);
|
||||
}
|
||||
|
||||
/** Generic operator new to allocate memory from a given pool. Works with
|
||||
all objects that don't define their own operator new.
|
||||
**/
|
||||
void* operator new(size_t s, MemoryPool& p)
|
||||
{
|
||||
return p.allocate(s, 0);
|
||||
}
|
||||
|
||||
/** operator delete to handle exceptions thrown while contructing object with
|
||||
our custom operator new.
|
||||
**/
|
||||
void operator delete(void* mem, MemoryPool& p)
|
||||
{
|
||||
if (mem) {
|
||||
MemoryPool::deallocate(mem);
|
||||
}
|
||||
}
|
||||
|
||||
/** standard operator delete called to free object without their own
|
||||
implementation of operator delete.
|
||||
**/
|
||||
void operator delete(void* mem)
|
||||
{
|
||||
if (mem) {
|
||||
MemoryPool::deallocate(mem);
|
||||
}
|
||||
}
|
||||
|
||||
// no implmentation of these two functions in dev build to force link
|
||||
// errors if they are used.
|
||||
#ifndef DEV_BUILD
|
||||
/** This operator new traps the standard libraries placement new. It simply
|
||||
pops an assert to prevent inadvertant use. Use the reference versions
|
||||
of operator new() instead.
|
||||
**/
|
||||
void* operator new[](size_t s, MemoryPool* p)
|
||||
{
|
||||
assert(0);
|
||||
}
|
||||
|
||||
/** This operator new traps the standard libraries placement new. It simply
|
||||
pops an assert to prevent inadvertant use. Use the reference versions
|
||||
of operator new() instead.
|
||||
**/
|
||||
void* operator new(size_t s, MemoryPool* p)
|
||||
{
|
||||
assert(0);
|
||||
}
|
||||
#endif
|
||||
|
||||
/** Generic operator new to allocate memory from a given pool. Works with
|
||||
all objects that don't define their own operator new.
|
||||
**/
|
||||
void* operator new[](size_t s, MemoryPool& p)
|
||||
{
|
||||
return p.allocate(s, 0);
|
||||
}
|
||||
|
||||
/** operator delete[] to handle exceptions thrown while contructing object with
|
||||
our custom operator new.
|
||||
**/
|
||||
void operator delete[](void* mem, MemoryPool& p)
|
||||
{
|
||||
if (mem) {
|
||||
MemoryPool::deallocate(mem);
|
||||
}
|
||||
}
|
||||
|
||||
/** standard operator delete[] called to free object without their own
|
||||
implementation of operator delete.
|
||||
**/
|
||||
void operator delete[](void* mem)
|
||||
{
|
||||
if (mem) {
|
||||
MemoryPool::deallocate(mem);
|
||||
}
|
||||
}
|
||||
|
||||
|
132
src/common/memory/allocators.h
Normal file
132
src/common/memory/allocators.h
Normal file
@ -0,0 +1,132 @@
|
||||
/*
|
||||
* PROGRAM: Client/Server Common Code
|
||||
* MODULE: memory_pool.h
|
||||
* DESCRIPTION: Memory Pool Manager
|
||||
*
|
||||
* The contents of this file are subject to the Interbase Public
|
||||
* License Version 1.0 (the "License"); you may not use this file
|
||||
* except in compliance with the License. You may obtain a copy
|
||||
* of the License at http://www.Inprise.com/IPL.html
|
||||
*
|
||||
* Software distributed under the License is distributed on an
|
||||
* "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, either express
|
||||
* or implied. See the License for the specific language governing
|
||||
* rights and limitations under the License.
|
||||
*
|
||||
* The Original Code was created by Inprise Corporation
|
||||
* and its predecessors. Portions created by Inprise Corporation are
|
||||
* Copyright (C) Inprise Corporation.
|
||||
*
|
||||
* All Rights Reserved.
|
||||
* Contributor(s): ______________________________________.
|
||||
* 2001.11.29 John Bellardo: Reworked all routines to create the MemoryPool
|
||||
* class as part of the C++ conversion. Additionally the class now handles
|
||||
* generic memory allocations instead of typed-only allocations.
|
||||
*/
|
||||
|
||||
#ifndef COMMON_ALLOCATORS_H
|
||||
#define COMMON_ALLOCATORS_H
|
||||
|
||||
#include "../common/memory/memory_pool.h"
|
||||
#include "../jrd/gds_proto.h"
|
||||
#include <vector>
|
||||
|
||||
extern "C" {
|
||||
#ifdef DEBUG_GDS_ALLOC
|
||||
void* API_ROUTINE gds__alloc_debug(SLONG size_request,
|
||||
TEXT* filename,
|
||||
ULONG lineno);
|
||||
#else
|
||||
void* API_ROUTINE gds__alloc(SLONG size_request);
|
||||
#endif
|
||||
extern ULONG API_ROUTINE gds__free(void* blk);
|
||||
};
|
||||
|
||||
extern MemoryPool *FB_MemoryPool;
|
||||
|
||||
void* operator new(size_t);
|
||||
void* operator new[](size_t);
|
||||
|
||||
void* operator new(size_t, MemoryPool&);
|
||||
void operator delete(void* mem, MemoryPool&);
|
||||
void* operator new[](size_t s, MemoryPool&);
|
||||
void operator delete[](void* mem, MemoryPool&);
|
||||
|
||||
void* operator new(size_t, MemoryPool*);
|
||||
void* operator new[](size_t s, MemoryPool*);
|
||||
|
||||
void operator delete(void* mem);
|
||||
void operator delete[](void* mem);
|
||||
|
||||
/**
|
||||
This is the allocator template provided to be used with the STL.
|
||||
Since the STL is the client of this class look to its documentation
|
||||
to determine what the individual functions and typedefs do.
|
||||
|
||||
In order to use the allocator class you need to instansiate the
|
||||
C++ container template with the allocator. For example if you
|
||||
want to use a std::vector<int> the declaration would be:
|
||||
|
||||
std::vector<int, MemoryPool::allocator<int> >
|
||||
|
||||
The allocator, by default, allocates all memory from the process
|
||||
wide pool FB_MemoryPool. Typically this is NOT the behavior you
|
||||
want. Selection of the correct pool to allocate your memory from is
|
||||
important. If you select a pool to far down in (a statement pool,
|
||||
for example) you memory may be freed before you are done with it.
|
||||
On the other hand if you always use the global pool you will
|
||||
either leak memory or have to make sure you always delete the objects
|
||||
you create.
|
||||
|
||||
If you decide to allocate the memory from a pool other than the global
|
||||
pool you need to pass an allocator object to the constructor for
|
||||
the STL object. For example:
|
||||
|
||||
std::vector<int, MemoryPool::allocator<int> > vec(MemoryPool::allocator<int>(poolRef, type));
|
||||
The type is an optional parameter that defaults to 0.
|
||||
**/
|
||||
namespace Firebird
|
||||
{
|
||||
template <class T>
|
||||
class allocator
|
||||
{
|
||||
public:
|
||||
typedef size_t size_type;
|
||||
typedef ptrdiff_t difference_type;
|
||||
typedef T* pointer;
|
||||
typedef const T* const_pointer;
|
||||
typedef T& reference;
|
||||
typedef const T& const_reference;
|
||||
typedef T value_type;
|
||||
|
||||
allocator(MemoryPool& p, SSHORT t = 0) : pool(&p), type(t) {}
|
||||
allocator(MemoryPool *p = FB_MemoryPool, SSHORT t = 0) : pool(p), type(t) {}
|
||||
|
||||
pointer allocate(size_type s, const void * = 0)
|
||||
{ return (pointer) (pool ? pool->allocate(sizeof(T) * s) : gds__alloc(sizeof(T)*s)); }
|
||||
void deallocate(pointer p, size_type s)
|
||||
{ if (pool) MemoryPool::deallocate(p); else gds__free(p); }
|
||||
void construct(pointer p, const T& v) { new(p) T(v); }
|
||||
void destroy(pointer p) { p->~T(); }
|
||||
|
||||
size_type max_size() const { return (size_type)-1 / sizeof(T); }
|
||||
|
||||
pointer address(reference X) const {return &X; }
|
||||
const_pointer address(const_reference X) const {return &X; }
|
||||
|
||||
template <class _Tp1> struct rebind {
|
||||
typedef Firebird::allocator<_Tp1> other;
|
||||
};
|
||||
|
||||
bool operator==(const allocator<T>& rhs)
|
||||
{
|
||||
return pool == rhs.pool && type == rhs.type;
|
||||
}
|
||||
|
||||
private:
|
||||
MemoryPool *pool;
|
||||
SSHORT type;
|
||||
};
|
||||
};
|
||||
|
||||
#endif // COMMON_ALLOCATORS_H
|
1667
src/common/memory/memory_pool.cpp
Normal file
1667
src/common/memory/memory_pool.cpp
Normal file
File diff suppressed because it is too large
Load Diff
129
src/common/memory/memory_pool.h
Normal file
129
src/common/memory/memory_pool.h
Normal file
@ -0,0 +1,129 @@
|
||||
/*
|
||||
* PROGRAM: Client/Server Common Code
|
||||
* MODULE: memory_pool.h
|
||||
* DESCRIPTION: Memory Pool Manager
|
||||
*
|
||||
* The contents of this file are subject to the Interbase Public
|
||||
* License Version 1.0 (the "License"); you may not use this file
|
||||
* except in compliance with the License. You may obtain a copy
|
||||
* of the License at http://www.Inprise.com/IPL.html
|
||||
*
|
||||
* Software distributed under the License is distributed on an
|
||||
* "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, either express
|
||||
* or implied. See the License for the specific language governing
|
||||
* rights and limitations under the License.
|
||||
*
|
||||
* The Original Code was created by Inprise Corporation
|
||||
* and its predecessors. Portions created by Inprise Corporation are
|
||||
* Copyright (C) Inprise Corporation.
|
||||
*
|
||||
* All Rights Reserved.
|
||||
* Contributor(s): ______________________________________.
|
||||
* 2001.11.29 John Bellardo: Reworked all routines to create the MemoryPool
|
||||
* class as part of the C++ conversion. Additionally the class now handles
|
||||
* generic memory allocations instead of typed-only allocations.
|
||||
*/
|
||||
|
||||
#ifndef MEMORY_POOL_H
|
||||
#define MEMORY_POOL_H
|
||||
|
||||
#include "../include/fb_types.h"
|
||||
#include "../jrd/ib_stdio.h"
|
||||
|
||||
extern class MemoryPool *FB_MemoryPool;
|
||||
|
||||
/**
|
||||
For various reasons Firebird has chosen to do its own heap management.
|
||||
The MemoryPool class is the result of that decision. Basically a memory
|
||||
pool object is the same as a single heap. Objects can be allocated
|
||||
out of the heap and returned to the heap. Just like all requests
|
||||
for dynamic memory must reference a heap, all such requests in Firebird
|
||||
must reference a memory pool.
|
||||
|
||||
Memory pools are implemented in such a way they never return their memory
|
||||
back to the host operating system. Instead they keep track of that
|
||||
memory internally and use it to satisify future allocation requests.
|
||||
|
||||
Every memory pool has no initial pool space. It grows dynamically as
|
||||
more allocation requests are made. Every time the pool needs more space
|
||||
it goes to the operating system and requests another chunk of memory.
|
||||
That chunk is usually more than what is needed to satisify the pending
|
||||
allocation request. The minimum requested size can vary from memory
|
||||
pool to memory pool and is call the extend size.
|
||||
|
||||
The option also exists to have a pool contact another pool if it needs
|
||||
more memory instead of going to the operating system. This allows the
|
||||
creation of pool hierarchies.
|
||||
|
||||
All the memory in the pool can be freed at once which is a speed savings,
|
||||
but at the current time the destructors for any objects in the pool
|
||||
will NOT get called. So they need to be explicitly deleted BEFORE the
|
||||
pool is released.
|
||||
|
||||
To make it easier to allocate memory from the memory pools a number
|
||||
of implementations of the operator new are provided in the file
|
||||
common/memory/allocators.h. Basically, to allocate memory from a pool
|
||||
use the following code:
|
||||
|
||||
obj = new(poolReference) Obj;
|
||||
|
||||
If you use the STL you must also use allocators to ensure all the memory
|
||||
allocated by the STL ends up in a heap. The template
|
||||
MemoryPool::allocator<T> has been written to be used with the STL objects.
|
||||
Sometimes the template types can get out of control when using allocators.
|
||||
So there are some convience templates provided in the Firebird namespace
|
||||
that mimic the std classes, but use Firebird allocators.
|
||||
|
||||
The details of how the memory is managed (not just how you get the memory
|
||||
you need) can be found in the documentation for the FBMemoryPool class.
|
||||
|
||||
If any memory operation fail an exception is raised.
|
||||
**/
|
||||
class MemoryPool
|
||||
{
|
||||
public:
|
||||
MemoryPool(size_t = 0, MemoryPool* = 0);
|
||||
virtual ~MemoryPool();
|
||||
|
||||
/// Free all memory from the pool, but leave the pool in a state to
|
||||
/// allocate more memory.
|
||||
void release_pool(void);
|
||||
|
||||
/// Allocates at least the given number of bytes from the pool and
|
||||
/// returns a pointer to the memory.
|
||||
void* allocate(size_t, SSHORT = 0);
|
||||
|
||||
/// Deallocates memory that has been allocated from ANY MemoryPool.
|
||||
static int deallocate(void*);
|
||||
|
||||
/// Allocate memory directly from the OS
|
||||
static void* malloc_from_system(size_t);
|
||||
/// Deallocate memory allocated directly from the OS
|
||||
static SLONG free_from_system(void* mem);
|
||||
|
||||
/// Pool debugging calls
|
||||
void print_contents(IB_FILE*, const char* (*)(int) = 0,
|
||||
void (*)(int, void*, IB_FILE*, const char*) = 0);
|
||||
/// Verify the structural integrity of the pool
|
||||
bool verify_pool(bool = false);
|
||||
|
||||
/// Get the minimum extend size for the pool.
|
||||
size_t extendSize();
|
||||
/// Set the minimum extend size for the pool
|
||||
void setExtendSize(size_t);
|
||||
|
||||
/// Returns the type associated with the allocated memory.
|
||||
static SSHORT blk_type(const void* mem);
|
||||
/// Returns the pool the memory was allocated from.
|
||||
static MemoryPool* blk_pool(const void* mem);
|
||||
|
||||
private:
|
||||
class FBMemoryPool *pimpl;
|
||||
class MemoryPool *parent;
|
||||
size_t extend_inc;
|
||||
|
||||
void* allocate_int(size_t, SSHORT);
|
||||
friend class FBMemoryPool;
|
||||
};
|
||||
|
||||
#endif // JRD_MEMORY_POOL_H
|
21
src/common/mp/AtomicCounter.h
Normal file
21
src/common/mp/AtomicCounter.h
Normal file
@ -0,0 +1,21 @@
|
||||
#ifndef ATOMIC_COUNTER_H
|
||||
#define ATOMIC_COUNTER_H
|
||||
|
||||
class AtomicCounter
|
||||
{
|
||||
public:
|
||||
AtomicCounter(int);
|
||||
~AtomicCounter();
|
||||
|
||||
operator int() const;
|
||||
const AtomicCounter &operator +=(int);
|
||||
const AtomicCounter &operator -=(int);
|
||||
const AtomicCounter &operator ++(int);
|
||||
const AtomicCounter &operator --(int);
|
||||
|
||||
private:
|
||||
const AtomicCounter &operator =
|
||||
int counter;
|
||||
};
|
||||
|
||||
#endif
|
0
src/common/mp/crit_section_guard.h
Normal file
0
src/common/mp/crit_section_guard.h
Normal file
0
src/common/mp/crit_section_lock.h
Normal file
0
src/common/mp/crit_section_lock.h
Normal file
0
src/common/mp/mutex.h
Normal file
0
src/common/mp/mutex.h
Normal file
0
src/common/mp/semaphore.h
Normal file
0
src/common/mp/semaphore.h
Normal file
0
src/common/mp/thread.h
Normal file
0
src/common/mp/thread.h
Normal file
Loading…
Reference in New Issue
Block a user