//============================================================================= //
// Copyright : (c) 2004 by Dzenis Softic /
http://www.dzeni.com
//
// Filename :
//
// Description:
//
// Company : Seenetix D.O.O.
//
// Authors :
//
// $Id$
// //=============================================================================
#ifndef VMP_BUFFERED_MEM_MANAGER_H
#define VMP_BUFFERED_MEM_MANAGER_H
#include <map>
#include <list>
#include <vector>
#include <utility>
#include <stdio.h>
#include <pthread.h>
#include <cstdlib>
#include <new>
#include <stdlib.h>
#include "vmpthreads.h"
/* use new allocator */
#define MALLOCATOR
#if !defined(MALLOCATOR)
#include "vmp_malloc_allocator.h"
#else
#include "vmp_mallocator.h"
#endif
class SpecAllocator
{
public:
SpecAllocator(size_t buffsz,size_t nodesz,bool threadmodel);
~SpecAllocator();
void *AcquireBuffer(SpecAllocator **ppnode,size_t *freemem);
size_t ReleaseBuffer(void *buf);
size_t ChunkSize() {return bufsz_;}
protected:
bool LostFound(void *first,size_t nodesz);
size_t AcquireMemory();
size_t ReleaseMemory(size_t size);
struct bigBufferNode_t
{
bigBufferNode_t *next;
};
bigBufferNode_t *first_;
size_t bufsz_; // mem unit size
size_t nodesz_; // preallocate units
size_t used_; // allocated memory
bool multi_; // thread model
typedef std::pair<size_t,bigBufferNode_t*> mapvalue_t;
typedef std::pair<pthread_t, mapvalue_t> value_t;
#if !defined(MALLOCATOR)
typedef std::vector<value_t, TMallocAllocator<value_t> > map_t;
#else
typedef std::vector<value_t, TMallocator<value_t> > map_t;
#endif
map_t foreigners_;
typedef std::pair<size_t,void *> listvalue_t;
#if !defined(MALLOCATOR)
typedef std::vector<listvalue_t,TMallocAllocator<listvalue_t> > list_t; // memory allocated
#else
typedef std::vector<listvalue_t,TMallocator<listvalue_t> > list_t; // memory allocated
#endif
list_t amem_; // memory allocated
RecursiveMutex lostLock_;
private:
void hlpDestroy();
static size_t &header_size() {
static size_t _header_size= (sizeof(pthread_t) + 3) & ~3;
return _header_size;
}
// static size_t header_size_;
SpecAllocator(const SpecAllocator&);
SpecAllocator& operator=(const SpecAllocator&);
friend class MemManager;
friend class GenAllocator;
};
class GenAllocator
{
public:
static void setThreadModel(bool);
template<int ObjectSize> static GenAllocator &instance() {
setupThreadModel();
if(multi()) {
pthread_once(&mem_key_once(),&mem_key_alloc);
if(!pthread_getspecific(mem_key())) {
#if !defined(MALLOCATOR)
void *tmp= malloc(sizeof(map_t));
#else
void *tmp= Mallocator::alloc(sizeof(map_t));
#endif
new(tmp)map_t();
pthread_setspecific(mem_key(),tmp);
}
map_t &m=
*static_cast<map_t *>(pthread_getspecific(mem_key()));
GenAllocator *a= 0;
map_t::iterator itr= m.find(ObjectSize);
if(itr != m.end()) a= itr->second;
else {
#if !defined(MALLOCATOR)
void *tmp= malloc(sizeof(GenAllocator));
#else
void *tmp= Mallocator::alloc(sizeof(GenAllocator));
#endif
new(tmp)GenAllocator(ObjectSize);
a= static_cast<GenAllocator*>(tmp);
m[ObjectSize]= a;
}
return *a;
}
else {
static GenAllocator *a= 0;
if(!a) {
#if !defined(MALLOCATOR)
void *tmp= malloc(sizeof(GenAllocator));
#else
void *tmp= Mallocator::alloc(sizeof(GenAllocator));
#endif
new(tmp)GenAllocator(ObjectSize);
a= static_cast<GenAllocator*>(tmp);
}
return *a;
}
}
GenAllocator(size_t bufsz);
GenAllocator(size_t ibufsz,size_t nodesz);
~GenAllocator();
void *Alloc(size_t sz);
void Free(void *p,size_t sz);
protected:
static void setupThreadModel();
#if !defined(MALLOCATOR)
typedef std::map<const size_t,GenAllocator*,std::less<const size_t>,TMallocAllocator<std::pair<const size_t,GenAllocator*> > > map_t;
#else
typedef std::map<const size_t,GenAllocator*,std::less<const size_t>,TMallocator<std::pair<const size_t,GenAllocator*> > > map_t;
#endif
size_t bufsz_;
size_t maxfreememory_; // max free memory which can be holded by manager
size_t freememory_; // current free memory holded by manager
SpecAllocator allocator_;
static bool &multi() {
static bool _multi= true;
return _multi;
}
//static bool multi_;
static void destroy();
static void destroy(void *);
static void mem_key_alloc();
// static void set_thread_model(); can't see implementation
static pthread_key_t &mem_key() {
static pthread_key_t _mem_key;
return _mem_key;
}
//static pthread_key_t mem_key_;
static pthread_once_t &mem_key_once() {
static pthread_once_t _mem_key_once= PTHREAD_ONCE_INIT;
return _mem_key_once;
}
//static pthread_once_t mem_key_once_;
/*
static pthread_once_t &thread_model_once() {
static pthread_once_t _thread_model_once= PTHREAD_ONCE_INIT;
return _thread_model_once;
}
*/
// static pthread_once_t thread_model_once_;
private:
GenAllocator &operator=(const GenAllocator &);
GenAllocator(const GenAllocator &);
};
#ifdef DEBUG_BUFFER_STACK
#define REGISTER_ALLOC(ObjectType) \
static void *operator new(size_t sz) { \
printf("%s::new(size_t sz= %d)\n",#ObjectType,sz); \
return GenAllocator::instance<sizeof(ObjectType)>().Alloc(sz); } \
static void *operator new[](size_t sz) { \
printf("%s::new[](size_t sz= %d)(sizeof(%s)= %d)\n", \
#ObjectType,sz,#ObjectType,sizeof(ObjectType)); \
void *tmp; \
MemManager::instance().AcquireBuffer(sz,&tmp); \
return tmp; } \
static void operator delete(void *p,size_t sz) { \
printf("%s::delete(void *ptr,size_t sz= %d)\n",#ObjectType,sz); \
return GenAllocator::instance<sizeof(ObjectType)>().Free(p,sz); } \
static void operator delete[](void *p,size_t sz) { \
printf("%s::delete[](void *,size_t sz= %d)(sizeof(%s)= %d)\n", \
#ObjectType,sz,#ObjectType,sizeof(ObjectType)); \ MemManager::instance().ReleaseBuffer(p,sz); }
#else
#define REGISTER_ALLOC(ObjectType) \
static void *operator new(size_t sz) { \
return GenAllocator::instance<sizeof(ObjectType)>().Alloc(sz); } \
static void *operator new[](size_t sz) { \
void *tmp; \
MemManager::instance().AcquireBuffer(sz,&tmp); \
return tmp; } \
static void operator delete(void *p,size_t sz) { \
return GenAllocator::instance<sizeof(ObjectType)>().Free(p,sz); } \
static void operator delete[](void *p,size_t sz) { \ MemManager::instance().ReleaseBuffer(p,sz); }
#define REGISTER_GEN_ALLOC \
static void *operator new(size_t sz) { \
void *tmp; \
MemManager::instance().AcquireBuffer(sz,&tmp); \
return tmp; } \
static void *operator new[](size_t sz) { \
void *tmp; \
MemManager::instance().AcquireBuffer(sz,&tmp); \
return tmp; } \
static void operator delete(void *p,size_t sz) { \ MemManager::instance().ReleaseBuffer(p,sz); } \
static void operator delete[](void *p,size_t sz) { \ MemManager::instance().ReleaseBuffer(p,sz); }
#endif
#define USE_NEW_INTERNAL_STATE
//#define MM_ASSUME_PTHREAD_INITIALIZATION // mind libpthread initialization
class MemManager
{
public:
static void setThreadModel(bool multi);
static MemManager& instance();
~MemManager();
int AcquireBuffer(size_t sz,void **pbuf,SpecAllocator **pnode);
size_t AcquireBuffer(size_t sz,void **pbuf);
size_t ReallocateBuffer(size_t sz, void **pbuf);
void ReleaseBuffer(void *buf,SpecAllocator*);
void ReleaseBuffer(void *buf,size_t sz);
size_t MaxSize();
static bool &multi()
{
static bool _multi= true;
return _multi;
}
// static bool multi_;
/*
static bool &recursion() {
static bool _recursion= false;
return _recursion;
}
*/
static bool &lib_pthread_initialized() {
#ifdef MM_ASSUME_PTHREAD_INITIALIZATION
/**
in case we need to be aware of libpthread during initialization process
start assuming libpthread is not initialized. While flag isn't set
MemManager interface shouldn't be used. When libpthread is initialized
user may set this flag so that memory management is done through
MemManager interface.
*/
static bool _pthread_initialized= false;
#else
/**
libpthread doesn't use dynamic memory during initialization. We may
start using MemMemory interface from the very begining...
*/
static bool _pthread_initialized= true;
#endif
return _pthread_initialized;
}
protected:
MemManager(pthread_t);
bool LostFound(size_t bufsz,void *first,size_t inodesz);
SpecAllocator* findSpecAllocator(size_t sz);
#ifndef USE_NEW_INTERNAL_STATE
void InstallNode(size_t,size_t);
#endif
size_t ReleaseMemory(size_t sz);
void InstallNodes(bool);
static void setupThreadModel();
#ifndef USE_NEW_INTERNAL_STATE
// definition of the internal state: allocator info container
typedef std::pair<size_t,SpecAllocator *> content_t;
#if !defined(MALLOCATOR)
typedef std::vector<content_t,TMallocAllocator<content_t> > container_t; #else
typedef std::vector<content_t,TMallocator<content_t> > container_t;
#endif
static bool cmp(const content_t &,const content_t &);
container_t cont_;
#endif
static MemManager *manager_;
//static bool multi_;
static void destroy();
static void destroy(void *);
static void mem_key_alloc();
static pthread_key_t &mem_key()
{
static pthread_key_t _mem_key;
return _mem_key;
}
static pthread_once_t &mem_key_once()
{
static pthread_once_t _mem_key_once= PTHREAD_ONCE_INIT;;
return _mem_key_once;
}
//static pthread_key_t mem_key_;
//static pthread_once_t mem_key_once_;
#ifdef USE_NEW_INTERNAL_STATE
struct SegInfo
{
SegInfo(size_t segbase,size_t segend,size_t cdiff):
segbase_(segbase),segend_(segend),chunkdiff_(cdiff){}
size_t segbase_;
size_t segend_;
size_t chunkdiff_;
#if !defined(MALLOCATOR)
typedef std::vector<SpecAllocator*,TMallocAllocator<SpecAllocator*> > v_t; #else
typedef std::vector<SpecAllocator*,TMallocator<SpecAllocator*> > v_t; #endif
v_t v_;
static bool cmp(const SegInfo &lhs,const SegInfo &rhs) {
return lhs.segend_<rhs.segend_;
}
};
#if !defined(MALLOCATOR)
typedef std::vector<SegInfo,TMallocAllocator<SegInfo> > seginfo_t;
#else
typedef std::vector<SegInfo,TMallocator<SegInfo> > seginfo_t;
#endif
seginfo_t seginfos_;
static size_t &maxsize()
{
static size_t _maxsize= 65536-sizeof(size_t);
return _maxsize;
}
static size_t &segmentsize()
{
static size_t _segmentsize= 12;
return _segmentsize;
}
//static size_t maxsize_;
//static size_t segmentsize_;
size_t maxfreememory_; // max free memory which can be holded by manager
size_t freememory_; // current free memory holded by manager
size_t mrcnt_;
pthread_t mytid_;
#endif
/*
static MemManager *&init_manager() {
static MemManager *_init_manager= 0;
return _init_manager;
}
*/
#ifdef MM_ASSUME_PTHREAD_INITIALIZATION
/**
define global static object which will tell us when lib's initialization
is finished. Start using MemManager interface by switching on init flag.
*/
static void lib_pthread_init_finished();
class PthreadInitializer {
public:
PthreadInitializer()
{
if(__malloc_hook && __free_hook)
{
void* p = __malloc_hook(16,0);
__free_hook(p,0);
}
else perror("__malloc__hook || __free_hook NULL!");
MemManager::lib_pthread_init_finished();
}
~PthreadInitializer() {
MemManager::lib_pthread_initialized()= false;
#ifdef MALLOCATOR
Mallocator::set_lock(false);
#endif
}
};
static PthreadInitializer pthread_initializer_;
friend class PthreadInitializer;
#endif
friend class MemManagerTable;
};
struct MemManagerPrim{
void* operator new(size_t s)throw (std::bad_alloc);
inline void* operator new[](size_t s)throw (std::bad_alloc)
{
return MemManagerPrim::operator new(s);
}
void operator delete(void* p)throw ();
inline void operator delete[](void* p)throw ()
{
MemManagerPrim::operator delete(p);
}
static void* malloc(size_t s);
static void* calloc(size_t n, size_t s);
static void* realloc(void* p, size_t s);
static void free(void* p);
};
// application callbacks
extern "C"
{
void setupMemoryThreadModel();
void configureMemManager(MemManager *);
}
#endif
//============================================================================= // History:
//
// $Log$
// Revision 1.26 2009/07/17 16:16:34 luska
// library repackaged
//
// Revision 1.25 2006/01/19 17:08:14 virtus
// ported to openbsd
//
// Revision 1.24 2005/08/18 17:54:34 luska
// ASSUME_PTHREAD_INITIALIZATION switch added
//
// Revision 1.23 2005/08/04 18:08:24 bmaxa
// *** empty log message ***
//
// Revision 1.22 2005/08/01 22:41:31 luska
// hm, while initializing pthread use Mallocator interface
//
// Revision 1.21 2005/08/01 21:37:32 luska
// reset Mallocator's lock flag in PthreadInitializer's destructor
//
// Revision 1.20 2005/08/01 21:28:37 vmp
// destructor for PthreadInitializer resets lib_pthread_initialized flag
//
// Revision 1.19 2005/08/01 20:43:22 luska
// only lock memory banks if pthread init is finished
//
// Revision 1.18 2005/08/01 18:19:30 luska
// all statics wrapped
//
// Revision 1.17 2005/07/05 18:49:38 build
// resolved namespace and const map key issue
//
// Revision 1.16 2005/01/12 12:59:14 luska
// nasty little fixed
//
// Revision 1.15 2004/10/25 18:15:10 bmaxa
// new,delete
//
// Revision 1.14 2004/10/25 16:56:34 bmaxa
// added malloc....
//
// Revision 1.13 2004/10/19 20:01:00 bmaxa
// ReallocBuffer and findSpecAllocator added
//
// Revision 1.12 2004/10/15 21:58:43 luska
// *** empty log message ***
//
// Revision 1.11 2004/10/05 19:31:20 bmaxa
// typo's
//
// Revision 1.10 2004/10/04 19:34:09 bmaxa
// suited for mallocator
//
// Revision 1.9 2004/09/21 18:53:09 bmaxa
// size_t instead of int
//
// Revision 1.8 2004/09/20 16:11:43 bmaxa
// list,map into vector
//
// Revision 1.7 2004/09/16 19:36:00 luska
// releasing memory bug fixed
//
// Revision 1.6 2004/09/16 18:36:41 luska
// allocator interface changed due to memory accounting
//
// Revision 1.5 2004/09/16 16:42:10 bmaxa
// corrections...
//
// Revision 1.4 2004/09/15 17:55:57 luska
// *** empty log message ***
//
// Revision 1.3 2004/09/15 17:15:19 luska
// REGISTER_GEN_ALLOC
//
// Revision 1.2 2004/09/13 16:25:00 luska
// new internal state defined
//
// Revision 1.1 2004/09/09 21:11:27 luska
// first implementation
//
//
//
//
// //=============================================================================
/** and now cpp */ //============================================================================= //
// Copyright : (c) 2004 by Dzenis Softic /
http://www.dzeni.com
//
// Filename :
//
// Description:
//
// Company : Seenetix D.O.O.
//
// Authors :
//
// $Id$
// //=============================================================================
#include <algorithm>
#include <exception>
#include <limits.h>
#include <cstring>
#include "vmp_buffered_mem_manager.h"
#ifdef USE_NEW_INTERNAL_STATE
#include <math.h>
#endif
#include <assert.h>
#define STORAGE_SIZE 524288
#define MT_PREALLOCATE_UNITS 32
#define ST_PREALLOCATE_UNITS 32
class MemManagerTable
{
public:
static MemManagerTable &instance();
void Insert(pthread_t,MemManager *);
void Erase(pthread_t);
bool LostFound(pthread_t tid,size_t bufsz,void *first,size_t nodesz);
MemManager *FindManager(pthread_t tid);
protected:
#if !defined(MALLOCATOR)
typedef std::map<const pthread_t,MemManager *,std::less<const pthread_t>,TMallocAllocator<std::pair<const pthread_t,MemManager *> > > map_t;
#else
typedef std::map<const pthread_t,MemManager *,std::less<const pthread_t>,TMallocator<std::pair<const pthread_t,MemManager *> > > map_t;
#endif
map_t table_;
RecursiveMutex lock_;
static void initialize();
static void destroy();
static MemManagerTable *instance_;
static pthread_once_t &init_once() {
static pthread_once_t _init_once= (pthread_once_t)PTHREAD_ONCE_INIT;
return _init_once;
}
//static pthread_once_t init_once_;
};
//size_t SpecAllocator::header_size_= (sizeof(pthread_t) + 3) & ~3;
SpecAllocator::SpecAllocator(size_t bufsz,size_t nodesz,bool threadmodel):
first_(0)
,bufsz_(bufsz)
,nodesz_(nodesz)
,used_(0)
,multi_(threadmodel)
{
}
void
SpecAllocator::hlpDestroy()
{
while(first_) {
bigBufferNode_t *tmp= first_->next;
#if !defined(MALLOCATOR)
free((char *)first_ - header_size_);
#else
size_t bufsz = bufsz_;
if(bufsz_ < sizeof(bigBufferNode_t)) bufsz= sizeof(bigBufferNode_t);
Mallocator::free((char *)first_ - header_size(),bufsz + header_size()); #endif
first_= tmp;
}
}
SpecAllocator::~SpecAllocator()
{
if(multi_) {
hlpDestroy();
while(!amem_.empty()) {
first_= static_cast<bigBufferNode_t *>(amem_.back().second);
hlpDestroy();
amem_.pop_back();
}
for(map_t::iterator itr= foreigners_.begin();itr!=foreigners_.end();++itr){
if(!MemManagerTable::instance().LostFound(itr->first,bufsz_,itr->second.second,itr->second.first)) {
first_= itr->second.second;
hlpDestroy();
}
}
}
else {
for(list_t::iterator i= amem_.begin();i != amem_.end();++i) {
#if !defined(MALLOCATOR)
free(i->second);
#else
size_t bufsz = bufsz_;
if(bufsz_ < sizeof(bigBufferNode_t)) bufsz= sizeof(bigBufferNode_t);
Mallocator::free(i->second,bufsz*nodesz_);
#endif
}
}
}
bool
SpecAllocator::LostFound(void *first,size_t nodesz)
{
AutoLock guard(lostLock_);
amem_.push_back(std::make_pair(nodesz,static_cast<bigBufferNode_t *>(first)));
return true;
}
size_t
SpecAllocator::AcquireMemory()
{
if(multi_) {
// use foreigners if any
map_t::reverse_iterator mitr= foreigners_.rbegin();
if(mitr != foreigners_.rend())
{
first_= mitr->second.second;
size_t tmp= mitr->second.first;
foreigners_.pop_back(); // foreigners_.erase(mitr);
// there is no reverse iterator version of erase ?!
return tmp*bufsz_;
}
// use lost if any
{
AutoLock guard(lostLock_);
if(!amem_.empty())
{
first_= static_cast<bigBufferNode_t*>(amem_.back().second);
size_t tmp= amem_.back().first;
amem_.pop_back();
return tmp*bufsz_;
}
}
// have no luck: must malloc
bigBufferNode_t *tmp= (bigBufferNode_t*)&first_;
bool b= false;
size_t bufsz = bufsz_;
if(bufsz_ < sizeof(bigBufferNode_t)) bufsz= sizeof(bigBufferNode_t);
size_t nodesAcquired = 0;
for(size_t i= 0;i<nodesz_;++i,++nodesAcquired)
{
#if !defined(MALLOCATOR)
void *p= malloc(bufsz+header_size());
#else
void* p= Mallocator::alloc(bufsz+header_size());
#endif
if(!p)
{
if(b) break;
else throw std::bad_alloc();
}
*(pthread_t *)p= pthread_self();
p = (char*)p+header_size();
b= true;
tmp->next= static_cast<bigBufferNode_t*>(p);
tmp= tmp->next;
}
tmp->next= 0;
return nodesAcquired*bufsz_;
}
else {
// single thread model
size_t bufsz = bufsz_;
if(bufsz_ < sizeof(bigBufferNode_t)) bufsz= sizeof(bigBufferNode_t);
#if !defined(MALLOCATOR)
void *mem= malloc(bufsz*nodesz_);
#else
void *mem= Mallocator::alloc(bufsz*nodesz_);
#endif
if(!mem)throw std::bad_alloc();
char *ptr= static_cast<char *>(mem);
first_= static_cast<bigBufferNode_t *>(mem);
bigBufferNode_t *tmp= first_;
for(size_t i= 1;i<nodesz_;++i) {
ptr+= bufsz;
tmp->next= (bigBufferNode_t*)(ptr);
tmp= tmp->next;
}
tmp->next= 0;
amem_.push_back(std::make_pair(nodesz_,mem));
return nodesz_*bufsz_;
}
}
size_t
SpecAllocator::ReleaseMemory(size_t size)
{
if(!size)return 0;
size_t memReleased=0;
if(multi_) {
if(first_) {
while(first_->next && memReleased<size) {
typeof(first_) tmp = first_;
first_ = first_->next;
#if !defined(MALLOCATOR)
free((char *)tmp - header_size());
#else
size_t bufsz = bufsz_;
if(bufsz_ < sizeof(bigBufferNode_t)) bufsz= sizeof(bigBufferNode_t);
Mallocator::free((char *)tmp - header_size(),bufsz + header_size()); #endif
memReleased+=bufsz_;
}
if(!(memReleased<size))return memReleased;
}
{
AutoLock guard(lostLock_);
while(!amem_.empty() && memReleased<size) {
typeof(first_) tmp = static_cast<typeof(first_)>(amem_.back().second);
size_t cnt= amem_.back().first;
while(tmp && memReleased<size) {
typeof(tmp) tmp1 = tmp;
tmp = tmp->next;
#if !defined(MALLOCATOR)
free((char *)tmp1 - header_size());
#else
size_t bufsz = bufsz_;
if(bufsz_ < sizeof(bigBufferNode_t)) bufsz= sizeof(bigBufferNode_t);
Mallocator::free((char *)tmp1 - header_size(),bufsz + header_size()); #endif
memReleased+=bufsz_;
--cnt;
}
if(!tmp)amem_.pop_back();
else amem_.back()= std::make_pair(cnt,tmp);
}
}
}
else {
//single thread
while(amem_.size()>1) {
#if !defined(MALLOCATOR)
free(amem_.back().second);
#else
size_t bufsz = bufsz_;
if(bufsz_ < sizeof(bigBufferNode_t)) bufsz= sizeof(bigBufferNode_t);
Mallocator::free(amem_.back().second,bufsz*nodesz_);
#endif
amem_.pop_back();
}
void *mem= amem_.back().second;
char *ptr= static_cast<char *>(mem);
first_= static_cast<bigBufferNode_t *>(mem);
bigBufferNode_t *tmp= first_;
for(size_t i= 1;i<nodesz_;++i) {
ptr+= bufsz_;
tmp->next= (bigBufferNode_t*)(ptr);
tmp= tmp->next;
}
tmp->next= 0;
/*
we don't use mem released info in single thread model
*/
}
return memReleased;
}
void *
SpecAllocator::AcquireBuffer(SpecAllocator **ppa,size_t *freemem)
{
*freemem= 0;
if(!first_) *freemem= AcquireMemory();
void *mem= first_;
first_= first_->next;
*ppa= this;
if(!multi_)
{
used_+=bufsz_;
}
return mem;
}
size_t
SpecAllocator::ReleaseBuffer(void *buf)
{
bigBufferNode_t *tmp= static_cast<bigBufferNode_t *>(buf);
if(multi_) {
char *tmp1= static_cast<char *>(buf) - header_size();
pthread_t tid= *(pthread_t *)tmp1;
if(tid != pthread_self()) {
size_t acqSize = 0;
// this chunk is not allocated by this node
//printf("SpecAllocator::ReleaseBuffer(%u,%u): this chunk is not allocated by this node but in thread %u\n",bufsz_,pthread_self(),tid);
map_t::iterator itr= foreigners_.begin();
for(;itr!=foreigners_.end();++itr)
{
if(itr->first == tid)break;
}
if(itr != foreigners_.end()) {
itr->second.first++;
tmp->next= itr->second.second;
itr->second.second= tmp;
// at last, check the magic number
if(itr->second.first > nodesz_) {
// be nice
if(!MemManagerTable::instance().LostFound(tid,
bufsz_,
itr->second.second,
itr->second.first)) {
// well, no one at home
tmp= itr->second.second;
bigBufferNode_t *tmp2= 0;
while(tmp) {
tmp1= (char *)tmp - header_size();
*(pthread_t *)tmp1= pthread_self();
tmp2= tmp;
tmp= tmp->next;
}
tmp2->next= first_;
first_= itr->second.second;
acqSize = itr->second.first*bufsz_;
}
foreigners_.erase(itr);
}
}
else {
tmp->next= 0;
foreigners_.push_back(std::make_pair(tid,std::make_pair(1,tmp)));
}
return acqSize;
}
}
tmp->next= first_;
first_= tmp;
if(!multi_)
{
used_-=bufsz_;
if(used_ == 0)ReleaseMemory(1);
return bufsz_;
}
else
{
return bufsz_;
}
}
//pthread_key_t GenAllocator::mem_key_;
//pthread_once_t GenAllocator::mem_key_once_= PTHREAD_ONCE_INIT;
//bool GenAllocator::multi_= true;
static pthread_once_t &thread_model_once()
{
static pthread_once_t _thread_model_once= (pthread_once_t)PTHREAD_ONCE_INIT;
return _thread_model_once;
}
#pragma weak setupMemoryThreadModel
static void setup_thread_model()
{
if(setupMemoryThreadModel) setupMemoryThreadModel();
}
GenAllocator::GenAllocator(size_t sz)
:
bufsz_(sz)
,maxfreememory_(32*MT_PREALLOCATE_UNITS)
,freememory_(0)
,allocator_(sz,multi()?MT_PREALLOCATE_UNITS:ST_PREALLOCATE_UNITS,multi())
{
}
GenAllocator::GenAllocator(size_t sz,size_t cnt)
:
bufsz_(sz)
,maxfreememory_(32*MT_PREALLOCATE_UNITS)
,freememory_(0)
,allocator_(sz,cnt,multi())
{
}
GenAllocator::~GenAllocator()
{
}
void
GenAllocator::setupThreadModel()
{
//printf("GenAllocator::setupThreadModel()\n");
pthread_once(&thread_model_once(),&setup_thread_model);
}
void
GenAllocator::setThreadModel(bool multithread)
{
static bool called= false;
assert(!called);
multi()= multithread;
called= true;
}
void *
GenAllocator::Alloc(size_t sz)
{
#ifdef DEBUG_BUFFER_STACK
printf("GenAllocator[%u]::Alloc(int sz= %u)\n",bufsz_,sz);
#endif
if(sz != bufsz_) {
#if !defined(MALLOCATOR)
void *p= malloc(sz);
#else
void *p = Mallocator::alloc(sz);
#endif
if(p) return p;
else throw std::bad_alloc();
}
SpecAllocator *tmp;
size_t freemem= 0;
void* mem = allocator_.AcquireBuffer(&tmp,&freemem); // can throw bad_alloc
if(multi())
{
freememory_+= freemem;
freememory_-= bufsz_;
}
return mem;
}
void
GenAllocator::Free(void *p,size_t sz)
{
#ifdef DEBUG_BUFFER_STACK
printf("GenAllocator[%u]::Free(void *p,int sz= %u)\n",bufsz_,sz);
#endif
if(!p) return;
if(sz != bufsz_)
#if !defined(MALLOCATOR)
return free(p);
#else
return Mallocator::free(p,sz);
#endif
size_t released = allocator_.ReleaseBuffer(p);
if(multi())
{
freememory_+= released;
if(freememory_>maxfreememory_)
{
freememory_-=allocator_.ReleaseMemory(freememory_- maxfreememory_);
}
}
}
void
GenAllocator::destroy()
{
pthread_key_delete(mem_key());
mem_key_once() = (pthread_once_t)PTHREAD_ONCE_INIT;
}
void
GenAllocator::destroy(void *buf)
{
map_t *m= static_cast<map_t *>(buf);
for(map_t::iterator itr= m->begin();itr!=m->end();++itr) {
itr->second->~GenAllocator();
#if !defined(MALLOCATOR)
free(itr->second);
#else
Mallocator::free(itr->second,sizeof(GenAllocator));
#endif
}
m->~map_t();
#if !defined(MALLOCATOR)
free(m);
#else
Mallocator::free(m,sizeof(map_t));
#endif
}
void
GenAllocator::mem_key_alloc()
{
pthread_key_create(&mem_key(),&destroy);
atexit(&destroy);
}
//pthread_key_t MemManager::mem_key_;
//pthread_once_t MemManager::mem_key_once_= PTHREAD_ONCE_INIT;
MemManager *MemManager::manager_= 0;
//bool MemManager::multi_= true;
#ifdef USE_NEW_INTERNAL_STATE
//size_t MemManager::maxsize_= 65536-sizeof(size_t);//65536;
//size_t MemManager::segmentsize_= 12;
#endif
MemManager::MemManager(pthread_t tid)
: maxfreememory_(0)
, freememory_(0)
,mrcnt_(0)
,mytid_(tid)
{
}
MemManager::~MemManager()
{
#ifdef USE_NEW_INTERNAL_STATE
for(seginfo_t::iterator i= seginfos_.begin();i != seginfos_.end();++i)
for(SegInfo::v_t::iterator j= (*i).v_.begin();j != (*i).v_.end();++j){
(*j)->~SpecAllocator();
#if !defined(MALLOCATOR)
free(*j);
#else
Mallocator::free(*j,sizeof(SpecAllocator));
#endif
}
#else
for(container_t::iterator i= cont_.begin();i != cont_.end();++i) {
i->second->~SpecAllocator();
#if !defined(MALLOCATOR)
free(i->second);
#else
Mallocator::free(i->second,sizeof(SpecAllocator));
#endif
}
#endif
}
#ifndef USE_NEW_INTERNAL_STATE
bool
MemManager::cmp(const content_t& lhs,const content_t& rhs)
{
return lhs.first<rhs.first;
}
#endif
SpecAllocator* MemManager::findSpecAllocator(size_t sz)
{
SpecAllocator *allocator= 0;
seginfo_t::iterator itr=
lower_bound(seginfos_.begin(),seginfos_.end(),SegInfo(0,sz,0),SegInfo::cmp);
assert(itr!=seginfos_.end());
SegInfo &seginfo= *itr;
size_t allindex= (sz<=seginfo.segbase_)?0:(sz - seginfo.segbase_)/seginfo.chunkdiff_;
allocator= seginfo.v_[allindex];
return allocator;
}
void
MemManager::InstallNodes(bool bmulti)
{
#ifdef USE_NEW_INTERNAL_STATE
//printf("MemManager::InstallNodes(%s): start\n",multi?"TRUE":"FALSE");
size_t segbase= 12;
size_t nodesz= 128;
for(size_t i= 3;i<9;++i) {
// printf("node size: %u\n",nodesz);
size_t nextsegbase= (size_t)pow(4,i)-4;
#if 0
printf("segment %u: segment base= %u, next segment base= %u\n",
i-3,segbase,nextsegbase);
#endif
size_t segmentsize= 12;
#if 1
seginfos_.push_back(SegInfo(segbase+1,nextsegbase,(nextsegbase-segbase)/segmentsize));
#else
seginfos_.push_back(SegInfo(segbase+1,nextsegbase,(nextsegbase-segbase)/segmentsize_));
#endif
SegInfo &seginfo= seginfos_[i-3];
#if 1
for(size_t j= 0;j<segmentsize;++j) {
#if !defined(MALLOCATOR)
void *tmp= malloc(sizeof(SpecAllocator));
#else
void *tmp= Mallocator::alloc(sizeof(SpecAllocator));
#endif
if(!tmp) throw std::bad_alloc();
new(tmp)SpecAllocator(segbase + (j+1)*((nextsegbase-segbase)/segmentsize),multi()?nodesz:ST_PREALLOCATE_UNITS,multi());
// printf("%u\n",segbase + (j+1)*((nextsegbase-segbase)/segmentsize));
seginfo.v_.push_back(static_cast<SpecAllocator *>(tmp));
}
nodesz/= 2;
#else
for(size_t j= 0;j<segmentsize_;++j) {
#if !defined(MALLOCATOR)
void *tmp= malloc(sizeof(SpecAllocator));
#else
void *tmp= Mallocator::alloc(sizeof(SpecAllocator));
#endif
if(!tmp) throw std::bad_alloc();
new(tmp)SpecAllocator(segbase + (j+1)*((nextsegbase-segbase)/segmentsize_),multi_?MT_PREALLOCATE_UNITS:ST_PREALLOCATE_UNITS,multi_);
seginfo.v_.push_back(static_cast<SpecAllocator *>(tmp));
}
#endif
segbase= nextsegbase;
}
maxfreememory_ = maxsize()*seginfos_.size()*segmentsize()*2;
//fprintf(stderr,"max allocator free memory:%u\n", maxfreememory_);
//printf("MemManager::InstallNodes(): end\n\n");
#else
for(size_t i = 2; i<16; ++i) {
size_t bufsz= 2<<i;
InstallNode(bufsz,STORAGE_SIZE/bufsz);
#if 0
printf("MemManager::InstallNodes(): bufsz= %u,nodesz= %u\n",
bufsz,STORAGE_SIZE/bufsz);
#endif
}
#endif
}
size_t
MemManager::ReleaseMemory(size_t size)
{
//printf("MemManager::ReleaseMemory[%d](int size= %d)\n",++mrcnt_,size);
size_t memoryReleased = 0;
size_t tmpSize = size;
for(seginfo_t::reverse_iterator i=seginfos_.rbegin();i!=seginfos_.rend();++i)
{
SegInfo& si = *i;
for(SegInfo::v_t::reverse_iterator j=si.v_.rbegin();j!=si.v_.rend();++j)
{
size_t tmp =(*j)->ReleaseMemory(tmpSize);
tmpSize -= tmp;
memoryReleased += tmp;
if(memoryReleased>=size)
{
//printf("MemManager::ReleaseMemory[%u] 1 thread %u, memory released %u, required %u\n",++mrcnt_,pthread_self(), memoryReleased, size);
return memoryReleased;
}
}
}
//printf("MemManager::ReleaseMemory 2 thread %u, memory released %u, required %u\n",pthread_self(), memoryReleased, size);
return memoryReleased;
}
int
MemManager::AcquireBuffer(size_t sz,void **pbuf,SpecAllocator **ppnode)
{
#ifdef DEBUG_BUFFER_STACK
printf("MemManager::AcquireBuffer(int sz= %u,void **,CMemStackNode **)\n",
sz);
#endif
#ifdef USE_NEW_INTERNAL_STATE
if(seginfos_.empty()) return -1;
if(sz > maxsize()) sz= maxsize();
SpecAllocator* allocator = findSpecAllocator(sz);
size_t freemem= 0; // new memory allocated
*pbuf= allocator->AcquireBuffer(ppnode,&freemem);
if(multi())
{
freememory_+= freemem;
freememory_-= allocator->ChunkSize();
if(freememory_>maxfreememory_)
{
#if 0
printf("MemManager::AcquireMemory[%u](): free %u vs max %u\n",
++mrcnt_,freememory_,maxfreememory_);
#endif
freememory_-=ReleaseMemory(freememory_ - maxfreememory_);
}
}
return allocator->ChunkSize();
#else
if(cont_.empty()) return -1;
SpecAllocator *tmp= 0;
container_t::iterator fnd=
lower_bound(cont_.begin(),cont_.end(),std::make_pair(sz,tmp),cmp);
if(fnd == cont_.end()) --fnd;
[continued in next message]
--- SoupGate-Win32 v1.05
* Origin: fsxNet Usenet Gateway (21:1/5)