Neal Norwitz | adb69fc | 2005-12-17 20:54:49 +0000 | [diff] [blame] | 1 | #include "Python.h" |
| 2 | #include "pyarena.h" |
| 3 | |
| 4 | /* An arena list is a linked list that can store either pointers or |
| 5 | PyObjects. The type is clear from context. |
| 6 | */ |
| 7 | |
| 8 | typedef struct _arena_list { |
| 9 | struct _arena_list *al_next; |
| 10 | void *al_pointer; |
| 11 | } PyArenaList; |
| 12 | |
| 13 | /* There are two linked lists in an arena, one for malloc pointers and |
| 14 | one for PyObject. For each list, there is a pointer to the head |
| 15 | and to the tail. The head is used to free the list. The tail is |
| 16 | used to add a new element to the list. |
| 17 | |
| 18 | The list always keeps one un-used node at the end of the list. |
| 19 | */ |
| 20 | |
| 21 | struct _arena { |
| 22 | PyArenaList *a_malloc_head; |
| 23 | PyArenaList *a_malloc_tail; |
| 24 | PyArenaList *a_object_head; |
| 25 | PyArenaList *a_object_tail; |
| 26 | }; |
| 27 | |
| 28 | static PyArenaList* |
| 29 | PyArenaList_New(void) |
| 30 | { |
| 31 | PyArenaList *alist = (PyArenaList *)malloc(sizeof(PyArenaList)); |
| 32 | if (!alist) |
| 33 | return NULL; |
| 34 | |
| 35 | alist->al_next = NULL; |
| 36 | alist->al_pointer = NULL; |
| 37 | return alist; |
| 38 | } |
| 39 | |
| 40 | static void |
| 41 | PyArenaList_FreeObject(PyArenaList *alist) |
| 42 | { |
Neal Norwitz | adb69fc | 2005-12-17 20:54:49 +0000 | [diff] [blame] | 43 | while (alist) { |
| 44 | PyArenaList *prev; |
| 45 | Py_XDECREF((PyObject *)alist->al_pointer); |
| 46 | alist->al_pointer = NULL; |
| 47 | prev = alist; |
| 48 | alist = alist->al_next; |
| 49 | free(prev); |
| 50 | } |
| 51 | } |
| 52 | |
| 53 | static void |
| 54 | PyArenaList_FreeMalloc(PyArenaList *alist) |
| 55 | { |
Neal Norwitz | adb69fc | 2005-12-17 20:54:49 +0000 | [diff] [blame] | 56 | while (alist) { |
| 57 | PyArenaList *prev; |
| 58 | if (alist->al_pointer) { |
| 59 | free(alist->al_pointer); |
| 60 | } |
| 61 | alist->al_pointer = NULL; |
| 62 | prev = alist; |
| 63 | alist = alist->al_next; |
| 64 | free(prev); |
| 65 | } |
| 66 | } |
| 67 | |
| 68 | |
| 69 | PyArena * |
| 70 | PyArena_New() |
| 71 | { |
| 72 | PyArena* arena = (PyArena *)malloc(sizeof(PyArena)); |
| 73 | if (!arena) |
| 74 | return NULL; |
| 75 | |
| 76 | arena->a_object_head = PyArenaList_New(); |
| 77 | arena->a_object_tail = arena->a_object_head; |
| 78 | arena->a_malloc_head = PyArenaList_New(); |
| 79 | arena->a_malloc_tail = arena->a_malloc_head; |
| 80 | return arena; |
| 81 | } |
| 82 | |
| 83 | void |
| 84 | PyArena_Free(PyArena *arena) |
| 85 | { |
| 86 | assert(arena); |
| 87 | PyArenaList_FreeObject(arena->a_object_head); |
| 88 | PyArenaList_FreeMalloc(arena->a_malloc_head); |
| 89 | free(arena); |
| 90 | } |
| 91 | |
| 92 | void * |
| 93 | PyArena_Malloc(PyArena *arena, size_t size) |
| 94 | { |
| 95 | /* A better implementation might actually use an arena. The current |
| 96 | approach is just a trivial implementation of the API that allows |
| 97 | it to be tested. |
| 98 | */ |
| 99 | void *p; |
| 100 | assert(size != 0); |
| 101 | p = malloc(size); |
Neal Norwitz | 84456bd | 2005-12-18 03:16:20 +0000 | [diff] [blame^] | 102 | if (p) |
| 103 | PyArena_AddMallocPointer(arena, p); |
Neal Norwitz | adb69fc | 2005-12-17 20:54:49 +0000 | [diff] [blame] | 104 | return p; |
| 105 | } |
| 106 | |
| 107 | int |
| 108 | PyArena_AddMallocPointer(PyArena *arena, void *pointer) |
| 109 | { |
| 110 | assert(pointer); |
| 111 | PyArenaList *tail = arena->a_malloc_tail; |
| 112 | assert(tail->al_pointer != pointer); |
| 113 | tail->al_next = PyArenaList_New(); |
| 114 | tail->al_pointer = pointer; |
| 115 | arena->a_malloc_tail = tail->al_next; |
| 116 | return 1; |
| 117 | } |
| 118 | |
| 119 | int |
| 120 | PyArena_AddPyObject(PyArena *arena, PyObject *pointer) |
| 121 | { |
| 122 | assert(pointer); |
| 123 | PyArenaList *tail = arena->a_object_tail; |
| 124 | tail->al_next = PyArenaList_New(); |
| 125 | tail->al_pointer = pointer; |
| 126 | arena->a_object_tail = tail->al_next; |
| 127 | return 1; |
| 128 | } |