blob: d67753215e12042e49b33bfb1356e2f5cbdd1c11 [file] [log] [blame]
Neal Norwitzadb69fc2005-12-17 20:54:49 +00001#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
8typedef 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
21struct _arena {
22 PyArenaList *a_malloc_head;
23 PyArenaList *a_malloc_tail;
24 PyArenaList *a_object_head;
25 PyArenaList *a_object_tail;
26};
27
28static PyArenaList*
29PyArenaList_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
40static void
41PyArenaList_FreeObject(PyArenaList *alist)
42{
43 if (!alist)
44 return;
45
46 while (alist) {
47 PyArenaList *prev;
48 Py_XDECREF((PyObject *)alist->al_pointer);
49 alist->al_pointer = NULL;
50 prev = alist;
51 alist = alist->al_next;
52 free(prev);
53 }
54}
55
56static void
57PyArenaList_FreeMalloc(PyArenaList *alist)
58{
59 if (!alist)
60 return;
61
62 while (alist) {
63 PyArenaList *prev;
64 if (alist->al_pointer) {
65 free(alist->al_pointer);
66 }
67 alist->al_pointer = NULL;
68 prev = alist;
69 alist = alist->al_next;
70 free(prev);
71 }
72}
73
74
75PyArena *
76PyArena_New()
77{
78 PyArena* arena = (PyArena *)malloc(sizeof(PyArena));
79 if (!arena)
80 return NULL;
81
82 arena->a_object_head = PyArenaList_New();
83 arena->a_object_tail = arena->a_object_head;
84 arena->a_malloc_head = PyArenaList_New();
85 arena->a_malloc_tail = arena->a_malloc_head;
86 return arena;
87}
88
89void
90PyArena_Free(PyArena *arena)
91{
92 assert(arena);
93 PyArenaList_FreeObject(arena->a_object_head);
94 PyArenaList_FreeMalloc(arena->a_malloc_head);
95 free(arena);
96}
97
98void *
99PyArena_Malloc(PyArena *arena, size_t size)
100{
101 /* A better implementation might actually use an arena. The current
102 approach is just a trivial implementation of the API that allows
103 it to be tested.
104 */
105 void *p;
106 assert(size != 0);
107 p = malloc(size);
108 PyArena_AddMallocPointer(arena, p);
109 return p;
110}
111
112int
113PyArena_AddMallocPointer(PyArena *arena, void *pointer)
114{
115 assert(pointer);
116 PyArenaList *tail = arena->a_malloc_tail;
117 assert(tail->al_pointer != pointer);
118 tail->al_next = PyArenaList_New();
119 tail->al_pointer = pointer;
120 arena->a_malloc_tail = tail->al_next;
121 return 1;
122}
123
124int
125PyArena_AddPyObject(PyArena *arena, PyObject *pointer)
126{
127 assert(pointer);
128 PyArenaList *tail = arena->a_object_tail;
129 tail->al_next = PyArenaList_New();
130 tail->al_pointer = pointer;
131 arena->a_object_tail = tail->al_next;
132 return 1;
133}