Back to index

lightning-sunbird  0.9+nobinonly
nsRecyclingAllocator.h
Go to the documentation of this file.
00001 /* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
00002 /* ***** BEGIN LICENSE BLOCK *****
00003  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
00004  *
00005  * The contents of this file are subject to the Mozilla Public License Version
00006  * 1.1 (the "License"); you may not use this file except in compliance with
00007  * the License. You may obtain a copy of the License at
00008  * http://www.mozilla.org/MPL/
00009  *
00010  * Software distributed under the License is distributed on an "AS IS" basis,
00011  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
00012  * for the specific language governing rights and limitations under the
00013  * License.
00014  *
00015  * The Original Code is mozilla.org code.
00016  *
00017  * The Initial Developer of the Original Code is
00018  * Netscape Communications Corporation.
00019  * Portions created by the Initial Developer are Copyright (C) 2001, 2002
00020  * the Initial Developer. All Rights Reserved.
00021  *
00022  * Contributor(s):
00023  *     Suresh Duddi <dp@netscape.com>
00024  *
00025  * Alternatively, the contents of this file may be used under the terms of
00026  * either the GNU General Public License Version 2 or later (the "GPL"), or
00027  * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
00028  * in which case the provisions of the GPL or the LGPL are applicable instead
00029  * of those above. If you wish to allow use of your version of this file only
00030  * under the terms of either the GPL or the LGPL, and not to allow others to
00031  * use your version of this file under the terms of the MPL, indicate your
00032  * decision by deleting the provisions above and replace them with the notice
00033  * and other provisions required by the GPL or the LGPL. If you do not delete
00034  * the provisions above, a recipient may use your version of this file under
00035  * the terms of any one of the MPL, the GPL or the LGPL.
00036  *
00037  * ***** END LICENSE BLOCK ***** */
00038 
00039 /*
00040  * nsRecyclingAllocator
00041  *
00042  * This allocator is useful when we cycle through a small set of allocations
00043  * repeatedly with minimal overlap. For eg. something we do for every gif
00044  * file read (or) buffers required for decompression of every file from jar.
00045  *
00046  * What this does is keeps around the first set of memory allocated and
00047  * reuses it subsequently. If all buckets are full, this falls back to
00048  * malloc/free
00049  *
00050  * Uses a timer to release all memory allocated if not used for more than
00051  * 10 secs automatically.
00052  *
00053  * Also there is a 4 byte maintenance overhead on every allocation.
00054  *
00055  * This allocator is thread safe.
00056  *
00057  * CAVEATS: As the number of buckets increases, this allocators performance
00058  *          will drop. As a general guideline, dont use this for more
00059  *          than NS_MAX_BLOCKS
00060  */
00061 
00062 #ifndef nsRecyclingAllocator_h__
00063 #define nsRecyclingAllocator_h__
00064 
00065 #include "nscore.h"
00066 #include "pratom.h"
00067 #include "prlock.h"
00068 #include "nsIRecyclingAllocator.h"
00069 #include "nsIGenericFactory.h"
00070 
00071 #define NS_DEFAULT_RECYCLE_TIMEOUT 10  // secs
00072 #define NS_MAX_BLOCKS              24
00073 #define NS_ALLOCATOR_OVERHEAD_BYTES (sizeof(Block)) // bytes
00074 
00075 class nsITimer;
00076 class nsIMemory;
00077 
00078 class NS_COM nsRecyclingAllocator {
00079  protected:
00080     struct Block {
00081       PRSize bytes;
00082     };
00083 
00084     // Make |BlockStoreNode| a |friend| so it can access |Block|.
00085     struct BlockStoreNode;
00086     friend struct BlockStoreNode;
00087 
00088     struct BlockStoreNode {
00089       BlockStoreNode() : bytes(0), block(nsnull), next(nsnull) {};
00090       PRSize bytes;
00091       Block *block;
00092       BlockStoreNode *next;
00093     };
00094 
00095 #define DATA(block) ((void *)(((char *)block) + NS_ALLOCATOR_OVERHEAD_BYTES))
00096 #define DATA_TO_BLOCK(data) ((Block *)((char *)(data) - NS_ALLOCATOR_OVERHEAD_BYTES))
00097 
00098     // mMaxBlocks: Maximum number of blocks that can be allocated
00099     PRUint32 mMaxBlocks;
00100 
00101     // mBlocks:
00102     //  All blocks used or not.
00103     BlockStoreNode *mBlocks;
00104 
00105     // mFreeList
00106     //  A linked list of free blocks sorted by increasing order of size
00107     BlockStoreNode* mFreeList;
00108 
00109     // mNotUsedList
00110     //  A linked list of BlockStoreNodes that are not used to store
00111     //  any block information. When we add blocks into mFreeList, we
00112     //  take BlockStoreNode from here.
00113     BlockStoreNode* mNotUsedList;
00114 
00115     // mLock: Thread safety of mFreeList and mNotUsedList
00116     PRLock *mLock;
00117 
00118     // Timer for freeing unused memory
00119     nsITimer *mRecycleTimer;
00120 
00121     // mRecycleAfter:
00122     //  Allocator should be untouched for this many seconds for freeing
00123     //  unused Blocks.
00124     PRUint32 mRecycleAfter;
00125 
00126     // mTouched:
00127     //  says if the allocator touched any bucket. If allocator didn't touch
00128     //  any bucket over a time time interval, timer will call FreeUnusedBuckets()
00129     PRInt32 mTouched;
00130 
00131     // mId:
00132     //  a string for identifying the user of nsRecyclingAllocator
00133     //  User mainly for debug prints
00134     const char *mId;
00135 
00136 #ifdef DEBUG
00137     // mNAllocated: Number of blocks allocated
00138     PRInt32 mNAllocated;
00139 #endif
00140 
00141  public:
00142 
00143     // nbucket : number of buckets to hold. Capped at NS_MAX_BUCKET
00144     // recycleAfter : Try recycling allocated buckets after this many seconds
00145     // id : a string used to identify debug prints. Will not be released.
00146     nsRecyclingAllocator(PRUint32 nbucket = 0, PRUint32 recycleAfter = NS_DEFAULT_RECYCLE_TIMEOUT,
00147                          const char *id = NULL);
00148     ~nsRecyclingAllocator();
00149 
00150     nsresult Init(PRUint32 nbucket, PRUint32 recycleAfter, const char *id);
00151 
00152     // Allocation and free routines
00153     void* Malloc(PRSize size, PRBool zeroit = PR_FALSE);
00154     void  Free(void *ptr);
00155 
00156     void* Calloc(PRUint32 items, PRSize size)
00157     {
00158         return Malloc(items * size, PR_TRUE);
00159     }
00160 
00161     // FreeUnusedBuckets - Frees any bucket memory that isn't in use
00162     void FreeUnusedBuckets();
00163 
00164  protected:
00165 
00166     // Timer callback to trigger unused memory
00167     static void nsRecycleTimerCallback(nsITimer *aTimer, void *aClosure);
00168 
00169     // Freelist management
00170     // FindFreeBlock: return a free block that can hold bytes (best fit)
00171     Block* FindFreeBlock(PRSize bytes);
00172     // AddToFreeList: adds block into our freelist for future retrieval.
00173     //  Returns PR_TRUE is addition was successful. PR_FALSE otherewise.
00174     PRBool AddToFreeList(Block* block);
00175 
00176     // Touch will mark that someone used this allocator
00177     // Timer based release will free unused memory only if allocator
00178     // was not touched for mRecycleAfter seconds.
00179     void Touch() {
00180         if (!mTouched)
00181             PR_AtomicSet(&mTouched, 1);
00182     }
00183     void Untouch() {
00184         PR_AtomicSet(&mTouched, 0);
00185     }
00186 
00187     friend void nsRecycleTimerCallback(nsITimer *aTimer, void *aClosure);
00188 };
00189 
00190 // ----------------------------------------------------------------------
00191 // Wrapping the recyling allocator with nsIMemory
00192 // ----------------------------------------------------------------------
00193 
00194 // Wrapping the nsRecyclingAllocator with nsIMemory
00195 class nsRecyclingAllocatorImpl : public nsRecyclingAllocator, public nsIRecyclingAllocator {
00196 public:
00197     NS_DECL_ISUPPORTS
00198     NS_DECL_NSIMEMORY
00199     NS_DECL_NSIRECYCLINGALLOCATOR
00200 
00201     nsRecyclingAllocatorImpl()
00202     {
00203     }
00204 
00205 private:
00206     ~nsRecyclingAllocatorImpl() {}
00207 };
00208 #endif // nsRecyclingAllocator_h__