⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 alignedchunk.h

📁 hoard内存管理器
💻 H
字号:
/* -*- C++ -*- */#ifndef _ALIGNEDCHUNK_H_#define _ALIGNEDCHUNK_H_/*  Heap Layers: An Extensible Memory Allocation Infrastructure    Copyright (C) 2000-2003 by Emery Berger  http://www.cs.umass.edu/~emery  emery@cs.umass.edu    This program is free software; you can redistribute it and/or modify  it under the terms of the GNU General Public License as published by  the Free Software Foundation; either version 2 of the License, or  (at your option) any later version.    This program is distributed in the hope that it will be useful,  but WITHOUT ANY WARRANTY; without even the implied warranty of  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the  GNU General Public License for more details.    You should have received a copy of the GNU General Public License  along with this program; if not, write to the Free Software  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA*/#include <stdlib.h>#include <malloc.h>#include <assert.h>#include "bitindex.h"/*	An aligned chunk is a chunk of memory	containing a number of fixed-size "slots".	As long as the chunk is naturally aligned,	each slot will also be naturally aligned.	This alignment allows us to use address masking to find	which chunk a given pointer belongs to.	All information about the chunk is stored at the end	of the chunk.*/// AlignHeap aligns every memory request to chunkSize.//// If you know that memory allocations are always aligned to chunkSize// from your allocator of choice, don't use AlignHeap because it// will waste memory.namespace HL {template <int chunkSize, class Super>class AlignHeap {public:	inline void * malloc (size_t sz) {		// Get a piece of memory large enough to be able to guarantee alignment.		void * buf = ::malloc (sz + chunkSize);		// Align the buffer.		void * alignedBuf = (void *) (((unsigned long) buf + sizeof(unsigned long) + chunkSize - 1) & -chunkSize);		// Record the original buffer's address right behind the aligned part.		assert ((unsigned long) alignedBuf - (unsigned long) buf > sizeof(unsigned long));		*((unsigned long *) alignedBuf - 1) = (unsigned long) buf;		return alignedBuf;	}	void free (void * ptr) {		// Get the original buffer's address and free that.		::free ((void *) *((unsigned long *) ptr - 1));	}};// An aligned chunk is of size chunkSize and is divided up into 32 pieces// of size slotSize. The 32nd one will not be available for allocation// because it is used for 'header' information (albeit stored in the footer).// Some restrictions: chunkSize MUST BE A POWER OF TWO.//                    slotSize MUST BE AT LEAST THE SIZE OF A DOUBLE.// The amount of memory that this approach wastes is small in practice://   For one aligned chunk, utilization is 31/32 = 97%.//   For two nested chunks, utilization is (31/32)^2 = 94%.//   For three nested chunks, utilization is (31/32)^3 = 91%.// Note that the smallest possible size of a three-deep aligned chunk// is 32 * 32 * 32 * 32 = one megabyte.template <int chunkSize, int slotSize>class AlignedChunk {public:	AlignedChunk (void)		: prev (NULL),			next (NULL),			status (ACQUIRED),			inUse (0)	{		// Make sure there's enough slop to let us store the chunk information!		assert (getNumSlots() * slotSize + sizeof(AlignedChunk) <= chunkSize);		// The slot size must be at least large enough to hold a double.		assert (slotSize == align(slotSize));		// Initialize the bitmap.		freeBitmap = 0;		// Block the last slot.		BitIndex::set (freeBitmap, 0);		emptyBitmap = freeBitmap;	}	~AlignedChunk (void)		{}  // Get and put slots.	// These are ATOMIC and lock-free.  // Get returns NULL iff there are no slots available.  void * getSlot (void) {RETRY_UNSET:		unsigned long currBitmap = freeBitmap;		// If currBitmap is all ones, everything is in use.		// Just return NULL.		if (currBitmap == (unsigned long) -1) {			assert (inUse == getNumSlots());			return NULL;		}		// Find an unset bit.		// We flip the bits in currBitmap and find the index of a one bit		// (which corresponds to the index of a zero in currBitmap).		int bitIndex;		unsigned long oneBit = (~currBitmap) & (-((signed long) ~currBitmap));		assert (oneBit != 0);		bitIndex = BitIndex::msb (oneBit);		if (bitIndex > getNumSlots()) {			assert (inUse == getNumSlots());			return NULL;		}		assert (inUse < getNumSlots());		assert (bitIndex < getNumSlots() + 1);		// Set it.		unsigned long oldBitmap = currBitmap;		BitIndex::set (currBitmap, bitIndex);		unsigned long updatedBitmap = InterlockedExchange ((long *) &freeBitmap, currBitmap);		if (updatedBitmap == oldBitmap) {			// Success.			// Return a pointer to the appropriate slot.			char * start = (char *) ((unsigned long) this & -chunkSize);			inUse++;			return start + slotSize * (getNumSlots() - bitIndex);		}		// Someone changed the bitmap before we were able to write it.		// Try again.		goto RETRY_UNSET;	}  // Put returns 1 iff the chunk is now completely empty.  inline int putSlot (void * ptr) {		assert (inUse >= 1);		AlignedChunk * ch = getChunk (ptr);		assert (ch == this);		// Find the index of this pointer.		// Since slotSize is known at compile time and is usually a power of two,		// the divide should be turned into shifts and will be fast.		char * start = (char *) ((unsigned long) ptr & -chunkSize);		int bitIndex = getNumSlots() - (((unsigned long) ((char *) ptr - start)) / slotSize);RETRY_RESET:		unsigned long currBitmap = freeBitmap;		unsigned long oldBitmap = currBitmap;		BitIndex::reset (currBitmap, bitIndex);		unsigned long updatedBitmap = InterlockedExchange ((long *) &freeBitmap, currBitmap);		if (updatedBitmap == oldBitmap) {			// Success.			inUse--;			assert ((inUse != 0) || (currBitmap == emptyBitmap));			assert ((inUse == 0) || (currBitmap != emptyBitmap));			// Return 1 iff the chunk is now empty.			if (currBitmap == emptyBitmap) {				assert (inUse == 0);				return 1;			} else {				assert (inUse > 0);				return 0;			}		}		// Try again.		goto RETRY_RESET;	}  // How many slots are there in total?  inline static int getNumSlots (void) {		return 31;	}	inline int isReleased (void) {		return (status == RELEASED);	}	inline void acquire (void) {		assert (status == RELEASED);		status = ACQUIRED;	}	inline void release (void) {		assert (status == ACQUIRED);		status = RELEASED;	}  // Find a chunk for a given slot.  inline static AlignedChunk * getChunk (void * slot) {		// Here's where the alignment is CRITICAL!!		// Verify that chunkSize is a power of two.		assert ((chunkSize & (chunkSize - 1)) == 0);		// Mask off the slot to find the start of the chunkSize block.		char * start = (char *) ((unsigned long) slot & -chunkSize);		// Find the end of the block.		char * eob = (start + chunkSize);		// Now locate the 'header' (in this case, it's actually a footer).		char * headerPos = eob - sizeof(AlignedChunk);		return (AlignedChunk *) headerPos;	}  // Add doubly linked-list operations.  AlignedChunk * getNext (void) { return next; }  AlignedChunk * getPrev (void) { return prev; }   void setNext (AlignedChunk * p) { next = p; }  void setPrev (AlignedChunk * p) { prev = p; } private:	enum { RELEASED = 0, ACQUIRED = 1 };  static inline size_t align (size_t sz) {    return (sz + (sizeof(double) - 1)) & ~(sizeof(double) - 1);  }	int inUse; // For debugging only.  unsigned long freeBitmap;	unsigned long emptyBitmap;	int status;  AlignedChunk * prev;  AlignedChunk * next;};// AlignedChunkHeap manages a number of chunks.template <int maxFree, int chunkSize, int slotSize, class Super>class AlignedChunkHeap : public Super {public:	AlignedChunkHeap (void)		: chunkList (NULL),		length (0)	{}	virtual ~AlignedChunkHeap (void)	{		chunkType * ch, * tmp;		ch = chunkList;		while (ch != NULL) {			tmp = ch;			ch = ch->getNext();			assert (tmp->isReleased());			Super::free ((char *) ((unsigned long) tmp & -chunkSize));		}	}	// Malloc a CHUNK. Returns a pointer to the start of the allocated block.	inline void * malloc (size_t sz)	{		assert (sz == chunkSize);		chunkType * ch;		// Get a chunk from our chunk list		// or make one.		if (chunkList != NULL) {			ch = chunkList;			chunkList = chunkList->getNext();			length--;			ch->acquire();		} else {			// Make a buffer large enough to hold the chunk.			void * buf = Super::malloc (chunkSize);			// The buffer MUST BE ALIGNED.			assert ((unsigned long) buf == ((unsigned long) buf & -chunkSize));			// Instantiate the chunk "header" (actually the footer)			// at the end of the chunk.			ch = new (chunkType::getChunk (buf)) chunkType;		}		// Now return the start of the chunk's buffer.		assert (!ch->isReleased());		return (void *) ((unsigned long) ch & -chunkSize);	}	// Free a CHUNK.	// The pointer is to the chunk header.	inline void free (void * ptr)	{		chunkType * ch = (chunkType *) AlignedChunk<chunkSize, slotSize>::getChunk(ptr);		assert (ch->isReleased());		if (length > maxFree) {			Super::free ((void *) ((unsigned long) ch & -chunkSize));		} else {		  ch->setNext (chunkList);		  chunkList = ch;			length++;		}	}	size_t size (void * ptr) {		return slotSize;	}private:	typedef AlignedChunk<chunkSize, slotSize> chunkType;	chunkType * chunkList;	int length;};// An AlignedSlotHeap holds at most one chunk.// When all of the slots are allocated from the chunk,// the chunk is "released" so that it may be freed back// to the super heap when all of its slots are freed.template <int chunkSize, int slotSize, class Super>class AlignedSlotHeap : public Super {public:	AlignedSlotHeap (void)		: myChunk (NULL)	{}	virtual ~AlignedSlotHeap (void) {		// Note that this is NOT enough to completely clean up after ourselves!!		if (myChunk != NULL) {			myChunk->release();			Super::free ((void *) ((unsigned long) myChunk & -chunkSize));		}	}	// Malloc a SLOT.	// Use up a chunk, if we've got one.	// Once it's used up, 'release it' and get another one.	inline void * malloc (size_t sz) {		assert (sz <= slotSize);		void * ptr = NULL;		while (ptr == NULL) {			if (myChunk == NULL) {				myChunk = AlignedChunk<chunkSize, slotSize>::getChunk(Super::malloc (chunkSize));			}			ptr = myChunk->getSlot();			if (ptr == NULL) {				// This chunk is completely in use.				// "Release" it.				myChunk->release();				myChunk = NULL;			}		};		return ptr;	}					// Free a SLOT.	// If the chunk is now completely empty and has been 'released',	// free the whole chunk.	inline void free (void * ptr)	{		// Find out which chunk this slot belongs to.		AlignedChunk<chunkSize, slotSize> * ch = AlignedChunk<chunkSize, slotSize>::getChunk (ptr);		// Return it to its chunk.		int empty = ch->putSlot (ptr);		if (empty && ch->isReleased()) {			Super::free ((void *) ((unsigned long) ch & -chunkSize));		}	}private:	// A one chunk buffer. Emptied when the chunk is completely allocated.	AlignedChunk<chunkSize, slotSize> * myChunk;};template <int maxFree, int chunkSize, int slotSize, class Super>class AlignedChunkHeapFoo : public AlignedSlotHeap<chunkSize, slotSize, AlignedChunkHeap<maxFree, chunkSize, slotSize, Super> > {};};#endif

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -