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

    From Branimir Maksimovic@21:1/5 to All on Mon Oct 11 10:46:46 2021
    [continued from previous message]

    *pbuf= fnd->second->AcquireBuffer(ppnode);

    return fnd->first;

    #endif
    }


    size_t
    MemManager::AcquireBuffer(size_t sz,void **pbuf)
    {
    #ifdef DEBUG_BUFFER_STACK
    printf("MemManager::AcquireBuffer(int sz= %d,void **pbuf)\n",sz);
    #endif

    #ifdef USE_NEW_INTERNAL_STATE

    #if 0
    printf("MemManager::AcquireBuffer(size= %u,tid= %u): start\n",
    sz,pthread_self());
    #endif

    assert(sz<=~0ul-sizeof(size_t));

    sz+=sizeof(size_t);

    SpecAllocator *tmp= 0;
    if(sz > maxsize()) {

    #if !defined(MALLOCATOR)
    *pbuf= malloc(sz);
    #else
    *pbuf= Mallocator::alloc(sz);
    #endif
    if(!*pbuf) throw std::bad_alloc();

    *(size_t*)*pbuf=sz;
    *pbuf = (size_t*)*pbuf+1;

    return sz;
    }

    SpecAllocator *allocator= findSpecAllocator(sz);

    size_t freemem= 0;
    *pbuf= allocator->AcquireBuffer(&tmp,&freemem);

    *(size_t*)*pbuf = sz;
    *pbuf = (size_t*)*pbuf+1;

    if(multi())
    {
    freememory_+= freemem;
    freememory_-= allocator->ChunkSize();
    if(freememory_>maxfreememory_)
    {
    #if 0

    printf("MemManager::AcquireMemory[%u,%u](): free %u vs max %u\n",
    ++mrcnt_,pthread_self(),freememory_,maxfreememory_);
    #endif
    freememory_-=ReleaseMemory(freememory_ - maxfreememory_);
    }
    }

    //printf("MemManager::AcquireBuffer(size= %u): end\n",sz);
    return allocator->ChunkSize();

    #else

    SpecAllocator *tmp= 0;
    container_t::iterator fnd=
    lower_bound(cont_.begin(),cont_.end(),std::make_pair(sz,tmp),cmp);
    if(fnd == cont_.end()) {

    #if !defined(MALLOCATOR)
    *pbuf= malloc(sz);
    #else
    *pbuf= Mallocator::alloc(sz);
    #endif
    if(!*pbuf) throw std::bad_alloc();
    return sz;
    }
    *pbuf= fnd->second->AcquireBuffer(&tmp);

    return fnd->first;

    #endif
    }

    size_t
    MemManager::ReallocateBuffer(size_t sz, void **pbuf)
    {

    if(!*pbuf)return AcquireBuffer(sz, pbuf);

    if(!sz)
    {
    ReleaseBuffer(*pbuf, sz);
    return 0;
    }

    assert(sz<=~0ul-sizeof(size_t));

    sz+=sizeof(size_t);

    *pbuf = (size_t*)*pbuf-1;
    size_t oldsz = *(size_t*)*pbuf;

    if(oldsz>=sz)
    {
    *pbuf = (size_t*)*pbuf+1;
    return oldsz;
    }

    if(oldsz>maxsize())
    {
    #if !defined(MALLOCATOR)
    void* tmpbuf = realloc(*pbuf,sz);
    #else
    void* tmpbuf = Mallocator::realloc(*pbuf,oldsz,sz);
    #endif
    if(!tmpbuf)
    {
    *pbuf = (size_t*)*pbuf+1;
    return 0;
    }
    *pbuf = tmpbuf;
    *(size_t*)*pbuf = sz;
    *pbuf = (size_t*)*pbuf+1;
    return sz;
    }

    SpecAllocator *oldallocator = findSpecAllocator(oldsz);

    if(sz>maxsize())
    {
    #if !defined(MALLOCATOR)
    void* tmpbuf = malloc(sz);
    #else
    void* tmpbuf = Mallocator::alloc(sz);
    #endif
    if(!tmpbuf)
    {
    *pbuf = (size_t*)*pbuf+1;
    return 0;
    }
    memcpy(tmpbuf, *pbuf, oldsz);
    size_t freed = oldallocator->ReleaseBuffer(*pbuf);
    *pbuf = tmpbuf;
    *(size_t*)*pbuf = sz;
    *pbuf = (size_t*)*pbuf+1;
    if(multi())
    {
    freememory_+=freed;
    if(freememory_>maxfreememory_)
    {
    #if 0
    printf("MemManager::AcquireMemory[%u](%u): free %u vs max %u\n",
    ++mrcnt_,pthread_self(), freememory_,maxfreememory_); #endif
    freememory_-=ReleaseMemory(freememory_ - maxfreememory_);
    }
    }
    return sz;
    }

    SpecAllocator *newallocator = findSpecAllocator(sz), *atmp=0;

    if(newallocator == oldallocator)
    {
    *(size_t*)*pbuf=sz;
    *pbuf = (size_t*)*pbuf+1;
    return newallocator->ChunkSize();
    }

    size_t freemem= 0;
    void *tmpbuf= newallocator->AcquireBuffer(&atmp,&freemem);
    if(multi())
    {
    freememory_+= freemem;
    freememory_-= newallocator->ChunkSize();
    if(freememory_>maxfreememory_)
    {
    #if 0

    printf("MemManager::AcquireMemory[%u,%u](): free %u vs max %u\n",
    ++mrcnt_,pthread_self(),freememory_,maxfreememory_);
    #endif
    freememory_-=ReleaseMemory(freememory_ - maxfreememory_);
    }
    }

    memcpy(tmpbuf, *pbuf, oldsz);

    size_t freed = oldallocator->ReleaseBuffer(*pbuf);
    if(multi())
    {
    freememory_+=freed;
    if(freememory_>maxfreememory_)
    {
    #if 0
    printf("MemManager::AcquireMemory[%u](%u): free %u vs max %u\n",
    ++mrcnt_,pthread_self(), freememory_,maxfreememory_);
    #endif
    freememory_-=ReleaseMemory(freememory_ - maxfreememory_);
    }
    }
    *pbuf = tmpbuf;
    *(size_t*)*pbuf = sz;
    *pbuf = (size_t*)*pbuf + 1;
    return newallocator->ChunkSize();
    }

    size_t
    MemManager::MaxSize()
    {
    #if 1
    return UINT_MAX;
    #else
    container_t::iterator it= cont_.end();
    --it;
    return it->first;
    #endif
    }


    void
    MemManager::ReleaseBuffer(void* buf, SpecAllocator* alloc)
    {
    size_t freed = alloc->ReleaseBuffer(buf);
    if(multi())
    {
    freememory_+=freed;
    if(freememory_>maxfreememory_)
    {
    #if 0
    printf("MemManager::AcquireMemory[%u](%u): free %u vs max %u\n",
    ++mrcnt_,pthread_self(), freememory_,maxfreememory_); #endif
    freememory_-=ReleaseMemory(freememory_ - maxfreememory_);
    }
    }
    }

    void
    MemManager::ReleaseBuffer(void *buf,size_t sz)
    {
    if(!buf)return;
    #ifdef DEBUG_BUFFER_STACK
    printf("MemManager::ReleaseBuffer(char *buf,int sz= %u)\n",sz);
    #endif

    #ifdef USE_NEW_INTERNAL_STATE

    buf = (size_t*)buf-1;
    sz = *(size_t*)buf;

    if(sz > maxsize()) {

    #if !defined(MALLOCATOR)
    free(buf);
    #else
    Mallocator::free(buf,sz);
    #endif
    return;
    }

    SpecAllocator *allocator= findSpecAllocator(sz);

    size_t freed = allocator->ReleaseBuffer(buf);

    if(multi())
    {
    freememory_+=freed;
    if(freememory_>maxfreememory_)
    {
    #if 0
    printf("MemManager::ReleaseBuffer[%d](%u): free %d vs max %d\n",
    ++mrcnt_,pthread_self(), freememory_,maxfreememory_);
    #endif
    freememory_-=ReleaseMemory(freememory_ - maxfreememory_);
    }
    }

    #else
    SpecAllocator *tmp= 0;
    container_t::iterator fnd=
    lower_bound(cont_.begin(),cont_.end(),std::make_pair(sz,tmp),cmp);
    if(fnd == cont_.end()) {

    free(buf);
    return;
    }

    fnd->second->ReleaseBuffer(buf);
    #endif
    }


    bool
    MemManager::LostFound(size_t sz,void *first,size_t nodesz)
    {
    #ifdef USE_NEW_INTERNAL_STATE

    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];

    assert(sz == allocator->ChunkSize());

    return allocator->LostFound(first,nodesz);

    #else

    SpecAllocator *tmp= 0;
    container_t::iterator fnd=
    lower_bound(cont_.begin(),cont_.end(),std::make_pair(sz,tmp),cmp);
    if(fnd == cont_.end()) return false;

    return fnd->second->LostFound(first);

    #endif
    }


    #ifndef USE_NEW_INTERNAL_STATE
    void
    MemManager::InstallNode(size_t ibufsz,size_t inodesz)
    {
    #ifdef DEBUG_BUFFER_STACK
    printf("MemManager::InstallNode(size_t bufsz= %u,size_t nodesz= %u): ",
    bufsz,nodesz);
    #endif

    // check if we have node already installed
    container_t::iterator itr= cont_.begin();
    for(;itr!=cont_.end();++itr)
    if(itr->first == bufsz) break;

    if(itr != cont_.end()) {

    return;
    }

    #if !defined(MALLOCATOR)
    void *node= malloc(sizeof(SpecAllocator));
    #else
    void *node= Mallocator::alloc(sizeof(SpecAllocator));
    #endif
    if(node) {
    new(node)SpecAllocator(ibufsz,inodesz,multi_);
    cont_.push_back(std::make_pair(ibufsz,static_cast<SpecAllocator*>(node)));
    }
    else throw std::bad_alloc();
    std::sort(cont_.begin(),cont_.end(),cmp);
    }
    #endif



    #pragma weak configureMemManager


    #ifdef MM_ASSUME_PTHREAD_INITIALIZATION
    MemManager::PthreadInitializer MemManager::pthread_initializer_;


    void
    MemManager::lib_pthread_init_finished()
    {
    // save initialization manager
    // MemManagerTable::instance().Insert(pthread_self(),init_manager());

    // create mem_key
    pthread_once(&mem_key_once(),&mem_key_alloc);

    // init specific
    // pthread_setspecific(mem_key(),init_manager());

    #ifdef MALLOCATOR
    Mallocator::set_lock(true);
    #endif

    lib_pthread_initialized()= true;
    }
    #endif


    MemManager &
    MemManager::instance()
    {
    //printf("MemManager::instance(): start\n");
    setupThreadModel();
    //printf("MemManager::instance(): thread model set\n");

    if(!multi()) {

    if(!manager_) {

    #if !defined(MALLOCATOR)
    void *tmp= malloc(sizeof(MemManager));
    #else
    void *tmp= Mallocator::alloc(sizeof(MemManager));
    #endif
    if(tmp) {
    new(tmp)MemManager(pthread_self());
    manager_= static_cast<MemManager*>(tmp);
    manager_->InstallNodes(multi());
    }
    else throw std::bad_alloc();
    atexit(&destroy);
    }
    return *manager_;
    }
    else {

    if(false && !lib_pthread_initialized()) {

    #if 0
    if(!init_manager()) {

    // create memmgr
    #if !defined(MALLOCATOR)
    void *mgr= malloc(sizeof(MemManager));
    #else
    void *mgr= Mallocator::alloc(sizeof(MemManager));
    #endif
    if(mgr)
    {
    new(mgr)MemManager(pthread_self());
    }
    else throw std::bad_alloc();

    #if 0
    printf("Manager created: %p, %u (%u)\n",
    mgr,pthread_self(),sizeof(MemManager));
    #endif

    init_manager()= static_cast<MemManager*>(mgr);
    #if 1
    if(configureMemManager)
    configureMemManager(init_manager());
    else
    #endif
    init_manager()->InstallNodes(multi());
    }

    return *init_manager();
    #endif
    }
    else {

    #ifndef MM_ASSUME_PTHREAD_INITIALIZATION
    // create mem_key
    pthread_once(&mem_key_once(),&mem_key_alloc);
    #endif

    if(!pthread_getspecific(mem_key())) {

    MemManager *mm=
    MemManagerTable::instance().FindManager(pthread_self());
    if(mm) return *mm;

    #if !defined(MALLOCATOR)
    void *mgr= malloc(sizeof(MemManager));
    #else
    void *mgr= Mallocator::alloc(sizeof(MemManager));
    #endif
    if(mgr)
    {
    new(mgr)MemManager(pthread_self());
    }
    else throw std::bad_alloc();

    #if 0
    printf("Manager created: %p, %u (%u)\n",
    mgr,pthread_self(),sizeof(MemManager));
    #endif

    MemManager *m=static_cast<MemManager*>(mgr);
    #if 1
    if(configureMemManager)
    configureMemManager(m);
    else
    #endif
    m->InstallNodes(multi());

    //printf("MemManager::instance(): before inserting to table\n");
    MemManagerTable::instance().Insert(pthread_self(),m);
    //printf("MemManager::instance(): after table insertion\n");
    pthread_setspecific(mem_key(),mgr);
    //printf("MemManager::instance(): after specific set\n");
    }
    return *static_cast<MemManager*>(pthread_getspecific(mem_key()));
    }
    }
    }


    void
    MemManager::setupThreadModel()
    {
    //printf("MemManager::setupThreadModel()\n");
    pthread_once(&thread_model_once(),&setup_thread_model);
    }


    void
    MemManager::setThreadModel(bool multithread)
    {
    static bool called= false;
    assert(!called);
    multi()= multithread;
    called= true;
    }


    void
    MemManager::destroy()
    {
    if(!multi()) {

    manager_->~MemManager();
    #if !defined(MALLOCATOR)
    free(manager_);
    #else
    Mallocator::free(manager_,sizeof(MemManager));
    #endif
    }
    else {

    //printf("MemManager::destroy()\n");

    pthread_key_delete(mem_key());
    mem_key_once() = (pthread_once_t)PTHREAD_ONCE_INIT;
    }
    }


    void
    MemManager::destroy(void *buf)
    {
    #if 0
    printf("MemManager::destroy(void *,tid= %u): should destroy %u manager\n",
    pthread_self(),static_cast<MemManager*>(buf)->mytid_);
    #endif

    #if 1
    MemManagerTable::instance().Erase(static_cast<MemManager*>(buf)->mytid_); #else
    MemManagerTable::instance().Erase(pthread_self());
    #endif
    //printf("MemManager::destroy(): manager erased from the global table\n");

    static_cast<MemManager*>(buf)->~MemManager();
    //printf("MemManager::destroy(): manager destroyed\n");

    #if !defined(MALLOCATOR)
    free(buf);
    #else
    Mallocator::free(buf,sizeof(MemManager));
    #endif

    #if 1
    //printf("MemManager::destroy(void *buf): END\n");
    #endif
    }


    void
    MemManager::mem_key_alloc()
    {
    pthread_key_create(&mem_key(),&destroy);
    atexit(&destroy);
    }



    MemManagerTable *MemManagerTable::instance_= 0;
    //pthread_once_t MemManagerTable::init_once_= PTHREAD_ONCE_INIT;

    MemManagerTable &
    MemManagerTable::instance()
    {
    //printf("MemManagerTable::instance(): before pthread_once\n");
    pthread_once(&init_once(),&initialize);
    //printf("MemManagerTable::instance(): after pthread_once\n");
    return *instance_;
    }

    MemManager *
    MemManagerTable::FindManager(pthread_t tid)
    {
    //printf("MemManagerTable::FindManager(tid= %d): before lock\n",tid);
    AutoLock guard(lock_);
    //printf("MemManagerTable::FindManager(tid= %d): locked\n",tid);
    map_t::iterator itr= table_.find(tid);
    if(itr != table_.end()) return itr->second;
    else return 0;
    }

    bool
    MemManagerTable::LostFound(pthread_t tid,size_t bufsz,void *n,size_t nodesz)
    {
    AutoLock guard(lock_);
    map_t::iterator itr= table_.find(tid);
    if(itr != table_.end()) return itr->second->LostFound(bufsz,n,nodesz);
    else return false;
    }


    void
    MemManagerTable::Insert(pthread_t tid,MemManager *mgr)
    {
    AutoLock guard(lock_);
    table_[tid]= mgr;
    }


    void
    MemManagerTable::Erase(pthread_t tid)
    {
    AutoLock guard(lock_);
    //fprintf(stderr,"MemManagerTable::Erase(pthread_t tid= %u)\n",tid);
    map_t::iterator itr= table_.find(tid);
    if(itr != table_.end()) table_.erase(itr);
    }


    void
    MemManagerTable::initialize()
    {

    #if !defined(MALLOCATOR)
    void *tmp= malloc(sizeof(MemManagerTable));
    #else
    void *tmp= Mallocator::alloc(sizeof(MemManagerTable));
    #endif
    if(tmp) {

    //printf("Manager Table created: %p (%u)\n",tmp,sizeof(MemManagerTable));
    new(tmp)MemManagerTable();
    //printf("Manager Table constructed: %p (%u)\n",tmp,sizeof(MemManagerTable));

    instance_= static_cast<MemManagerTable *>(tmp);
    atexit(&destroy);
    }
    else throw std::bad_alloc();
    }


    void
    MemManagerTable::destroy()
    {
    instance_->~MemManagerTable();
    #if !defined(MALLOCATOR)
    free(instance_);
    #else
    Mallocator::free(instance_,sizeof(MemManagerTable));
    #endif
    instance_= 0;
    init_once() = (pthread_once_t)PTHREAD_ONCE_INIT;
    }



    void* MemManagerPrim::operator new(size_t s)throw (std::bad_alloc)
    {
    //printf("new: %u\n",s);
    void *buf = 0;
    MemManager::instance().AcquireBuffer(s,&buf);
    return buf;
    }

    void MemManagerPrim::operator delete(void* p)throw ()
    {
    //printf("delete: \n");
    MemManager::instance().ReleaseBuffer(p, (size_t)0);
    //printf("-----------------------------\nend of delete\n\n");
    }

    void* MemManagerPrim::malloc(size_t s)
    try
    {
    if(MemManager::lib_pthread_initialized()) {

    //printf("malloc\n");
    void* buf = 0;
    MemManager::instance().AcquireBuffer(s, &buf);
    return buf;
    }
    else {

    //avoid MemManager interface; use base layer...
    s+= sizeof(size_t);
    void *buf= Mallocator::alloc(s);
    if(!buf) return 0;
    *(size_t *)buf= s;
    buf= (size_t *)buf + 1;
    return buf;
    }
    }
    catch(const std::exception& e)
    {
    //fprintf(stderr,"memory exception: %s\n", e.what());
    return 0;
    }
    catch(...)
    {
    //fprintf(stderr,"unkown memory exception\n");
    return 0;
    }

    void* MemManagerPrim::calloc(size_t n, size_t s)
    try
    {
    if(MemManager::lib_pthread_initialized()) {

    //printf("calloc: %u of size %u\n",n,s);
    void* buf = 0;
    MemManager::instance().AcquireBuffer(n*s, &buf);
    memset(buf,0,n*s);
    return buf;
    }
    else {

    size_t x= n*s;
    x+= sizeof(size_t);
    void *buf= Mallocator::alloc(x);
    if(!buf) return 0;
    memset(buf,0,x);
    *(size_t *)buf= x;
    buf= (size_t *)buf + 1;
    return buf;
    }
    }
    catch(const std::exception& e)
    {
    //fprintf(stderr,"memory exception: %s\n", e.what());
    return 0;
    }
    catch(...)
    {
    //fprintf(stderr,"unkown memory exception\n");
    return 0;
    }


    void* MemManagerPrim::realloc(void* p, size_t s)
    try
    {
    if(MemManager::lib_pthread_initialized()) {

    size_t rc = MemManager::instance().ReallocateBuffer(s, &p);
    if(rc)return p;
    else return 0;
    }
    else {

    return p;
    }
    }
    catch(const std::exception& e)
    {
    //fprintf(stderr,"memory exception: %s\n", e.what());
    return 0;
    }
    catch(...)
    {
    //fprintf(stderr,"unkown memory exception\n");
    return 0;
    }

    void MemManagerPrim::free(void* p)
    {
    //printf("free: \n");
    if(!p)return;
    if(MemManager::lib_pthread_initialized()) {

    MemManager::instance().ReleaseBuffer(p, (size_t)0);
    }
    else {

    p= (size_t *)p - 1;
    size_t s= *(size_t *)p;
    Mallocator::free(p,s);
    }
    }



    //============================================================================= // History:
    //
    // $Log$
    // Revision 1.50 2009/07/17 16:16:34 luska
    // library repackaged
    //
    // Revision 1.49 2008/08/05 14:17:33 virtus
    // *** empty log message ***
    //
    // Revision 1.48 2006/01/19 17:08:14 virtus
    // ported to openbsd
    //
    // Revision 1.47 2005/08/18 17:54:34 luska
    // ASSUME_PTHREAD_INITIALIZATION switch added
    //
    // Revision 1.46 2005/08/01 22:41:31 luska
    // hm, while initializing pthread use Mallocator interface
    //
    // Revision 1.45 2005/08/01 20:43:22 luska
    // only lock memory banks if pthread init is finished
    //
    // Revision 1.44 2005/08/01 18:39:48 luska
    // *** empty log message ***
    //
    // Revision 1.43 2005/08/01 18:19:30 luska
    // all statics wrapped
    //
    // Revision 1.42 2005/07/05 18:49:38 build
    // resolved namespace and const map key issue
    //
    // Revision 1.41 2005/01/12 12:59:14 luska
    // nasty little fixed
    //
    // Revision 1.40 2004/10/29 16:41:42 bmaxa
    // *** empty log message ***
    //
    // Revision 1.39 2004/10/29 16:38:53 bmaxa
    // *** empty log message ***
    //
    // Revision 1.38 2004/10/29 16:34:21 bmaxa
    // line 202 cast corrected
    //
    // Revision 1.37 2004/10/28 16:58:37 luska
    // f'in printf removed thanks to web team
    //
    // Revision 1.36 2004/10/26 18:40:13 luska
    // *** empty log message ***
    //
    // Revision 1.35 2004/10/25 21:49:21 bmaxa
    // release buffer check for null in mem manager
    //
    // Revision 1.34 2004/10/25 20:08:54 luska
    // *** empty log message ***
    //
    // Revision 1.33 2004/10/25 20:07:34 luska
    // recursion bug at pthread_setspecific fixed
    //
    // Revision 1.32 2004/10/25 18:15:10 bmaxa
    // new,delete
    //
    // Revision 1.31 2004/10/25 16:56:34 bmaxa
    // added malloc....
    //
    // Revision 1.30 2004/10/21 21:20:49 bmaxa
    // *** empty log message ***
    //
    // Revision 1.29 2004/10/19 20:10:00 bmaxa
    // corrected findSpecAllocator
    //
    // Revision 1.28 2004/10/19 20:01:00 bmaxa
    // ReallocBuffer and findSpecAllocator added
    //
    // Revision 1.27 2004/10/16 00:17:10 bmaxa
    // final with tree
    //
    // Revision 1.26 2004/10/15 21:58:43 luska
    // *** empty log message ***
    //
    // Revision 1.25 2004/10/07 16:50:07 virtus
    // *** empty log message ***
    //
    // Revision 1.24 2004/10/04 19:34:09 bmaxa
    // suited for mallocator
    //
    // Revision 1.23 2004/09/28 19:21:15 bmaxa
    // foreigners are up front...
    //
    // Revision 1.22 2004/09/27 21:09:49 bmaxa
    // foreigners are back :)
    //
    // Revision 1.21 2004/09/27 16:52:42 bmaxa
    // ammount of returned memory properly returned and check for null in malloc call for single threaded version
    //
    // Revision 1.20 2004/09/21 18:53:09 bmaxa
    // size_t instead of int
    //
    // Revision 1.19 2004/09/20 17:26:23 bmaxa
    // *** empty log message ***
    //
    // Revision 1.18 2004/09/20 17:16:01 bmaxa
    // size*16 max memory
    //
    // Revision 1.17 2004/09/20 16:11:43 bmaxa
    // list,map into vector
    //
    // Revision 1.15 2004/09/17 18:25:21 bmaxa
    // final
    //
    // Revision 1.14 2004/09/17 17:42:08 luska
    // InstallNodes algorithm changed
    //
    // Revision 1.13 2004/09/17 17:30:09 bmaxa
    // *** empty log message ***
    //
    // Revision 1.12 2004/09/17 15:13:53 vmp
    // mt preallocate 32 units
    //
    // Revision 1.11 2004/09/16 20:38:35 luska
    // *** empty log message ***
    //
    // Revision 1.10 2004/09/16 20:05:56 bmaxa
    // *** empty log message ***
    //
    // Revision 1.9 2004/09/16 19:36:05 luska
    // releasing memory bug fixed
    //
    // Revision 1.8 2004/09/16 18:36:48 luska
    // allocator interface changed due to memory accounting
    //
    // Revision 1.7 2004/09/16 16:42:10 bmaxa
    // corrections...
    //
    // Revision 1.6 2004/09/15 17:49:47 vmp
    // yet another once set for gen allocator
    //
    // Revision 1.5 2004/09/15 16:26:52 luska
    // use of pragma weak again
    //
    // Revision 1.4 2004/09/15 15:37:22 vmp
    // pthread_once_t reseted after destruction
    //
    // Revision 1.3 2004/09/13 16:54:02 luska
    // *** empty log message ***
    //
    // 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
    //
    //
    //
    //
    // //=============================================================================


    --

    7-77-777
    Evil Sinner!
    with software, you repeat same experiment, expecting different results...

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)