blob: a262115bbf3564c42b411cd7ed744fc485df7bb7 [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{
Neal Norwitzadb69fc2005-12-17 20:54:49 +000043 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
53static void
54PyArenaList_FreeMalloc(PyArenaList *alist)
55{
Neal Norwitzadb69fc2005-12-17 20:54:49 +000056 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
69PyArena *
70PyArena_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
83void
84PyArena_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
92void *
93PyArena_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 Norwitz84456bd2005-12-18 03:16:20 +0000102 if (p)
103 PyArena_AddMallocPointer(arena, p);
Neal Norwitzadb69fc2005-12-17 20:54:49 +0000104 return p;
105}
106
107int
108PyArena_AddMallocPointer(PyArena *arena, void *pointer)
109{
Neal Norwitzadb69fc2005-12-17 20:54:49 +0000110 PyArenaList *tail = arena->a_malloc_tail;
Fredrik Lundh93d69a72005-12-18 15:44:21 +0000111 assert(pointer);
Neal Norwitzadb69fc2005-12-17 20:54:49 +0000112 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
119int
120PyArena_AddPyObject(PyArena *arena, PyObject *pointer)
121{
Neal Norwitzadb69fc2005-12-17 20:54:49 +0000122 PyArenaList *tail = arena->a_object_tail;
Fredrik Lundh93d69a72005-12-18 15:44:21 +0000123 assert(pointer);
Neal Norwitzadb69fc2005-12-17 20:54:49 +0000124 tail->al_next = PyArenaList_New();
125 tail->al_pointer = pointer;
126 arena->a_object_tail = tail->al_next;
127 return 1;
128}