This commit is contained in:
Jeremy Hylton 2006-02-28 18:29:00 +00:00
parent 14ca327f99
commit 08533fdad6

View file

@ -4,8 +4,8 @@
/* An arena list is a linked list that can store PyObjects. */ /* An arena list is a linked list that can store PyObjects. */
typedef struct _arena_list { typedef struct _arena_list {
struct _arena_list *al_next; struct _arena_list *al_next;
void *al_pointer; void *al_pointer;
} PyArenaList; } PyArenaList;
/* A simple arena block structure */ /* A simple arena block structure */
@ -13,134 +13,137 @@ typedef struct _arena_list {
#define DEFAULT_BLOCK_SIZE 8192 #define DEFAULT_BLOCK_SIZE 8192
typedef struct _block { typedef struct _block {
size_t ab_size; size_t ab_size;
size_t ab_offset; size_t ab_offset;
struct _block *ab_next; struct _block *ab_next;
void *ab_mem; void *ab_mem;
} block; } block;
struct _arena { struct _arena {
block *a_head; block *a_head;
block *a_cur; block *a_cur;
PyArenaList *a_object_head; PyArenaList *a_object_head;
PyArenaList *a_object_tail; PyArenaList *a_object_tail;
}; };
static PyArenaList* static PyArenaList*
PyArenaList_New(void) PyArenaList_New(void)
{ {
PyArenaList *alist = (PyArenaList *)malloc(sizeof(PyArenaList)); PyArenaList *alist = (PyArenaList *)malloc(sizeof(PyArenaList));
if (!alist) if (!alist)
return NULL; return NULL;
alist->al_next = NULL; alist->al_next = NULL;
alist->al_pointer = NULL; alist->al_pointer = NULL;
return alist; return alist;
} }
static void static void
PyArenaList_FreeObject(PyArenaList *alist) PyArenaList_FreeObject(PyArenaList *alist)
{ {
while (alist) { while (alist) {
PyArenaList *prev; PyArenaList *prev;
Py_XDECREF((PyObject *)alist->al_pointer); Py_XDECREF((PyObject *)alist->al_pointer);
alist->al_pointer = NULL; alist->al_pointer = NULL;
prev = alist; prev = alist;
alist = alist->al_next; alist = alist->al_next;
free(prev); free(prev);
} }
} }
static block * static block *
block_new(size_t size) block_new(size_t size)
{ {
/* Allocate header and block as one unit. ab_mem points just past header. */ /* Allocate header and block as one unit.
block *b = (block *)malloc(sizeof(block) + size); ab_mem points just past header. */
if (!b) block *b = (block *)malloc(sizeof(block) + size);
return NULL; if (!b)
b->ab_size = size; return NULL;
b->ab_mem = (void *)(b + 1); b->ab_size = size;
b->ab_next = NULL; b->ab_mem = (void *)(b + 1);
b->ab_offset = 0; b->ab_next = NULL;
return b; b->ab_offset = 0;
return b;
} }
static void static void
block_free(block *b) { block_free(block *b) {
while (b) { while (b) {
block *next = b->ab_next; block *next = b->ab_next;
free(b); free(b);
b = next; b = next;
} }
} }
static void * static void *
block_alloc(block *b, size_t size) block_alloc(block *b, size_t size)
{ {
void *p; void *p;
assert(b); assert(b);
if (b->ab_offset + size > b->ab_size) { if (b->ab_offset + size > b->ab_size) {
/* If we need to allocate more memory than will fit in the default /* If we need to allocate more memory than will fit in
block, allocate a one-off block that is exactly the right size. */ the default block, allocate a one-off block that is
/* TODO(jhylton): Think more about space waste at end of block */ exactly the right size. */
block *new = block_new( /* TODO(jhylton): Think about space waste at end of block */
size < DEFAULT_BLOCK_SIZE ? DEFAULT_BLOCK_SIZE : size); block *new = block_new(
if (!new) size < DEFAULT_BLOCK_SIZE ?
return NULL; DEFAULT_BLOCK_SIZE : size);
assert(!b->ab_next); if (!new)
b->ab_next = new; return NULL;
b = new; assert(!b->ab_next);
} b->ab_next = new;
b = new;
}
assert(b->ab_offset + size <= b->ab_size); assert(b->ab_offset + size <= b->ab_size);
p = (void *)(((char *)b->ab_mem) + b->ab_offset); p = (void *)(((char *)b->ab_mem) + b->ab_offset);
b->ab_offset += size; b->ab_offset += size;
return p; return p;
} }
PyArena * PyArena *
PyArena_New() PyArena_New()
{ {
PyArena* arena = (PyArena *)malloc(sizeof(PyArena)); PyArena* arena = (PyArena *)malloc(sizeof(PyArena));
if (!arena) if (!arena)
return NULL; return NULL;
arena->a_head = block_new(DEFAULT_BLOCK_SIZE); arena->a_head = block_new(DEFAULT_BLOCK_SIZE);
arena->a_cur = arena->a_head; arena->a_cur = arena->a_head;
arena->a_object_head = PyArenaList_New(); arena->a_object_head = PyArenaList_New();
arena->a_object_tail = arena->a_object_head; arena->a_object_tail = arena->a_object_head;
return arena; return arena;
} }
void void
PyArena_Free(PyArena *arena) PyArena_Free(PyArena *arena)
{ {
assert(arena); assert(arena);
block_free(arena->a_head); block_free(arena->a_head);
PyArenaList_FreeObject(arena->a_object_head); PyArenaList_FreeObject(arena->a_object_head);
free(arena); free(arena);
} }
void * void *
PyArena_Malloc(PyArena *arena, size_t size) PyArena_Malloc(PyArena *arena, size_t size)
{ {
void *p = block_alloc(arena->a_cur, size); void *p = block_alloc(arena->a_cur, size);
if (!p) if (!p)
return NULL; return NULL;
/* Reset cur if we allocated a new block. */ /* Reset cur if we allocated a new block. */
if (arena->a_cur->ab_next) { if (arena->a_cur->ab_next) {
arena->a_cur = arena->a_cur->ab_next; arena->a_cur = arena->a_cur->ab_next;
} }
return p; return p;
} }
int int
PyArena_AddPyObject(PyArena *arena, PyObject *pointer) PyArena_AddPyObject(PyArena *arena, PyObject *pointer)
{ {
PyArenaList *tail = arena->a_object_tail; PyArenaList *tail = arena->a_object_tail;
assert(pointer); assert(pointer);
tail->al_next = PyArenaList_New(); tail->al_next = PyArenaList_New();
tail->al_pointer = pointer; tail->al_pointer = pointer;
arena->a_object_tail = tail->al_next; arena->a_object_tail = tail->al_next;
return 1; return 1;
} }