2002-12-14 22:43:18 +01:00
|
|
|
/*
|
|
|
|
* PROGRAM: Client/Server Common Code
|
|
|
|
* MODULE: alloc.cpp
|
|
|
|
* DESCRIPTION: Memory Pool Manager (based on B+ tree)
|
|
|
|
*
|
2003-09-08 22:23:46 +02:00
|
|
|
* This library is free software; you can redistribute it and/or
|
|
|
|
* modify it under the terms of the GNU Lesser General Public
|
|
|
|
* License as published by the Free Software Foundation; either
|
|
|
|
* version 2.1 of the License, or (at your option) any later version.
|
|
|
|
* You may obtain a copy of the Licence at
|
|
|
|
* http://www.gnu.org/licences/lgpl.html
|
|
|
|
*
|
|
|
|
* As a special exception this file can also be included in modules
|
|
|
|
* with other source code as long as that source code has been
|
|
|
|
* released under an Open Source Initiative certificed licence.
|
|
|
|
* More information about OSI certification can be found at:
|
|
|
|
* http://www.opensource.org
|
|
|
|
*
|
|
|
|
* This module is distributed in the hope that it will be useful,
|
|
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
* GNU Lesser General Public Licence for more details.
|
|
|
|
*
|
|
|
|
* This module was created by members of the firebird development
|
|
|
|
* team. All individual contributions remain the Copyright (C) of
|
|
|
|
* those individuals and all rights are reserved. Contributors to
|
|
|
|
* this file are either listed below or can be obtained from a CVS
|
|
|
|
* history command.
|
2002-12-14 22:43:18 +01:00
|
|
|
*
|
2003-09-08 22:23:46 +02:00
|
|
|
* Created by: Nickolay Samofatov <skidder@bssys.com>
|
2002-12-14 22:43:18 +01:00
|
|
|
*
|
2003-09-08 22:23:46 +02:00
|
|
|
* Contributor(s):
|
|
|
|
*
|
2002-12-14 22:43:18 +01:00
|
|
|
*
|
2004-01-28 08:50:41 +01:00
|
|
|
* $Id: alloc.cpp,v 1.37 2004-01-28 07:50:18 robocop Exp $
|
2002-12-14 22:43:18 +01:00
|
|
|
*
|
|
|
|
*/
|
|
|
|
|
2003-01-06 18:35:21 +01:00
|
|
|
#include "../../include/firebird.h"
|
2002-12-14 22:43:18 +01:00
|
|
|
#include "alloc.h"
|
|
|
|
|
|
|
|
// Size in bytes, must be aligned according to ALLOC_ALIGNMENT
|
2003-02-02 14:09:55 +01:00
|
|
|
#define MIN_EXTENT_SIZE 16384
|
2002-12-14 22:43:18 +01:00
|
|
|
|
|
|
|
#define FB_MAX(M,N) ((M)>(N)?(M):(N))
|
|
|
|
|
2003-01-09 20:47:46 +01:00
|
|
|
#define FREE_PATTERN 0xDEADBEEF
|
|
|
|
#define ALLOC_PATTERN 0xFEEDABED
|
2003-01-16 18:47:10 +01:00
|
|
|
//#define ALLOC_PATTERN 0x0
|
2003-01-09 20:47:46 +01:00
|
|
|
#ifdef DEBUG_GDS_ALLOC
|
2003-01-10 22:37:18 +01:00
|
|
|
#define PATTERN_FILL(ptr,size,pattern) for (size_t _i=0;_i< size>>2;_i++) ((unsigned int*)(ptr))[_i]=(pattern)
|
2003-01-09 20:47:46 +01:00
|
|
|
#else
|
|
|
|
#define PATTERN_FILL(ptr,size,pattern) ((void)0)
|
|
|
|
#endif
|
|
|
|
|
2003-01-03 17:03:30 +01:00
|
|
|
// TODO (in order of importance):
|
2003-01-07 17:35:10 +01:00
|
|
|
// 1. local pool locking +
|
|
|
|
// 2. line number debug info +
|
2003-01-09 20:47:46 +01:00
|
|
|
// 3. debug alloc/free pattern +
|
|
|
|
// 4. print pool contents function +
|
2003-01-07 17:35:10 +01:00
|
|
|
//---- Not needed for current codebase
|
|
|
|
// 5. Pool size limit
|
|
|
|
// 6. allocation source
|
|
|
|
// 7. shared pool locking
|
|
|
|
// 8. red zones checking (not really needed because verify_pool is able to detect most corruption cases)
|
2002-12-16 19:33:54 +01:00
|
|
|
|
2002-12-14 22:43:18 +01:00
|
|
|
namespace Firebird {
|
|
|
|
|
2003-01-27 12:47:04 +01:00
|
|
|
int MemoryPool::process_max_memory = 0;
|
|
|
|
int MemoryPool::process_current_memory = 0;
|
2003-01-18 22:45:24 +01:00
|
|
|
|
2002-12-14 22:43:18 +01:00
|
|
|
// Helper function to reduce code size, since many compilers
|
|
|
|
// generate quite a bit of code at the point of the throw.
|
|
|
|
static void pool_out_of_memory()
|
|
|
|
{
|
|
|
|
throw std::bad_alloc();
|
|
|
|
}
|
|
|
|
|
2003-01-16 18:47:10 +01:00
|
|
|
static MemoryPool* processMemoryPool;
|
2003-01-07 17:35:10 +01:00
|
|
|
|
2003-01-30 14:26:16 +01:00
|
|
|
MemoryPool::MemoryPool(void *first_extent, void *root_page, int* cur_mem, int* max_mem) :
|
|
|
|
freeBlocks((InternalAllocator*)this, root_page),
|
|
|
|
extents((MemoryExtent *)first_extent),
|
|
|
|
needSpare(false),
|
|
|
|
pendingFree(NULL),
|
|
|
|
/*extents_memory(0), - Initialized in internal_create() */
|
|
|
|
used_memory(0),
|
|
|
|
cur_memory(cur_mem),
|
|
|
|
max_memory(max_mem)
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
2003-01-03 17:03:30 +01:00
|
|
|
void MemoryPool::updateSpare() {
|
|
|
|
do {
|
2003-01-09 20:47:46 +01:00
|
|
|
do {
|
|
|
|
needSpare = false;
|
|
|
|
while (spareLeafs.getCount() < spareLeafs.getCapacity()) {
|
2003-01-16 18:47:10 +01:00
|
|
|
void* temp = internal_alloc(sizeof(FreeBlocksTree::ItemList), TYPE_LEAFPAGE);
|
2003-01-09 20:47:46 +01:00
|
|
|
if (!temp) return;
|
|
|
|
spareLeafs.add(temp);
|
|
|
|
}
|
|
|
|
while (spareNodes.getCount() <= freeBlocks.level) {
|
2003-01-16 18:47:10 +01:00
|
|
|
void* temp = internal_alloc(sizeof(FreeBlocksTree::NodeList), TYPE_TREEPAGE);
|
2003-01-09 20:47:46 +01:00
|
|
|
if (!temp) return;
|
|
|
|
spareNodes.add(temp);
|
2003-01-03 17:03:30 +01:00
|
|
|
}
|
|
|
|
break;
|
2003-01-09 20:47:46 +01:00
|
|
|
} while (needSpare);
|
|
|
|
// Great, if we were able to restore free blocks tree operations after critically low
|
|
|
|
// memory condition then try to add pending free blocks to our tree
|
|
|
|
while (pendingFree) {
|
|
|
|
PendingFreeBlock *temp = pendingFree;
|
|
|
|
pendingFree = temp->next;
|
|
|
|
MemoryBlock *blk = (MemoryBlock*)((char*)temp-MEM_ALIGN(sizeof(MemoryBlock)));
|
|
|
|
BlockInfo info = {
|
|
|
|
blk,
|
|
|
|
blk->length
|
|
|
|
};
|
|
|
|
freeBlocks.add(info); // We should be able to do this because we had all needed spare blocks
|
2003-01-03 17:03:30 +01:00
|
|
|
}
|
|
|
|
} while (needSpare);
|
|
|
|
}
|
|
|
|
|
2002-12-14 22:43:18 +01:00
|
|
|
void* MemoryPool::external_alloc(size_t size) {
|
2003-01-03 17:03:30 +01:00
|
|
|
// This method is assumed to return NULL in case it cannot alloc
|
2002-12-14 22:43:18 +01:00
|
|
|
return malloc(size);
|
|
|
|
}
|
|
|
|
|
|
|
|
void MemoryPool::external_free(void *blk) {
|
|
|
|
::free(blk);
|
|
|
|
}
|
|
|
|
|
2003-01-16 18:47:10 +01:00
|
|
|
void* MemoryPool::tree_alloc(size_t size) {
|
2003-01-10 13:27:57 +01:00
|
|
|
if (size == sizeof(FreeBlocksTree::ItemList))
|
|
|
|
// This condition is to handle case when nodelist and itemlist have equal size
|
|
|
|
if (sizeof(FreeBlocksTree::ItemList)!=sizeof(FreeBlocksTree::NodeList) ||
|
|
|
|
spareLeafs.getCount())
|
|
|
|
{
|
|
|
|
if (!spareLeafs.getCount()) pool_out_of_memory();
|
|
|
|
void *temp = spareLeafs[spareLeafs.getCount()-1];
|
|
|
|
spareLeafs.shrink(spareLeafs.getCount()-1);
|
|
|
|
needSpare = true;
|
|
|
|
return temp;
|
|
|
|
}
|
|
|
|
if (size == sizeof(FreeBlocksTree::NodeList)) {
|
|
|
|
if (!spareNodes.getCount()) pool_out_of_memory();
|
|
|
|
void *temp = spareNodes[spareNodes.getCount()-1];
|
|
|
|
spareNodes.shrink(spareNodes.getCount()-1);
|
|
|
|
needSpare = true;
|
|
|
|
return temp;
|
|
|
|
}
|
2003-11-04 00:59:24 +01:00
|
|
|
fb_assert(false);
|
2003-01-18 19:43:52 +01:00
|
|
|
return 0;
|
2003-01-10 13:27:57 +01:00
|
|
|
}
|
|
|
|
|
2003-01-16 18:47:10 +01:00
|
|
|
void MemoryPool::tree_free(void* block) {
|
2003-01-10 13:27:57 +01:00
|
|
|
((PendingFreeBlock*)block)->next = pendingFree;
|
|
|
|
((MemoryBlock*)((char*)block-MEM_ALIGN(sizeof(MemoryBlock))))->used = false;
|
|
|
|
pendingFree = (PendingFreeBlock*)block;
|
|
|
|
needSpare = true;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2003-01-16 18:47:10 +01:00
|
|
|
void* MemoryPool::allocate(size_t size, SSHORT type
|
2003-01-09 20:47:46 +01:00
|
|
|
#ifdef DEBUG_GDS_ALLOC
|
2003-11-07 09:06:35 +01:00
|
|
|
, const char* file, int line
|
2003-01-09 20:47:46 +01:00
|
|
|
#endif
|
|
|
|
) {
|
2003-01-10 22:37:18 +01:00
|
|
|
lock.enter();
|
2003-01-16 18:47:10 +01:00
|
|
|
void* result = internal_alloc(size, type
|
2003-01-09 20:47:46 +01:00
|
|
|
#ifdef DEBUG_GDS_ALLOC
|
|
|
|
, file, line
|
|
|
|
#endif
|
|
|
|
);
|
|
|
|
if (needSpare) updateSpare();
|
2003-01-10 22:37:18 +01:00
|
|
|
lock.leave();
|
2003-01-09 20:47:46 +01:00
|
|
|
if (!result) pool_out_of_memory();
|
2003-01-16 18:47:10 +01:00
|
|
|
// test with older behavior
|
|
|
|
// memset(result,0,size);
|
2003-01-09 20:47:46 +01:00
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
2003-01-16 18:47:10 +01:00
|
|
|
bool MemoryPool::verify_pool() {
|
|
|
|
#ifdef TESTING_ONLY
|
2003-01-10 22:37:18 +01:00
|
|
|
lock.enter();
|
2003-11-04 00:59:24 +01:00
|
|
|
fb_assert (!pendingFree || needSpare); // needSpare flag should be set if we are in
|
2002-12-16 19:33:54 +01:00
|
|
|
// a critically low memory condition
|
|
|
|
// check each block in each segment for consistency with free blocks structure
|
|
|
|
for (MemoryExtent *extent = extents; extent; extent=extent->next) {
|
|
|
|
MemoryBlock *prev = NULL;
|
2003-01-07 17:35:10 +01:00
|
|
|
for (MemoryBlock *blk = (MemoryBlock *)((char*)extent+MEM_ALIGN(sizeof(MemoryExtent)));
|
2003-01-09 20:47:46 +01:00
|
|
|
;
|
2003-01-07 17:35:10 +01:00
|
|
|
blk = (MemoryBlock *)((char*)blk+MEM_ALIGN(sizeof(MemoryBlock))+blk->length))
|
2002-12-16 19:33:54 +01:00
|
|
|
{
|
|
|
|
#ifndef NDEBUG
|
2003-11-04 00:59:24 +01:00
|
|
|
fb_assert(blk->pool == this); // Pool is correct ?
|
|
|
|
fb_assert(blk->prev == prev); // Prev is correct ?
|
2002-12-16 19:33:54 +01:00
|
|
|
BlockInfo temp = {blk, blk->length};
|
|
|
|
bool foundTree = freeBlocks.locate(temp), foundPending = false;
|
2003-01-06 18:35:21 +01:00
|
|
|
for (PendingFreeBlock *tmp = pendingFree; tmp; tmp = tmp->next)
|
2003-01-07 17:35:10 +01:00
|
|
|
if (tmp == (PendingFreeBlock *)((char*)blk+MEM_ALIGN(sizeof(MemoryBlock)))) {
|
2003-11-04 00:59:24 +01:00
|
|
|
fb_assert(!foundPending); // Block may be in pending list only one time
|
2002-12-16 19:33:54 +01:00
|
|
|
foundPending = true;
|
|
|
|
}
|
2003-11-04 00:59:24 +01:00
|
|
|
fb_assert(! (foundTree && foundPending)); // Block shouldn't be present both in
|
2002-12-16 19:33:54 +01:00
|
|
|
// pending list and in tree list
|
|
|
|
|
|
|
|
if (!blk->used) {
|
2003-11-04 00:59:24 +01:00
|
|
|
fb_assert(foundTree || foundPending); // Block is free. Should be somewhere
|
2004-01-28 08:50:41 +01:00
|
|
|
}
|
|
|
|
else
|
2003-11-04 00:59:24 +01:00
|
|
|
fb_assert(!foundTree && !foundPending); // Block is not free. Should not be in free lists
|
2002-12-16 19:33:54 +01:00
|
|
|
#endif
|
|
|
|
prev = blk;
|
2003-01-09 20:47:46 +01:00
|
|
|
if (blk->last) break;
|
|
|
|
}
|
|
|
|
}
|
2003-01-10 22:37:18 +01:00
|
|
|
lock.leave();
|
2003-01-16 18:47:10 +01:00
|
|
|
#endif
|
|
|
|
return true;
|
2003-01-09 20:47:46 +01:00
|
|
|
}
|
|
|
|
|
2003-01-16 18:47:10 +01:00
|
|
|
void MemoryPool::print_contents(IB_FILE *file, bool used_only) {
|
2003-01-10 22:37:18 +01:00
|
|
|
lock.enter();
|
2003-01-09 20:47:46 +01:00
|
|
|
for (MemoryExtent *extent = extents; extent; extent=extent->next) {
|
|
|
|
if (!used_only)
|
|
|
|
ib_fprintf(file, "EXTENT %p:\n", extent);
|
|
|
|
for (MemoryBlock *blk = (MemoryBlock *)((char*)extent+MEM_ALIGN(sizeof(MemoryExtent)));
|
|
|
|
;
|
|
|
|
blk = (MemoryBlock *)((char*)blk+MEM_ALIGN(sizeof(MemoryBlock))+blk->length))
|
|
|
|
{
|
|
|
|
void *mem = (char*)blk + MEM_ALIGN(sizeof(MemoryBlock));
|
|
|
|
if (blk->used && (blk->type>0 || !used_only)) {
|
|
|
|
#ifdef DEBUG_GDS_ALLOC
|
2003-01-20 09:40:02 +01:00
|
|
|
if (blk->type > 0)
|
2003-01-09 20:47:46 +01:00
|
|
|
ib_fprintf(file, "Block %p: size=%d allocated at %s:%d\n",
|
|
|
|
mem, blk->length, blk->file, blk->line);
|
2003-01-20 09:40:02 +01:00
|
|
|
else if (blk->type == 0)
|
2003-01-09 20:47:46 +01:00
|
|
|
ib_fprintf(file, "Typed block %p: type=%d size=%d allocated at %s:%d\n",
|
|
|
|
mem, blk->type, blk->length, blk->file, blk->line);
|
2003-01-20 09:40:02 +01:00
|
|
|
else
|
|
|
|
ib_fprintf(file, "Typed block %p: type=%d size=%d\n",
|
|
|
|
mem, blk->type, blk->length);
|
2003-01-09 20:47:46 +01:00
|
|
|
#else
|
|
|
|
if (blk->type)
|
|
|
|
ib_fprintf(file, "Typed block %p: type=%d size=%d\n", mem, blk->type, blk->length);
|
|
|
|
else
|
|
|
|
ib_fprintf(file, "Block %p: size=%d\n", mem, blk->length);
|
|
|
|
#endif
|
2004-01-28 08:50:41 +01:00
|
|
|
}
|
|
|
|
else {
|
2003-01-09 20:47:46 +01:00
|
|
|
if (!used_only)
|
|
|
|
ib_fprintf(file, "Free block %p: size=%d\n", mem, blk->length);
|
|
|
|
}
|
|
|
|
if (blk->last) break;
|
2002-12-16 19:33:54 +01:00
|
|
|
}
|
|
|
|
}
|
2003-01-10 22:37:18 +01:00
|
|
|
lock.leave();
|
2002-12-16 19:33:54 +01:00
|
|
|
}
|
|
|
|
|
2003-01-18 22:45:24 +01:00
|
|
|
MemoryPool* MemoryPool::internal_create(size_t instance_size, int *cur_mem, int *max_mem) {
|
2003-01-27 12:47:04 +01:00
|
|
|
if (!cur_mem) cur_mem = &process_current_memory;
|
|
|
|
if (!max_mem) max_mem = &process_max_memory;
|
|
|
|
|
2002-12-14 22:43:18 +01:00
|
|
|
size_t alloc_size = FB_MAX(
|
|
|
|
// This is the exact initial layout of memory pool in the first extent //
|
2003-01-07 17:35:10 +01:00
|
|
|
MEM_ALIGN(sizeof(MemoryExtent)) +
|
|
|
|
MEM_ALIGN(sizeof(MemoryBlock)) +
|
2003-01-16 18:47:10 +01:00
|
|
|
MEM_ALIGN(instance_size) +
|
2003-01-07 17:35:10 +01:00
|
|
|
MEM_ALIGN(sizeof(MemoryBlock)) +
|
|
|
|
MEM_ALIGN(sizeof(FreeBlocksTree::ItemList)) +
|
|
|
|
MEM_ALIGN(sizeof(MemoryBlock)) +
|
2002-12-14 22:43:18 +01:00
|
|
|
ALLOC_ALIGNMENT,
|
|
|
|
// ******************************************************************* //
|
|
|
|
MIN_EXTENT_SIZE);
|
2003-01-17 10:59:59 +01:00
|
|
|
|
2002-12-14 22:43:18 +01:00
|
|
|
char* mem = (char *)external_alloc(alloc_size);
|
|
|
|
if (!mem) pool_out_of_memory();
|
|
|
|
((MemoryExtent *)mem)->next = NULL;
|
2002-12-16 19:33:54 +01:00
|
|
|
MemoryPool* pool = new(mem +
|
2003-01-07 17:35:10 +01:00
|
|
|
MEM_ALIGN(sizeof(MemoryExtent)) +
|
|
|
|
MEM_ALIGN(sizeof(MemoryBlock)))
|
2002-12-16 19:33:54 +01:00
|
|
|
MemoryPool(mem, mem +
|
2003-01-07 17:35:10 +01:00
|
|
|
MEM_ALIGN(sizeof(MemoryExtent)) +
|
|
|
|
MEM_ALIGN(sizeof(MemoryBlock)) +
|
2003-01-16 18:47:10 +01:00
|
|
|
MEM_ALIGN(instance_size) +
|
2003-01-18 22:45:24 +01:00
|
|
|
MEM_ALIGN(sizeof(MemoryBlock)),
|
|
|
|
cur_mem, max_mem);
|
|
|
|
|
|
|
|
pool->extents_memory = alloc_size - MEM_ALIGN(sizeof(MemoryExtent));
|
|
|
|
|
2003-01-07 17:35:10 +01:00
|
|
|
MemoryBlock *poolBlk = (MemoryBlock*) (mem+MEM_ALIGN(sizeof(MemoryExtent)));
|
2002-12-16 19:33:54 +01:00
|
|
|
poolBlk->pool = pool;
|
|
|
|
poolBlk->used = true;
|
|
|
|
poolBlk->last = false;
|
|
|
|
poolBlk->type = TYPE_POOL;
|
2003-01-16 18:47:10 +01:00
|
|
|
poolBlk->length = MEM_ALIGN(instance_size);
|
2002-12-16 19:33:54 +01:00
|
|
|
poolBlk->prev = NULL;
|
2002-12-14 22:43:18 +01:00
|
|
|
|
2002-12-16 19:33:54 +01:00
|
|
|
MemoryBlock *hdr = (MemoryBlock*) (mem +
|
2003-01-07 17:35:10 +01:00
|
|
|
MEM_ALIGN(sizeof(MemoryExtent)) +
|
|
|
|
MEM_ALIGN(sizeof(MemoryBlock)) +
|
2003-01-16 18:47:10 +01:00
|
|
|
MEM_ALIGN(instance_size));
|
2002-12-14 22:43:18 +01:00
|
|
|
hdr->pool = pool;
|
|
|
|
hdr->used = true;
|
|
|
|
hdr->last = false;
|
|
|
|
hdr->type = TYPE_LEAFPAGE;
|
2003-01-07 17:35:10 +01:00
|
|
|
hdr->length = MEM_ALIGN(sizeof(FreeBlocksTree::ItemList));
|
2002-12-16 19:33:54 +01:00
|
|
|
hdr->prev = poolBlk;
|
|
|
|
MemoryBlock *blk = (MemoryBlock *)(mem +
|
2003-01-07 17:35:10 +01:00
|
|
|
MEM_ALIGN(sizeof(MemoryExtent)) +
|
|
|
|
MEM_ALIGN(sizeof(MemoryBlock)) +
|
2003-01-16 18:47:10 +01:00
|
|
|
MEM_ALIGN(instance_size) +
|
2003-01-07 17:35:10 +01:00
|
|
|
MEM_ALIGN(sizeof(MemoryBlock)) +
|
|
|
|
MEM_ALIGN(sizeof(FreeBlocksTree::ItemList)));
|
2002-12-16 19:33:54 +01:00
|
|
|
int blockLength = alloc_size -
|
2003-01-07 17:35:10 +01:00
|
|
|
MEM_ALIGN(sizeof(MemoryExtent)) -
|
|
|
|
MEM_ALIGN(sizeof(MemoryBlock)) -
|
2003-01-16 18:47:10 +01:00
|
|
|
MEM_ALIGN(instance_size) -
|
2003-01-07 17:35:10 +01:00
|
|
|
MEM_ALIGN(sizeof(MemoryBlock)) -
|
|
|
|
MEM_ALIGN(sizeof(FreeBlocksTree::ItemList)) -
|
|
|
|
MEM_ALIGN(sizeof(MemoryBlock));
|
2002-12-14 22:43:18 +01:00
|
|
|
blk->pool = pool;
|
|
|
|
blk->used = false;
|
|
|
|
blk->last = true;
|
|
|
|
blk->type = 0;
|
|
|
|
blk->length = blockLength;
|
|
|
|
blk->prev = hdr;
|
|
|
|
BlockInfo temp = {blk, blockLength};
|
|
|
|
pool->freeBlocks.add(temp);
|
2003-01-03 17:03:30 +01:00
|
|
|
pool->updateSpare();
|
2002-12-14 22:43:18 +01:00
|
|
|
return pool;
|
|
|
|
}
|
|
|
|
|
|
|
|
void MemoryPool::deletePool(MemoryPool* pool) {
|
2003-01-21 13:19:32 +01:00
|
|
|
/* dimitr: I think we need an abstract base class or a global macro
|
|
|
|
in locks.h to avoid these architecture checks. */
|
2003-08-10 17:43:23 +02:00
|
|
|
#ifdef MULTI_THREAD
|
2003-01-18 22:45:24 +01:00
|
|
|
pool->lock.~Spinlock();
|
2003-01-17 10:59:59 +01:00
|
|
|
#else
|
2003-01-18 22:45:24 +01:00
|
|
|
pool->lock.~SharedSpinlock();
|
2003-01-17 10:59:59 +01:00
|
|
|
#endif
|
2003-01-18 22:45:24 +01:00
|
|
|
if (pool->cur_memory) *pool->cur_memory -= pool->used_memory;
|
2002-12-14 22:43:18 +01:00
|
|
|
// Delete all extents now
|
|
|
|
MemoryExtent *temp = pool->extents;
|
|
|
|
while (temp) {
|
|
|
|
MemoryExtent *next = temp->next;
|
|
|
|
external_free(temp);
|
|
|
|
temp = next;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2003-01-16 18:47:10 +01:00
|
|
|
void* MemoryPool::internal_alloc(size_t size, SSHORT type
|
2003-01-07 17:35:10 +01:00
|
|
|
#ifdef DEBUG_GDS_ALLOC
|
2003-11-07 09:06:35 +01:00
|
|
|
, const char* file, int line
|
2003-01-07 17:35:10 +01:00
|
|
|
#endif
|
|
|
|
) {
|
2002-12-14 22:43:18 +01:00
|
|
|
// Lookup a block greater or equal than size in freeBlocks tree
|
2003-01-07 17:35:10 +01:00
|
|
|
size = MEM_ALIGN(size);
|
2003-02-13 03:19:14 +01:00
|
|
|
BlockInfo blTemp = {NULL, size};
|
2003-01-18 22:45:24 +01:00
|
|
|
MemoryBlock* blk;
|
2003-02-13 03:19:14 +01:00
|
|
|
if (freeBlocks.locate(locGreatEqual,blTemp)) {
|
2002-12-14 22:43:18 +01:00
|
|
|
// Found large enough block
|
|
|
|
BlockInfo* current = &freeBlocks.current();
|
2003-11-07 09:06:35 +01:00
|
|
|
if (current->length-size < MEM_ALIGN(sizeof(MemoryBlock)) + ALLOC_ALIGNMENT)
|
|
|
|
{
|
2003-01-18 22:45:24 +01:00
|
|
|
blk = current->block;
|
2002-12-14 22:43:18 +01:00
|
|
|
// Block is small enough to be returned AS IS
|
2003-01-18 22:45:24 +01:00
|
|
|
blk->used = true;
|
|
|
|
blk->type = type;
|
2003-01-07 17:35:10 +01:00
|
|
|
#ifdef DEBUG_GDS_ALLOC
|
2003-01-18 22:45:24 +01:00
|
|
|
blk->file = file;
|
|
|
|
blk->line = line;
|
2003-01-07 17:35:10 +01:00
|
|
|
#endif
|
2002-12-14 22:43:18 +01:00
|
|
|
freeBlocks.fastRemove();
|
2004-01-28 08:50:41 +01:00
|
|
|
}
|
|
|
|
else {
|
2002-12-14 22:43:18 +01:00
|
|
|
// Cut a piece at the end of block in hope to avoid structural
|
|
|
|
// modification of free blocks tree
|
2003-01-07 17:35:10 +01:00
|
|
|
current->block->length -= MEM_ALIGN(sizeof(MemoryBlock))+size;
|
2003-01-18 22:45:24 +01:00
|
|
|
blk = (MemoryBlock *)((char*)current->block +
|
2003-01-07 17:35:10 +01:00
|
|
|
MEM_ALIGN(sizeof(MemoryBlock)) + current->block->length);
|
2002-12-14 22:43:18 +01:00
|
|
|
blk->pool = this;
|
|
|
|
blk->used = true;
|
2003-01-07 17:35:10 +01:00
|
|
|
#ifdef DEBUG_GDS_ALLOC
|
|
|
|
blk->file = file;
|
|
|
|
blk->line = line;
|
|
|
|
#endif
|
2002-12-14 22:43:18 +01:00
|
|
|
blk->last = current->block->last;
|
|
|
|
current->block->last = false;
|
|
|
|
blk->type = type;
|
|
|
|
blk->length = size;
|
|
|
|
blk->prev = current->block;
|
|
|
|
if (!blk->last)
|
2003-01-07 17:35:10 +01:00
|
|
|
((MemoryBlock *)((char*)blk + MEM_ALIGN(sizeof(MemoryBlock)) + blk->length))->prev = blk;
|
2002-12-14 22:43:18 +01:00
|
|
|
// Update tree of free blocks
|
2003-01-03 17:03:30 +01:00
|
|
|
if (!freeBlocks.getPrev() || freeBlocks.current().length < current->block->length)
|
2002-12-14 22:43:18 +01:00
|
|
|
current->length = current->block->length;
|
|
|
|
else {
|
|
|
|
// Tree needs to be modified structurally
|
2002-12-16 19:33:54 +01:00
|
|
|
#ifdef NDEBUG
|
|
|
|
freeBlocks.getNext();
|
|
|
|
#else
|
2002-12-14 22:43:18 +01:00
|
|
|
bool res = freeBlocks.getNext();
|
2003-11-04 00:59:24 +01:00
|
|
|
fb_assert(res);
|
|
|
|
fb_assert(&freeBlocks.current()==current);
|
2002-12-16 19:33:54 +01:00
|
|
|
#endif
|
2003-01-03 17:03:30 +01:00
|
|
|
MemoryBlock *block = current->block;
|
|
|
|
freeBlocks.fastRemove();
|
|
|
|
addFreeBlock(block);
|
2002-12-14 22:43:18 +01:00
|
|
|
}
|
|
|
|
}
|
2004-01-28 08:50:41 +01:00
|
|
|
}
|
|
|
|
else {
|
2002-12-14 22:43:18 +01:00
|
|
|
// If we are in a critically low memory condition look up for a block in a list
|
|
|
|
// of pending free blocks. We do not do "best fit" in this case
|
|
|
|
PendingFreeBlock *itr = pendingFree, *prev = NULL;
|
|
|
|
while (itr) {
|
2003-01-07 17:35:10 +01:00
|
|
|
MemoryBlock *temp = (MemoryBlock *)((char*)itr-MEM_ALIGN(sizeof(MemoryBlock)));
|
2002-12-14 22:43:18 +01:00
|
|
|
if (temp->length >= size) {
|
2003-01-07 17:35:10 +01:00
|
|
|
if (temp->length-size < MEM_ALIGN(sizeof(MemoryBlock))+ALLOC_ALIGNMENT) {
|
2002-12-14 22:43:18 +01:00
|
|
|
// Block is small enough to be returned AS IS
|
|
|
|
temp->used = true;
|
|
|
|
temp->type = type;
|
2003-01-07 17:35:10 +01:00
|
|
|
#ifdef DEBUG_GDS_ALLOC
|
|
|
|
temp->file = file;
|
|
|
|
temp->line = line;
|
|
|
|
#endif
|
2002-12-14 22:43:18 +01:00
|
|
|
// Remove block from linked list
|
|
|
|
if (prev)
|
|
|
|
prev->next = itr->next;
|
|
|
|
else
|
2003-01-03 17:03:30 +01:00
|
|
|
pendingFree = itr->next;
|
2003-01-18 22:45:24 +01:00
|
|
|
// We can do this w/o any locking because
|
|
|
|
// (1) -= integer operation is atomic on all current platforms
|
|
|
|
// (2) nobody will die if max_memory will be a little inprecise
|
|
|
|
used_memory += temp->length + MEM_ALIGN(sizeof(MemoryBlock));
|
|
|
|
if (cur_memory) {
|
|
|
|
*cur_memory += temp->length + MEM_ALIGN(sizeof(MemoryBlock));
|
|
|
|
if (max_memory && *max_memory < *cur_memory) *max_memory = *cur_memory;
|
|
|
|
}
|
2003-01-09 20:47:46 +01:00
|
|
|
PATTERN_FILL(itr,size,ALLOC_PATTERN);
|
2002-12-14 22:43:18 +01:00
|
|
|
return itr;
|
2004-01-28 08:50:41 +01:00
|
|
|
}
|
|
|
|
else {
|
2002-12-14 22:43:18 +01:00
|
|
|
// Cut a piece at the end of block
|
|
|
|
// We don't need to modify tree of free blocks or a list of
|
|
|
|
// pending free blocks in this case
|
2003-01-07 17:35:10 +01:00
|
|
|
temp->length -= MEM_ALIGN(sizeof(MemoryBlock))+size;
|
2003-01-18 22:45:24 +01:00
|
|
|
blk = (MemoryBlock *)((char*)temp +
|
2003-01-07 17:35:10 +01:00
|
|
|
MEM_ALIGN(sizeof(MemoryBlock)) + temp->length);
|
2002-12-14 22:43:18 +01:00
|
|
|
blk->pool = this;
|
|
|
|
blk->used = true;
|
2003-01-07 17:35:10 +01:00
|
|
|
#ifdef DEBUG_GDS_ALLOC
|
|
|
|
blk->file = file;
|
|
|
|
blk->line = line;
|
|
|
|
#endif
|
2002-12-14 22:43:18 +01:00
|
|
|
blk->last = temp->last;
|
|
|
|
temp->last = false;
|
|
|
|
blk->type = type;
|
|
|
|
blk->length = size;
|
|
|
|
blk->prev = temp;
|
|
|
|
if (!blk->last)
|
2003-01-07 17:35:10 +01:00
|
|
|
((MemoryBlock *)((char*)blk + MEM_ALIGN(sizeof(MemoryBlock)) + blk->length))->prev = blk;
|
2003-01-18 22:45:24 +01:00
|
|
|
used_memory += blk->length + MEM_ALIGN(sizeof(MemoryBlock));
|
|
|
|
if (cur_memory) {
|
|
|
|
*cur_memory += blk->length + MEM_ALIGN(sizeof(MemoryBlock));
|
|
|
|
if (max_memory && *max_memory < *cur_memory) *max_memory = *cur_memory;
|
|
|
|
}
|
|
|
|
void *result = (char *)blk + MEM_ALIGN(sizeof(MemoryBlock));
|
2003-01-09 20:47:46 +01:00
|
|
|
PATTERN_FILL(result,size,ALLOC_PATTERN);
|
|
|
|
return result;
|
2002-12-14 22:43:18 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
prev = itr;
|
|
|
|
itr = itr->next;
|
|
|
|
}
|
|
|
|
// No large enough block found. We need to extend the pool
|
2003-01-07 17:35:10 +01:00
|
|
|
size_t alloc_size = FB_MAX(MEM_ALIGN(sizeof(MemoryExtent))+MEM_ALIGN(sizeof(MemoryBlock))+size, MIN_EXTENT_SIZE);
|
2002-12-14 22:43:18 +01:00
|
|
|
MemoryExtent* extent = (MemoryExtent *)external_alloc(alloc_size);
|
2003-01-07 17:35:10 +01:00
|
|
|
if (!extent) {
|
2003-01-09 20:47:46 +01:00
|
|
|
return NULL;
|
2003-01-07 17:35:10 +01:00
|
|
|
}
|
2003-01-18 22:45:24 +01:00
|
|
|
extents_memory += alloc_size - MEM_ALIGN(sizeof(MemoryExtent));
|
2002-12-14 22:43:18 +01:00
|
|
|
extent->next = extents;
|
|
|
|
extents = extent;
|
|
|
|
|
2003-01-18 22:45:24 +01:00
|
|
|
blk = (MemoryBlock *)((char*)extent+MEM_ALIGN(sizeof(MemoryExtent)));
|
2002-12-14 22:43:18 +01:00
|
|
|
blk->pool = this;
|
|
|
|
blk->used = true;
|
|
|
|
blk->type = type;
|
2003-01-07 17:35:10 +01:00
|
|
|
#ifdef DEBUG_GDS_ALLOC
|
|
|
|
blk->file = file;
|
|
|
|
blk->line = line;
|
|
|
|
#endif
|
2002-12-14 22:43:18 +01:00
|
|
|
blk->prev = NULL;
|
2003-01-07 17:35:10 +01:00
|
|
|
if (alloc_size-size-MEM_ALIGN(sizeof(MemoryExtent))-MEM_ALIGN(sizeof(MemoryBlock)) < MEM_ALIGN(sizeof(MemoryBlock))+ALLOC_ALIGNMENT) {
|
2002-12-14 22:43:18 +01:00
|
|
|
// Block is small enough to be returned AS IS
|
|
|
|
blk->last = true;
|
2003-01-07 17:35:10 +01:00
|
|
|
blk->length = alloc_size - MEM_ALIGN(sizeof(MemoryExtent)) - MEM_ALIGN(sizeof(MemoryBlock));
|
2004-01-28 08:50:41 +01:00
|
|
|
}
|
|
|
|
else {
|
2002-12-14 22:43:18 +01:00
|
|
|
// Cut a piece at the beginning of the block
|
|
|
|
blk->last = false;
|
|
|
|
blk->length = size;
|
|
|
|
// Put the rest to the tree of free blocks
|
2003-01-07 17:35:10 +01:00
|
|
|
MemoryBlock *rest = (MemoryBlock *)((char *)blk + MEM_ALIGN(sizeof(MemoryBlock)) + size);
|
2002-12-14 22:43:18 +01:00
|
|
|
rest->pool = this;
|
|
|
|
rest->used = false;
|
|
|
|
rest->last = true;
|
2003-01-07 17:35:10 +01:00
|
|
|
rest->length = alloc_size - MEM_ALIGN(sizeof(MemoryExtent)) -
|
|
|
|
MEM_ALIGN(sizeof(MemoryBlock)) - size - MEM_ALIGN(sizeof(MemoryBlock));
|
2002-12-14 22:43:18 +01:00
|
|
|
rest->prev = blk;
|
2003-01-03 17:03:30 +01:00
|
|
|
addFreeBlock(rest);
|
2002-12-14 22:43:18 +01:00
|
|
|
}
|
|
|
|
}
|
2003-01-18 22:45:24 +01:00
|
|
|
used_memory += blk->length + MEM_ALIGN(sizeof(MemoryBlock));
|
|
|
|
if (cur_memory) {
|
|
|
|
*cur_memory += blk->length + MEM_ALIGN(sizeof(MemoryBlock));
|
|
|
|
if (max_memory && *max_memory < *cur_memory) *max_memory = *cur_memory;
|
|
|
|
}
|
|
|
|
void *result = (char*)blk+MEM_ALIGN(sizeof(MemoryBlock));
|
2002-12-14 22:43:18 +01:00
|
|
|
// Grow spare blocks pool if necessary
|
2003-01-09 20:47:46 +01:00
|
|
|
PATTERN_FILL(result,size,ALLOC_PATTERN);
|
2003-01-03 17:03:30 +01:00
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
|
|
|
void MemoryPool::addFreeBlock(MemoryBlock *blk) {
|
|
|
|
BlockInfo info = {blk, blk->length};
|
|
|
|
try {
|
|
|
|
freeBlocks.add(info);
|
2003-02-13 14:44:44 +01:00
|
|
|
} catch(const std::exception&) {
|
2003-01-03 17:03:30 +01:00
|
|
|
// Add item to the list of pending free blocks in case of critically-low memory condition
|
|
|
|
PendingFreeBlock* temp = (PendingFreeBlock *)((char *)freeBlocks.getAddErrorValue().block+
|
2003-01-07 17:35:10 +01:00
|
|
|
MEM_ALIGN(sizeof(MemoryBlock)));
|
2003-01-03 17:03:30 +01:00
|
|
|
temp->next = pendingFree;
|
|
|
|
pendingFree = temp;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void MemoryPool::removeFreeBlock(MemoryBlock *blk) {
|
|
|
|
BlockInfo info = {blk, blk->length};
|
|
|
|
if (freeBlocks.locate(info)) {
|
|
|
|
freeBlocks.fastRemove();
|
2004-01-28 08:50:41 +01:00
|
|
|
}
|
|
|
|
else {
|
2003-01-03 17:03:30 +01:00
|
|
|
// If we are in a critically-low memory condition our block could be in the
|
|
|
|
// pending free blocks list. Remove it from there
|
|
|
|
PendingFreeBlock *itr = pendingFree,
|
2003-01-07 17:35:10 +01:00
|
|
|
*temp = (PendingFreeBlock *)((char *)blk+MEM_ALIGN(sizeof(MemoryBlock)));
|
2003-01-03 17:03:30 +01:00
|
|
|
if (itr == temp)
|
|
|
|
pendingFree = itr->next;
|
|
|
|
else
|
|
|
|
{
|
|
|
|
while ( itr ) {
|
|
|
|
PendingFreeBlock *next = itr->next;
|
|
|
|
if (next==temp) {
|
|
|
|
itr->next = temp->next;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
itr = next;
|
|
|
|
}
|
2003-11-04 00:59:24 +01:00
|
|
|
fb_assert(itr); // We had to find it somewhere
|
2002-12-14 22:43:18 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2003-01-18 22:45:24 +01:00
|
|
|
void MemoryPool::free_blk_extent(MemoryBlock *blk) {
|
|
|
|
MemoryExtent *extent = (MemoryExtent *)((char *)blk-MEM_ALIGN(sizeof(MemoryExtent)));
|
|
|
|
MemoryExtent *itr = extents;
|
|
|
|
if (extents == extent)
|
|
|
|
extents = extents->next;
|
|
|
|
else
|
|
|
|
{
|
|
|
|
while ( itr ) {
|
|
|
|
MemoryExtent *next = itr->next;
|
|
|
|
if (next==extent) {
|
|
|
|
itr->next = extent->next;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
itr = next;
|
|
|
|
}
|
2003-11-04 00:59:24 +01:00
|
|
|
fb_assert(itr); // We had to find it somewhere
|
2003-01-18 22:45:24 +01:00
|
|
|
}
|
|
|
|
extents_memory -= blk->length + MEM_ALIGN(sizeof(MemoryBlock));
|
|
|
|
external_free(extent);
|
|
|
|
}
|
|
|
|
|
2003-01-16 18:47:10 +01:00
|
|
|
void MemoryPool::deallocate(void *block) {
|
2003-01-17 10:59:59 +01:00
|
|
|
if (!block) return;
|
2003-01-10 22:37:18 +01:00
|
|
|
lock.enter();
|
2003-01-07 17:35:10 +01:00
|
|
|
MemoryBlock *blk = (MemoryBlock *)((char*)block - MEM_ALIGN(sizeof(MemoryBlock))), *prev;
|
2003-11-04 00:59:24 +01:00
|
|
|
fb_assert(blk->used);
|
|
|
|
fb_assert(blk->pool==this);
|
2003-01-18 22:45:24 +01:00
|
|
|
used_memory -= blk->length + MEM_ALIGN(sizeof(MemoryBlock));
|
|
|
|
if (cur_memory) *cur_memory -= blk->length + MEM_ALIGN(sizeof(MemoryBlock));
|
2002-12-14 22:43:18 +01:00
|
|
|
// Try to merge block with preceding free block
|
|
|
|
if ((prev = blk->prev) && !prev->used) {
|
2003-01-03 17:03:30 +01:00
|
|
|
removeFreeBlock(prev);
|
2003-01-07 17:35:10 +01:00
|
|
|
prev->length += blk->length + MEM_ALIGN(sizeof(MemoryBlock));
|
2003-01-03 17:03:30 +01:00
|
|
|
|
|
|
|
MemoryBlock *next = NULL;
|
|
|
|
if (blk->last) {
|
|
|
|
prev->last = true;
|
2004-01-28 08:50:41 +01:00
|
|
|
}
|
|
|
|
else {
|
2003-01-07 17:35:10 +01:00
|
|
|
next = (MemoryBlock *)((char *)blk+MEM_ALIGN(sizeof(MemoryBlock))+blk->length);
|
2003-01-03 17:03:30 +01:00
|
|
|
if (next->used) {
|
|
|
|
next->prev = prev;
|
|
|
|
prev->last = false;
|
2004-01-28 08:50:41 +01:00
|
|
|
}
|
|
|
|
else {
|
2003-01-03 17:03:30 +01:00
|
|
|
// Merge next block too
|
|
|
|
removeFreeBlock(next);
|
2003-01-07 17:35:10 +01:00
|
|
|
prev->length += next->length + MEM_ALIGN(sizeof(MemoryBlock));
|
2003-01-03 17:03:30 +01:00
|
|
|
prev->last = next->last;
|
2002-12-14 22:43:18 +01:00
|
|
|
if (!next->last)
|
2003-01-07 17:35:10 +01:00
|
|
|
((MemoryBlock *)((char *)next+MEM_ALIGN(sizeof(MemoryBlock))+next->length))->prev = prev;
|
2002-12-14 22:43:18 +01:00
|
|
|
}
|
|
|
|
}
|
2003-01-09 20:47:46 +01:00
|
|
|
PATTERN_FILL((char*)prev+MEM_ALIGN(sizeof(MemoryBlock)),prev->length,FREE_PATTERN);
|
2003-01-18 22:45:24 +01:00
|
|
|
if (!prev->prev && prev->last)
|
|
|
|
free_blk_extent(prev);
|
|
|
|
else
|
|
|
|
addFreeBlock(prev);
|
2004-01-28 08:50:41 +01:00
|
|
|
}
|
|
|
|
else {
|
2003-01-03 17:03:30 +01:00
|
|
|
MemoryBlock *next;
|
|
|
|
// Mark block as free
|
2002-12-14 22:43:18 +01:00
|
|
|
blk->used = false;
|
2003-01-03 17:03:30 +01:00
|
|
|
// Try to merge block with next free block
|
|
|
|
if (!blk->last &&
|
2003-01-07 17:35:10 +01:00
|
|
|
!(next = (MemoryBlock *)((char*)blk+MEM_ALIGN(sizeof(MemoryBlock))+blk->length))->used)
|
2003-01-03 17:03:30 +01:00
|
|
|
{
|
|
|
|
removeFreeBlock(next);
|
2003-01-07 17:35:10 +01:00
|
|
|
blk->length += next->length + MEM_ALIGN(sizeof(MemoryBlock));
|
2003-01-03 17:03:30 +01:00
|
|
|
blk->last = next->last;
|
|
|
|
if (!next->last)
|
2003-01-07 17:35:10 +01:00
|
|
|
((MemoryBlock *)((char *)next+MEM_ALIGN(sizeof(MemoryBlock))+next->length))->prev = blk;
|
2002-12-14 22:43:18 +01:00
|
|
|
}
|
2003-01-18 22:45:24 +01:00
|
|
|
PATTERN_FILL(block,blk->length,FREE_PATTERN);
|
|
|
|
if (!blk->prev && blk->last)
|
|
|
|
free_blk_extent(blk);
|
|
|
|
else
|
|
|
|
addFreeBlock(blk);
|
2002-12-14 22:43:18 +01:00
|
|
|
}
|
2003-01-09 20:47:46 +01:00
|
|
|
if (needSpare) updateSpare();
|
2003-01-10 22:37:18 +01:00
|
|
|
lock.leave();
|
2003-01-10 13:27:57 +01:00
|
|
|
}
|
|
|
|
|
2002-12-14 22:43:18 +01:00
|
|
|
} /* namespace Firebird */
|
2003-01-07 17:35:10 +01:00
|
|
|
|
2003-01-18 22:45:24 +01:00
|
|
|
#ifndef TESTING_ONLY
|
|
|
|
|
2003-01-16 18:47:10 +01:00
|
|
|
Firebird::MemoryPool* getDefaultMemoryPool() {
|
|
|
|
if (!Firebird::processMemoryPool) Firebird::processMemoryPool = MemoryPool::createPool();
|
|
|
|
return Firebird::processMemoryPool;
|
|
|
|
}
|
|
|
|
|
2003-11-03 03:05:14 +01:00
|
|
|
#if !defined(__GNUC__) || defined(MINGW)
|
2003-10-27 23:27:30 +01:00
|
|
|
|
2003-08-11 13:21:21 +02:00
|
|
|
void* operator new(size_t s) THROW_BAD_ALLOC {
|
2003-01-07 17:35:10 +01:00
|
|
|
#if defined(DEV_BUILD)
|
2003-05-07 13:13:55 +02:00
|
|
|
// Do not complain here. It causes client tools to crash on Red Hat 8.0
|
|
|
|
// fprintf(stderr, "You MUST allocate all memory from a pool. Don't use the default global new().\n");
|
2003-01-07 17:35:10 +01:00
|
|
|
#endif // DEV_BUILD
|
2003-02-04 12:18:17 +01:00
|
|
|
// return getDefaultMemoryPool()->calloc(s, 0
|
|
|
|
return getDefaultMemoryPool()->allocate(s, 0
|
2003-01-07 17:35:10 +01:00
|
|
|
#ifdef DEBUG_GDS_ALLOC
|
|
|
|
,__FILE__,__LINE__
|
|
|
|
#endif
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
2003-08-11 13:21:21 +02:00
|
|
|
void* operator new[](size_t s) THROW_BAD_ALLOC {
|
2003-01-07 17:35:10 +01:00
|
|
|
#if defined(DEV_BUILD)
|
2003-05-07 13:13:55 +02:00
|
|
|
// Do not complain here. It causes client tools to crash on Red Hat 8.0
|
|
|
|
// fprintf(stderr, "You MUST allocate all memory from a pool. Don't use the default global new[]().\n");
|
2003-01-07 17:35:10 +01:00
|
|
|
#endif // DEV_BUILD
|
2003-02-04 12:18:17 +01:00
|
|
|
// return getDefaultMemoryPool()->->calloc(s, 0
|
|
|
|
return getDefaultMemoryPool()->allocate(s, 0
|
2003-01-07 17:35:10 +01:00
|
|
|
#ifdef DEBUG_GDS_ALLOC
|
|
|
|
,__FILE__,__LINE__
|
|
|
|
#endif
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
2003-01-16 18:47:10 +01:00
|
|
|
void operator delete(void* mem) throw() {
|
|
|
|
Firebird::MemoryPool::globalFree(mem);
|
|
|
|
}
|
|
|
|
|
|
|
|
void operator delete[](void* mem) throw() {
|
|
|
|
Firebird::MemoryPool::globalFree(mem);
|
|
|
|
}
|
|
|
|
|
2003-01-07 17:35:10 +01:00
|
|
|
#endif
|
2003-10-27 23:27:30 +01:00
|
|
|
|
|
|
|
#endif
|