kallocator.cpp Source File (kdecore Library)

| # kdecore Library API Documentation
Overview | Class Hierarchy | Classes | Classes (annotated) | Members | Source Files

# kallocator.cpp

    00001 /*
    00002     This file is part of the KDE libraries
    00003
    00004     Copyright (C) 1999 Waldo Bastian (bastian@kde.org)
    00005     Copyright (C) 2002 Michael Matz (matz@kde.org)
    00006
    00007     This library is free software; you can redistribute it and/or
    00008     modify it under the terms of the GNU Library General Public
    00009     License as published by the Free Software Foundation; either
    00010     version 2 of the License, or (at your option) any later version.
    00011
    00012     This library is distributed in the hope that it will be useful,
    00013     but WITHOUT ANY WARRANTY; without even the implied warranty of
    00014     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
    00015     Library General Public License for more details.
    00016
    00017     You should have received a copy of the GNU Library General Public License
    00018     along with this library; see the file COPYING.LIB.  If not, write to
    00019     the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
    00020     Boston, MA 02111-1307, USA.
    00021 */
    00022
    00023 /* Fast zone memory allocator with deallocation support, for use as obstack
    00024    or as general purpose allocator.  It does no compaction.  If the usage
    00025    pattern is non-optimal it might waste some memory while running.  E.g.
    00026    allocating many small things at once, and then deallocating only every
    00027    second one, there is a high chance, that actually no memory is freed.  */
    00028 // $Id: kallocator.cpp,v 1.8 2002/08/29 07:13:08 cumming Exp $
    00029
    00030 #include "kallocator.h"
    00031 #include <kdebug.h>
    00032
    00033 class KZoneAllocator::MemBlock
    00034 {
    00035   public:
    00036     MemBlock(size_t s) : size(s), ref(0), older(0), newer(0)
    00037       { begin = new char[s]; }
    00038     ~MemBlock() { delete [] begin; }
    00039     bool is_in(void *ptr) const {return !(begin > (char *)ptr
    00040                                           || (begin + size) <= (char *)ptr); }
    00041     size_t size;
    00042     unsigned int ref;
    00043     char *begin;
    00044     MemBlock *older;
    00045     MemBlock *newer;
    00046 };
    00047
    00048 KZoneAllocator::KZoneAllocator(unsigned long _blockSize)
    00049 : currentBlock(0), blockSize(1), blockOffset(0), log2(0), num_blocks(0),
    00050   hashList(0), hashSize(0), hashDirty(true)
    00051 {
    00052   while (blockSize < _blockSize)
    00053     blockSize <<= 1, log2++;
    00054   /* Make sure, that a block is allocated at the first time allocate()
    00055      is called (even with a 0 size).  */
    00056   blockOffset = blockSize + 1;
    00057 }
    00058
    00059 KZoneAllocator::~KZoneAllocator()
    00060 {
    00061   unsigned int count = 0;
    00062   if (hashList) {
    00063     /* No need to maintain the different lists in hashList[] anymore.
    00064        I.e. no need to use delBlock().  */
    00065     for (unsigned int i = 0; i < hashSize; i++)
    00066       delete hashList[i];
    00067     delete [] hashList;
    00068     hashList = 0;
    00069   }
    00070   MemBlock *next;
    00071   for (; currentBlock; currentBlock = next) {
    00072     next = currentBlock->older;
    00073     delete currentBlock;
    00074     count++;
    00075   }
    00076   if (count > 1)
    00077     qDebug("zone still contained %d blocks", count);
    00078 }
    00079
    00080 void KZoneAllocator::insertHash(MemBlock *b)
    00081 {
    00082   unsigned int adr = ((unsigned int)b->begin) & (~(blockSize - 1));
    00083   unsigned int end = ((unsigned int)b->begin) + blockSize;
    00084   while (adr < end) {
    00085     unsigned int key = adr >> log2;
    00086     key = key & (hashSize - 1);
    00087     if (!hashList[key])
    00088       hashList[key] = new QValueList<MemBlock *>;
    00089     hashList[key]->append(b);
    00090     adr += blockSize;
    00091   }
    00092 }
    00093
    00094 void KZoneAllocator::addBlock(MemBlock *b)
    00095 {
    00096   b->newer = 0;
    00097   b->older = currentBlock;
    00098   if (currentBlock)
    00099     b->older->newer = b;
    00100   currentBlock = b;
    00101   num_blocks++;
    00102   /* If we either have no hashList at all, or since it's last construction
    00103      there are now many more blocks we reconstruct the list.  But don't
    00104      make it larger than a certain maximum.  */
    00105   if (hashList && ((num_blocks / 4) > hashSize && hashSize < 64*1024))
    00106     hashDirty = true;
    00107   /* Only insert this block into the hashlists, if we aren't going to
    00108      reconstruct them anyway.  */
    00109   if (hashList && !hashDirty)
    00110     insertHash (b);
    00111 }
    00112
    00113 void KZoneAllocator::initHash()
    00114 {
    00115   if (hashList) {
    00116     for (unsigned int i = 0; i < hashSize; i++)
    00117       delete hashList[i];
    00118     delete [] hashList;
    00119     hashList = 0;
    00120   }
    00121   hashSize = 1;
    00122   while (hashSize < num_blocks)
    00123     hashSize <<= 1;
    00124   if (hashSize < 1024)
    00125     hashSize = 1024;
    00126   if (hashSize > 64*1024)
    00127     hashSize = 64*1024;
    00128   hashList = new QValueList<MemBlock *> *[hashSize];
    00129   memset (hashList, 0, sizeof(QValueList<MemBlock*> *) * hashSize);
    00130   hashDirty = false;
    00131   for (MemBlock *b = currentBlock; b; b = b->older)
    00132     insertHash(b);
    00133 }
    00134
    00135 void KZoneAllocator::delBlock(MemBlock *b)
    00136 {
    00137   /* Update also the hashlists if we aren't going to reconstruct them
    00138      soon.  */
    00139   if (hashList && !hashDirty) {
    00140     unsigned int adr = ((unsigned int)b->begin) & (~(blockSize - 1));
    00141     unsigned int end = ((unsigned int)b->begin) + blockSize;
    00142     while (adr < end) {
    00143       unsigned int key = adr >> log2;
    00144       key = key & (hashSize - 1);
    00145       if (hashList[key]) {
    00146         QValueList<MemBlock *> *list = hashList[key];
    00147         QValueList<MemBlock *>::Iterator it = list->begin();
    00148         QValueList<MemBlock *>::Iterator endit = list->end();
    00149         for (; it != endit; ++it)
    00150           if (*it == b) {
    00151             list->remove(it);
    00152             break;
    00153           }
    00154       }
    00155       adr += blockSize;
    00156     }
    00157   }
    00158   if (b->older)
    00159     b->older->newer = b->newer;
    00160   if (b->newer)
    00161     b->newer->older = b->older;
    00162   if (b == currentBlock) {
    00163     currentBlock = 0;
    00164     blockOffset = blockSize;
    00165   }
    00166   delete b;
    00167   num_blocks--;
    00168 }
    00169
    00170 void *
    00171 KZoneAllocator::allocate(size_t _size)
    00172 {
    00173    // Use the size of (void *) as alignment
    00174    const size_t alignment = sizeof(void *) - 1;
    00175    _size = (_size + alignment) & ~alignment;
    00176
    00177    if ((unsigned long) _size + blockOffset > blockSize)
    00178    {
    00179       if (_size > blockSize) {
    00180         qDebug("KZoneAllocator: allocating more than %lu bytes", blockSize);
    00181         return 0;
    00182       }
    00183       addBlock(new MemBlock(blockSize));
    00184       blockOffset = 0;
    00185       //qDebug ("Allocating block #%d (%x)\n", num_blocks, currentBlock->begin);
    00186    }
    00187    void *result = (void *)(currentBlock->begin+blockOffset);
    00188    currentBlock->ref++;
    00189    blockOffset += _size;
    00190    return result;
    00191 }
    00192
    00193 void
    00194 KZoneAllocator::deallocate(void *ptr)
    00195 {
    00196   if (hashDirty)
    00197     initHash();
    00198
    00199   unsigned int key = (((unsigned int)ptr) >> log2) & (hashSize - 1);
    00200   QValueList<MemBlock *> *list = hashList[key];
    00201   if (!list) {
    00202     /* Can happen with certain usage pattern of intermixed free_since()
    00203        and deallocate().  */
    00204     //qDebug("Uhoh");
    00205     return;
    00206   }
    00207   QValueList<MemBlock*>::ConstIterator it = list->begin();
    00208   QValueList<MemBlock*>::ConstIterator endit = list->end();
    00209   for (; it != endit; ++it) {
    00210     MemBlock *cur = *it;
    00211     if (cur->is_in(ptr)) {
    00212       if (!--cur->ref) {
    00213         if (cur != currentBlock)
    00214           delBlock (cur);
    00215         else
    00216           blockOffset = 0;
    00217       }
    00218       return;
    00219     }
    00220   }
    00221   /* Can happen with certain usage pattern of intermixed free_since()
    00222      and deallocate().  */
    00223   //qDebug("Uhoh2");
    00224 }
    00225
    00226 void
    00227 KZoneAllocator::free_since(void *ptr)
    00228 {
    00229   /* If we have a hashList and it's not yet dirty, see, if we will dirty
    00230      it by removing too many blocks.  This will make the below delBlock()s
    00231      faster.  */
    00232   if (hashList && !hashDirty)
    00233     {
    00234       const MemBlock *b;
    00235       unsigned int removed = 0;
    00236       for (b = currentBlock; b; b = b->older, removed++)
    00237         if (b->is_in (ptr))
    00238           break;
    00239       if (hashSize >= 4 * (num_blocks - removed))
    00240         hashDirty = true;
    00241     }
    00242   while (currentBlock && !currentBlock->is_in(ptr)) {
    00243     currentBlock = currentBlock->older;
    00244     delBlock (currentBlock->newer);
    00245   }
    00246   blockOffset = ((char*)ptr) - currentBlock->begin;
    00247 }

This file is part of the documentation for kdelibs Version 3.1.5.
Documentation copyright © 1996-2002 the KDE developers.
Generated on Wed Jan 28 12:46:18 2004 by doxygen 1.3.4 written by Dimitri van Heesch, © 1997-2001