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

New C++ memory pool

This commit is contained in:
tamlin 2001-12-24 03:02:42 +00:00
parent 73147b110b
commit 6b0113844e
10 changed files with 2173 additions and 0 deletions

View 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);
}
}

View 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

File diff suppressed because it is too large Load Diff

View 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

View 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

View File

View File

0
src/common/mp/mutex.h Normal file
View File

View File

0
src/common/mp/thread.h Normal file
View File