Mercurial > cpython-lru_cache-weakref
diff Python/pyarena.c @ 36065:ea083efdc96c legacy-trunk
Merge from ast-arena. This reduces the code in Python/ast.c by ~300 lines,
simplifies a lot of error handling code, and fixes many memory leaks.
| author | Neal Norwitz <nnorwitz@gmail.com> |
|---|---|
| date | Sat, 17 Dec 2005 20:54:49 +0000 |
| parents | |
| children | de16a85c3b4c |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Python/pyarena.c Sat Dec 17 20:54:49 2005 +0000 @@ -0,0 +1,133 @@ +#include "Python.h" +#include "pyarena.h" + +/* An arena list is a linked list that can store either pointers or + PyObjects. The type is clear from context. + */ + +typedef struct _arena_list { + struct _arena_list *al_next; + void *al_pointer; +} PyArenaList; + +/* There are two linked lists in an arena, one for malloc pointers and + one for PyObject. For each list, there is a pointer to the head + and to the tail. The head is used to free the list. The tail is + used to add a new element to the list. + + The list always keeps one un-used node at the end of the list. +*/ + +struct _arena { + PyArenaList *a_malloc_head; + PyArenaList *a_malloc_tail; + PyArenaList *a_object_head; + PyArenaList *a_object_tail; +}; + +static PyArenaList* +PyArenaList_New(void) +{ + PyArenaList *alist = (PyArenaList *)malloc(sizeof(PyArenaList)); + if (!alist) + return NULL; + + alist->al_next = NULL; + alist->al_pointer = NULL; + return alist; +} + +static void +PyArenaList_FreeObject(PyArenaList *alist) +{ + if (!alist) + return; + + while (alist) { + PyArenaList *prev; + Py_XDECREF((PyObject *)alist->al_pointer); + alist->al_pointer = NULL; + prev = alist; + alist = alist->al_next; + free(prev); + } +} + +static void +PyArenaList_FreeMalloc(PyArenaList *alist) +{ + if (!alist) + return; + + while (alist) { + PyArenaList *prev; + if (alist->al_pointer) { + free(alist->al_pointer); + } + alist->al_pointer = NULL; + prev = alist; + alist = alist->al_next; + free(prev); + } +} + + +PyArena * +PyArena_New() +{ + PyArena* arena = (PyArena *)malloc(sizeof(PyArena)); + if (!arena) + return NULL; + + arena->a_object_head = PyArenaList_New(); + arena->a_object_tail = arena->a_object_head; + arena->a_malloc_head = PyArenaList_New(); + arena->a_malloc_tail = arena->a_malloc_head; + return arena; +} + +void +PyArena_Free(PyArena *arena) +{ + assert(arena); + PyArenaList_FreeObject(arena->a_object_head); + PyArenaList_FreeMalloc(arena->a_malloc_head); + free(arena); +} + +void * +PyArena_Malloc(PyArena *arena, size_t size) +{ + /* A better implementation might actually use an arena. The current + approach is just a trivial implementation of the API that allows + it to be tested. + */ + void *p; + assert(size != 0); + p = malloc(size); + PyArena_AddMallocPointer(arena, p); + return p; +} + +int +PyArena_AddMallocPointer(PyArena *arena, void *pointer) +{ + assert(pointer); + PyArenaList *tail = arena->a_malloc_tail; + assert(tail->al_pointer != pointer); + tail->al_next = PyArenaList_New(); + tail->al_pointer = pointer; + arena->a_malloc_tail = tail->al_next; + return 1; +} + +int +PyArena_AddPyObject(PyArena *arena, PyObject *pointer) +{ + assert(pointer); + PyArenaList *tail = arena->a_object_tail; + tail->al_next = PyArenaList_New(); + tail->al_pointer = pointer; + arena->a_object_tail = tail->al_next; + return 1; +}
