• Some old allocator code I want t share (1/2)

    From Branimir Maksimovic@21:1/5 to All on Mon Oct 11 10:46:46 2021
    //============================================================================= //
    // 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)