mirror of
https://github.com/RPCS3/llvm-mirror.git
synced 2024-11-23 19:23:23 +01:00
Initial checkin of pool allocator library
llvm-svn: 5429
This commit is contained in:
parent
649a63bd45
commit
e40d684a50
4
runtime/GCCLibraries/libpoolalloc/Makefile
Normal file
4
runtime/GCCLibraries/libpoolalloc/Makefile
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
LEVEL = ../../..
|
||||||
|
LIBNAME = poolalloc
|
||||||
|
include ../Makefile.libs
|
||||||
|
|
166
runtime/GCCLibraries/libpoolalloc/PoolAllocatorChained.c
Normal file
166
runtime/GCCLibraries/libpoolalloc/PoolAllocatorChained.c
Normal file
@ -0,0 +1,166 @@
|
|||||||
|
#include <assert.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
|
||||||
|
#undef assert
|
||||||
|
#define assert(X)
|
||||||
|
|
||||||
|
|
||||||
|
#define NODES_PER_SLAB 512
|
||||||
|
|
||||||
|
typedef struct PoolTy {
|
||||||
|
void *Data;
|
||||||
|
unsigned NodeSize;
|
||||||
|
} PoolTy;
|
||||||
|
|
||||||
|
/* PoolSlab Structure - Hold NODES_PER_SLAB objects of the current node type.
|
||||||
|
* Invariants: FirstUnused <= LastUsed+1
|
||||||
|
*/
|
||||||
|
typedef struct PoolSlab {
|
||||||
|
unsigned FirstUnused; /* First empty node in slab */
|
||||||
|
int LastUsed; /* Last allocated node in slab */
|
||||||
|
struct PoolSlab *Next;
|
||||||
|
unsigned char AllocatedBitVector[NODES_PER_SLAB/8];
|
||||||
|
char Data[1]; /* Buffer to hold data in this slab... variable sized */
|
||||||
|
} PoolSlab;
|
||||||
|
|
||||||
|
#define NODE_ALLOCATED(POOLSLAB, NODENUM) \
|
||||||
|
((POOLSLAB)->AllocatedBitVector[(NODENUM) >> 3] & (1 << ((NODENUM) & 7)))
|
||||||
|
#define MARK_NODE_ALLOCATED(POOLSLAB, NODENUM) \
|
||||||
|
(POOLSLAB)->AllocatedBitVector[(NODENUM) >> 3] |= 1 << ((NODENUM) & 7)
|
||||||
|
#define MARK_NODE_FREE(POOLSLAB, NODENUM) \
|
||||||
|
(POOLSLAB)->AllocatedBitVector[(NODENUM) >> 3] &= ~(1 << ((NODENUM) & 7))
|
||||||
|
|
||||||
|
|
||||||
|
/* poolinit - Initialize a pool descriptor to empty
|
||||||
|
*/
|
||||||
|
void poolinit(PoolTy *Pool, unsigned Size) {
|
||||||
|
assert(Pool && "Null pool pointer passed in!");
|
||||||
|
|
||||||
|
Pool->NodeSize = Size;
|
||||||
|
Pool->Data = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* pooldestroy - Release all memory allocated for a pool
|
||||||
|
*/
|
||||||
|
void pooldestroy(PoolTy *Pool) {
|
||||||
|
PoolSlab *PS = (PoolSlab*)Pool->Data;
|
||||||
|
while (PS) {
|
||||||
|
PoolSlab *Next = PS->Next;
|
||||||
|
free(PS);
|
||||||
|
PS = Next;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void *FindSlabEntry(PoolSlab *PS, unsigned NodeSize) {
|
||||||
|
/* Loop through all of the slabs looking for one with an opening */
|
||||||
|
for (; PS; PS = PS->Next) {
|
||||||
|
/* Check to see if there are empty entries at the end of the slab... */
|
||||||
|
if (PS->LastUsed < NODES_PER_SLAB-1) {
|
||||||
|
/* Mark the returned entry used */
|
||||||
|
MARK_NODE_ALLOCATED(PS, PS->LastUsed+1);
|
||||||
|
|
||||||
|
/* If we are allocating out the first unused field, bump its index also */
|
||||||
|
if (PS->FirstUnused == PS->LastUsed+1)
|
||||||
|
PS->FirstUnused++;
|
||||||
|
|
||||||
|
/* Return the entry, increment LastUsed field. */
|
||||||
|
return &PS->Data[0] + ++PS->LastUsed * NodeSize;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* If not, check to see if this node has a declared "FirstUnused" value that
|
||||||
|
* is less than the number of nodes allocated...
|
||||||
|
*/
|
||||||
|
if (PS->FirstUnused < NODES_PER_SLAB) {
|
||||||
|
/* Successfully allocate out the first unused node */
|
||||||
|
unsigned Idx = PS->FirstUnused;
|
||||||
|
|
||||||
|
/* Increment FirstUnused to point to the new first unused value... */
|
||||||
|
do {
|
||||||
|
++PS->FirstUnused;
|
||||||
|
} while (PS->FirstUnused < NODES_PER_SLAB &&
|
||||||
|
NODE_ALLOCATED(PS, PS->FirstUnused));
|
||||||
|
|
||||||
|
return &PS->Data[0] + Idx*NodeSize;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* No empty nodes available, must grow # slabs! */
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
char *poolalloc(PoolTy *Pool) {
|
||||||
|
unsigned NodeSize = Pool->NodeSize;
|
||||||
|
PoolSlab *PS = (PoolSlab*)Pool->Data;
|
||||||
|
void *Result;
|
||||||
|
|
||||||
|
if ((Result = FindSlabEntry(PS, NodeSize)))
|
||||||
|
return Result;
|
||||||
|
|
||||||
|
/* Otherwise we must allocate a new slab and add it to the list */
|
||||||
|
PS = (PoolSlab*)malloc(sizeof(PoolSlab)+NodeSize*NODES_PER_SLAB-1);
|
||||||
|
|
||||||
|
/* Initialize the slab to indicate that the first element is allocated */
|
||||||
|
PS->FirstUnused = 1;
|
||||||
|
PS->LastUsed = 0;
|
||||||
|
PS->AllocatedBitVector[0] = 1;
|
||||||
|
|
||||||
|
/* Add the slab to the list... */
|
||||||
|
PS->Next = (PoolSlab*)Pool->Data;
|
||||||
|
Pool->Data = PS;
|
||||||
|
return &PS->Data[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
void poolfree(PoolTy *Pool, char *Node) {
|
||||||
|
unsigned NodeSize = Pool->NodeSize, Idx;
|
||||||
|
PoolSlab *PS = (PoolSlab*)Pool->Data;
|
||||||
|
PoolSlab **PPS = (PoolSlab**)&Pool->Data;
|
||||||
|
|
||||||
|
/* Seach for the slab that contains this node... */
|
||||||
|
while (&PS->Data[0] > Node || &PS->Data[NodeSize*NODES_PER_SLAB] < Node) {
|
||||||
|
assert(PS && "free'd node not found in allocation pool specified!");
|
||||||
|
PPS = &PS->Next;
|
||||||
|
PS = PS->Next;
|
||||||
|
}
|
||||||
|
|
||||||
|
Idx = (Node-&PS->Data[0])/NodeSize;
|
||||||
|
assert(Idx < NODES_PER_SLAB && "Pool slab searching loop broken!");
|
||||||
|
|
||||||
|
/* Update the first free field if this node is below the free node line */
|
||||||
|
if (Idx < PS->FirstUnused) PS->FirstUnused = Idx;
|
||||||
|
|
||||||
|
/* If we are not freeing the last element in a slab... */
|
||||||
|
if (Idx != PS->LastUsed) {
|
||||||
|
MARK_NODE_FREE(PS, Idx);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Otherwise we are freeing the last element in a slab... shrink the
|
||||||
|
* LastUsed marker down to last used node.
|
||||||
|
*/
|
||||||
|
do {
|
||||||
|
--PS->LastUsed;
|
||||||
|
/* Fixme, this should scan the allocated array an entire byte at a time for
|
||||||
|
* performance!
|
||||||
|
*/
|
||||||
|
} while (PS->LastUsed >= 0 && (!NODE_ALLOCATED(PS, PS->LastUsed)));
|
||||||
|
|
||||||
|
assert(PS->FirstUnused <= PS->LastUsed+1 &&
|
||||||
|
"FirstUnused field was out of date!");
|
||||||
|
|
||||||
|
/* Ok, if this slab is empty, we unlink it from the of slabs and either move
|
||||||
|
* it to the head of the list, or free it, depending on whether or not there
|
||||||
|
* is already an empty slab at the head of the list.
|
||||||
|
*/
|
||||||
|
if (PS->LastUsed == -1) { /* Empty slab? */
|
||||||
|
PoolSlab *HeadSlab;
|
||||||
|
*PPS = PS->Next; /* Unlink from the list of slabs... */
|
||||||
|
|
||||||
|
HeadSlab = (PoolSlab*)Pool->Data;
|
||||||
|
if (HeadSlab && HeadSlab->LastUsed == -1){/* List already has empty slab? */
|
||||||
|
free(PS); /* Free memory for slab */
|
||||||
|
} else {
|
||||||
|
PS->Next = HeadSlab; /* No empty slab yet, add this */
|
||||||
|
Pool->Data = PS; /* one to the head of the list */
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user