blob: 0b865db65ff4aa443b82aeebad9901013e0c2cca [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 Hylton08533fd2006-02-28 18:29:00 +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 {
Jeremy Hylton08533fd2006-02-28 18:29:00 +000016 size_t ab_size;
17 size_t ab_offset;
18 struct _block *ab_next;
19 void *ab_mem;
Jeremy Hylton77f1bb22006-02-28 17:53:04 +000020} block;
Neal Norwitzadb69fc2005-12-17 20:54:49 +000021
22struct _arena {
Jeremy Hylton08533fd2006-02-28 18:29:00 +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{
Jeremy Hylton08533fd2006-02-28 18:29:00 +000032 PyArenaList *alist = (PyArenaList *)malloc(sizeof(PyArenaList));
33 if (!alist)
34 return NULL;
Neal Norwitzadb69fc2005-12-17 20:54:49 +000035
Jeremy Hylton08533fd2006-02-28 18:29:00 +000036 alist->al_next = NULL;
37 alist->al_pointer = NULL;
38 return alist;
Neal Norwitzadb69fc2005-12-17 20:54:49 +000039}
40
41static void
42PyArenaList_FreeObject(PyArenaList *alist)
43{
Jeremy Hylton08533fd2006-02-28 18:29:00 +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 }
Jeremy Hylton77f1bb22006-02-28 17:53:04 +000052}
53
54static block *
55block_new(size_t size)
56{
Jeremy Hylton08533fd2006-02-28 18:29:00 +000057 /* Allocate header and block as one unit.
58 ab_mem points just past header. */
59 block *b = (block *)malloc(sizeof(block) + size);
60 if (!b)
61 return NULL;
62 b->ab_size = size;
63 b->ab_mem = (void *)(b + 1);
64 b->ab_next = NULL;
65 b->ab_offset = 0;
66 return b;
Neal Norwitzadb69fc2005-12-17 20:54:49 +000067}
68
69static void
Jeremy Hylton77f1bb22006-02-28 17:53:04 +000070block_free(block *b) {
Jeremy Hylton08533fd2006-02-28 18:29:00 +000071 while (b) {
72 block *next = b->ab_next;
73 free(b);
74 b = next;
75 }
Neal Norwitzadb69fc2005-12-17 20:54:49 +000076}
77
Jeremy Hylton77f1bb22006-02-28 17:53:04 +000078static void *
79block_alloc(block *b, size_t size)
80{
Jeremy Hylton08533fd2006-02-28 18:29:00 +000081 void *p;
82 assert(b);
83 if (b->ab_offset + size > b->ab_size) {
84 /* If we need to allocate more memory than will fit in
85 the default block, allocate a one-off block that is
86 exactly the right size. */
87 /* TODO(jhylton): Think about space waste at end of block */
88 block *new = block_new(
89 size < DEFAULT_BLOCK_SIZE ?
90 DEFAULT_BLOCK_SIZE : size);
91 if (!new)
92 return NULL;
93 assert(!b->ab_next);
94 b->ab_next = new;
95 b = new;
96 }
Jeremy Hylton77f1bb22006-02-28 17:53:04 +000097
Jeremy Hylton08533fd2006-02-28 18:29:00 +000098 assert(b->ab_offset + size <= b->ab_size);
99 p = (void *)(((char *)b->ab_mem) + b->ab_offset);
100 b->ab_offset += size;
101 return p;
Jeremy Hylton77f1bb22006-02-28 17:53:04 +0000102}
Neal Norwitzadb69fc2005-12-17 20:54:49 +0000103
104PyArena *
105PyArena_New()
106{
Jeremy Hylton08533fd2006-02-28 18:29:00 +0000107 PyArena* arena = (PyArena *)malloc(sizeof(PyArena));
108 if (!arena)
109 return NULL;
Neal Norwitzadb69fc2005-12-17 20:54:49 +0000110
Jeremy Hylton08533fd2006-02-28 18:29:00 +0000111 arena->a_head = block_new(DEFAULT_BLOCK_SIZE);
112 arena->a_cur = arena->a_head;
113 arena->a_object_head = PyArenaList_New();
114 arena->a_object_tail = arena->a_object_head;
115 return arena;
Neal Norwitzadb69fc2005-12-17 20:54:49 +0000116}
117
118void
119PyArena_Free(PyArena *arena)
120{
Jeremy Hylton08533fd2006-02-28 18:29:00 +0000121 assert(arena);
122 block_free(arena->a_head);
123 PyArenaList_FreeObject(arena->a_object_head);
124 free(arena);
Neal Norwitzadb69fc2005-12-17 20:54:49 +0000125}
126
127void *
128PyArena_Malloc(PyArena *arena, size_t size)
129{
Jeremy Hylton08533fd2006-02-28 18:29:00 +0000130 void *p = block_alloc(arena->a_cur, size);
131 if (!p)
132 return NULL;
133 /* Reset cur if we allocated a new block. */
134 if (arena->a_cur->ab_next) {
135 arena->a_cur = arena->a_cur->ab_next;
136 }
137 return p;
Neal Norwitzadb69fc2005-12-17 20:54:49 +0000138}
139
140int
141PyArena_AddPyObject(PyArena *arena, PyObject *pointer)
142{
Jeremy Hylton08533fd2006-02-28 18:29:00 +0000143 PyArenaList *tail = arena->a_object_tail;
144 assert(pointer);
145 tail->al_next = PyArenaList_New();
146 tail->al_pointer = pointer;
147 arena->a_object_tail = tail->al_next;
148 return 1;
Neal Norwitzadb69fc2005-12-17 20:54:49 +0000149}