blob: 84c015ff5e10d7a6b2d635e0dc380cafbb086ef0 [file] [log] [blame]
Neal Norwitzadb69fc2005-12-17 20:54:49 +00001#include "Python.h"
2#include "pyarena.h"
3
Jeremy Hylton77f1bb22006-02-28 17:53:04 +00004/* An arena list is a linked list that can store PyObjects. */
Neal Norwitzadb69fc2005-12-17 20:54:49 +00005
6typedef struct _arena_list {
Jeremy Hylton77f1bb22006-02-28 17:53:04 +00007 struct _arena_list *al_next;
8 void *al_pointer;
Neal Norwitzadb69fc2005-12-17 20:54:49 +00009} PyArenaList;
10
Jeremy Hylton77f1bb22006-02-28 17:53:04 +000011/* A simple arena block structure */
12/* TODO(jhylton): Measurement to justify block size. */
Neal Norwitzadb69fc2005-12-17 20:54:49 +000013
Jeremy Hylton77f1bb22006-02-28 17:53:04 +000014#define DEFAULT_BLOCK_SIZE 8192
15typedef struct _block {
16 size_t ab_size;
17 size_t ab_offset;
18 struct _block *ab_next;
19 void *ab_mem;
20} block;
Neal Norwitzadb69fc2005-12-17 20:54:49 +000021
22struct _arena {
Jeremy Hylton77f1bb22006-02-28 17:53:04 +000023 block *a_head;
24 block *a_cur;
25 PyArenaList *a_object_head;
26 PyArenaList *a_object_tail;
Neal Norwitzadb69fc2005-12-17 20:54:49 +000027};
28
29static PyArenaList*
30PyArenaList_New(void)
31{
32 PyArenaList *alist = (PyArenaList *)malloc(sizeof(PyArenaList));
33 if (!alist)
34 return NULL;
35
36 alist->al_next = NULL;
37 alist->al_pointer = NULL;
38 return alist;
39}
40
41static void
42PyArenaList_FreeObject(PyArenaList *alist)
43{
Jeremy Hylton77f1bb22006-02-28 17:53:04 +000044 while (alist) {
45 PyArenaList *prev;
46 Py_XDECREF((PyObject *)alist->al_pointer);
47 alist->al_pointer = NULL;
48 prev = alist;
49 alist = alist->al_next;
50 free(prev);
51 }
52}
53
54static block *
55block_new(size_t size)
56{
57 /* Allocate header and block as one unit. ab_mem points just past header. */
58 block *b = (block *)malloc(sizeof(block) + size);
59 if (!b)
60 return NULL;
61 b->ab_size = size;
62 b->ab_mem = (void *)(b + 1);
63 b->ab_next = NULL;
64 b->ab_offset = 0;
65 return b;
Neal Norwitzadb69fc2005-12-17 20:54:49 +000066}
67
68static void
Jeremy Hylton77f1bb22006-02-28 17:53:04 +000069block_free(block *b) {
70 while (b) {
71 block *next = b->ab_next;
72 free(b);
73 b = next;
Neal Norwitzadb69fc2005-12-17 20:54:49 +000074 }
Neal Norwitzadb69fc2005-12-17 20:54:49 +000075}
76
Jeremy Hylton77f1bb22006-02-28 17:53:04 +000077static void *
78block_alloc(block *b, size_t size)
79{
80 void *p;
81 assert(b);
82 if (b->ab_offset + size > b->ab_size) {
83 /* If we need to allocate more memory than will fit in the default
84 block, allocate a one-off block that is exactly the right size. */
85 /* TODO(jhylton): Think more about space waste at end of block */
86 block *new = block_new(
87 size < DEFAULT_BLOCK_SIZE ? DEFAULT_BLOCK_SIZE : size);
88 if (!new)
89 return NULL;
90 assert(!b->ab_next);
91 b->ab_next = new;
92 b = new;
93 }
94
95 assert(b->ab_offset + size <= b->ab_size);
96 p = (void *)(((char *)b->ab_mem) + b->ab_offset);
97 b->ab_offset += size;
98 return p;
99}
Neal Norwitzadb69fc2005-12-17 20:54:49 +0000100
101PyArena *
102PyArena_New()
103{
104 PyArena* arena = (PyArena *)malloc(sizeof(PyArena));
105 if (!arena)
106 return NULL;
107
Jeremy Hylton77f1bb22006-02-28 17:53:04 +0000108 arena->a_head = block_new(DEFAULT_BLOCK_SIZE);
109 arena->a_cur = arena->a_head;
Neal Norwitzadb69fc2005-12-17 20:54:49 +0000110 arena->a_object_head = PyArenaList_New();
111 arena->a_object_tail = arena->a_object_head;
Neal Norwitzadb69fc2005-12-17 20:54:49 +0000112 return arena;
113}
114
115void
116PyArena_Free(PyArena *arena)
117{
Jeremy Hylton77f1bb22006-02-28 17:53:04 +0000118 assert(arena);
119 block_free(arena->a_head);
120 PyArenaList_FreeObject(arena->a_object_head);
121 free(arena);
Neal Norwitzadb69fc2005-12-17 20:54:49 +0000122}
123
124void *
125PyArena_Malloc(PyArena *arena, size_t size)
126{
Jeremy Hylton77f1bb22006-02-28 17:53:04 +0000127 void *p = block_alloc(arena->a_cur, size);
128 if (!p)
129 return NULL;
130 /* Reset cur if we allocated a new block. */
131 if (arena->a_cur->ab_next) {
132 arena->a_cur = arena->a_cur->ab_next;
133 }
134 return p;
Neal Norwitzadb69fc2005-12-17 20:54:49 +0000135}
136
137int
138PyArena_AddPyObject(PyArena *arena, PyObject *pointer)
139{
Neal Norwitzadb69fc2005-12-17 20:54:49 +0000140 PyArenaList *tail = arena->a_object_tail;
Fredrik Lundh93d69a72005-12-18 15:44:21 +0000141 assert(pointer);
Neal Norwitzadb69fc2005-12-17 20:54:49 +0000142 tail->al_next = PyArenaList_New();
143 tail->al_pointer = pointer;
144 arena->a_object_tail = tail->al_next;
145 return 1;
146}