diff options
Diffstat (limited to 'Python/pyarena.c')
-rw-r--r-- | Python/pyarena.c | 300 |
1 files changed, 150 insertions, 150 deletions
diff --git a/Python/pyarena.c b/Python/pyarena.c index f4cc474..2d63638 100644 --- a/Python/pyarena.c +++ b/Python/pyarena.c @@ -12,32 +12,32 @@ */ #define DEFAULT_BLOCK_SIZE 8192 -#define ALIGNMENT 8 -#define ALIGNMENT_MASK (ALIGNMENT - 1) -#define ROUNDUP(x) (((x) + ALIGNMENT_MASK) & ~ALIGNMENT_MASK) +#define ALIGNMENT 8 +#define ALIGNMENT_MASK (ALIGNMENT - 1) +#define ROUNDUP(x) (((x) + ALIGNMENT_MASK) & ~ALIGNMENT_MASK) typedef struct _block { - /* Total number of bytes owned by this block available to pass out. - * Read-only after initialization. The first such byte starts at - * ab_mem. - */ - size_t ab_size; - - /* Total number of bytes already passed out. The next byte available - * to pass out starts at ab_mem + ab_offset. - */ - size_t ab_offset; - - /* An arena maintains a singly-linked, NULL-terminated list of - * all blocks owned by the arena. These are linked via the - * ab_next member. - */ - struct _block *ab_next; - - /* Pointer to the first allocatable byte owned by this block. Read- - * only after initialization. - */ - void *ab_mem; + /* Total number of bytes owned by this block available to pass out. + * Read-only after initialization. The first such byte starts at + * ab_mem. + */ + size_t ab_size; + + /* Total number of bytes already passed out. The next byte available + * to pass out starts at ab_mem + ab_offset. + */ + size_t ab_offset; + + /* An arena maintains a singly-linked, NULL-terminated list of + * all blocks owned by the arena. These are linked via the + * ab_next member. + */ + struct _block *ab_next; + + /* Pointer to the first allocatable byte owned by this block. Read- + * only after initialization. + */ + void *ab_mem; } block; /* The arena manages two kinds of memory, blocks of raw memory @@ -46,175 +46,175 @@ typedef struct _block { */ struct _arena { - /* Pointer to the first block allocated for the arena, never NULL. - It is used only to find the first block when the arena is - being freed. - */ - block *a_head; - - /* Pointer to the block currently used for allocation. It's - ab_next field should be NULL. If it is not-null after a - call to block_alloc(), it means a new block has been allocated - and a_cur should be reset to point it. - */ - block *a_cur; - - /* A Python list object containing references to all the PyObject - pointers associated with this area. They will be DECREFed - when the arena is freed. - */ - PyObject *a_objects; + /* Pointer to the first block allocated for the arena, never NULL. + It is used only to find the first block when the arena is + being freed. + */ + block *a_head; + + /* Pointer to the block currently used for allocation. It's + ab_next field should be NULL. If it is not-null after a + call to block_alloc(), it means a new block has been allocated + and a_cur should be reset to point it. + */ + block *a_cur; + + /* A Python list object containing references to all the PyObject + pointers associated with this area. They will be DECREFed + when the arena is freed. + */ + PyObject *a_objects; #if defined(Py_DEBUG) - /* Debug output */ - size_t total_allocs; - size_t total_size; - size_t total_blocks; - size_t total_block_size; - size_t total_big_blocks; + /* Debug output */ + size_t total_allocs; + size_t total_size; + size_t total_blocks; + size_t total_block_size; + size_t total_big_blocks; #endif }; static block * block_new(size_t size) { - /* Allocate header and block as one unit. - ab_mem points just past header. */ - block *b = (block *)malloc(sizeof(block) + size); - if (!b) - return NULL; - b->ab_size = size; - b->ab_mem = (void *)(b + 1); - b->ab_next = NULL; - b->ab_offset = ROUNDUP((Py_uintptr_t)(b->ab_mem)) - - (Py_uintptr_t)(b->ab_mem); - return b; + /* Allocate header and block as one unit. + ab_mem points just past header. */ + block *b = (block *)malloc(sizeof(block) + size); + if (!b) + return NULL; + b->ab_size = size; + b->ab_mem = (void *)(b + 1); + b->ab_next = NULL; + b->ab_offset = ROUNDUP((Py_uintptr_t)(b->ab_mem)) - + (Py_uintptr_t)(b->ab_mem); + return b; } static void block_free(block *b) { - while (b) { - block *next = b->ab_next; - free(b); - b = next; - } + while (b) { + block *next = b->ab_next; + free(b); + b = next; + } } static void * block_alloc(block *b, size_t size) { - void *p; - assert(b); - size = ROUNDUP(size); - if (b->ab_offset + size > b->ab_size) { - /* If we need to allocate more memory than will fit in - the default block, allocate a one-off block that is - exactly the right size. */ - /* TODO(jhylton): Think about space waste at end of block */ - block *newbl = block_new( - size < DEFAULT_BLOCK_SIZE ? - DEFAULT_BLOCK_SIZE : size); - if (!newbl) - return NULL; - assert(!b->ab_next); - b->ab_next = newbl; - b = newbl; - } - - assert(b->ab_offset + size <= b->ab_size); - p = (void *)(((char *)b->ab_mem) + b->ab_offset); - b->ab_offset += size; - return p; + void *p; + assert(b); + size = ROUNDUP(size); + if (b->ab_offset + size > b->ab_size) { + /* If we need to allocate more memory than will fit in + the default block, allocate a one-off block that is + exactly the right size. */ + /* TODO(jhylton): Think about space waste at end of block */ + block *newbl = block_new( + size < DEFAULT_BLOCK_SIZE ? + DEFAULT_BLOCK_SIZE : size); + if (!newbl) + return NULL; + assert(!b->ab_next); + b->ab_next = newbl; + b = newbl; + } + + assert(b->ab_offset + size <= b->ab_size); + p = (void *)(((char *)b->ab_mem) + b->ab_offset); + b->ab_offset += size; + return p; } PyArena * PyArena_New() { - PyArena* arena = (PyArena *)malloc(sizeof(PyArena)); - if (!arena) - return (PyArena*)PyErr_NoMemory(); - - arena->a_head = block_new(DEFAULT_BLOCK_SIZE); - arena->a_cur = arena->a_head; - if (!arena->a_head) { - free((void *)arena); - return (PyArena*)PyErr_NoMemory(); - } - arena->a_objects = PyList_New(0); - if (!arena->a_objects) { - block_free(arena->a_head); - free((void *)arena); - return (PyArena*)PyErr_NoMemory(); - } + PyArena* arena = (PyArena *)malloc(sizeof(PyArena)); + if (!arena) + return (PyArena*)PyErr_NoMemory(); + + arena->a_head = block_new(DEFAULT_BLOCK_SIZE); + arena->a_cur = arena->a_head; + if (!arena->a_head) { + free((void *)arena); + return (PyArena*)PyErr_NoMemory(); + } + arena->a_objects = PyList_New(0); + if (!arena->a_objects) { + block_free(arena->a_head); + free((void *)arena); + return (PyArena*)PyErr_NoMemory(); + } #if defined(Py_DEBUG) - arena->total_allocs = 0; - arena->total_size = 0; - arena->total_blocks = 1; - arena->total_block_size = DEFAULT_BLOCK_SIZE; - arena->total_big_blocks = 0; + arena->total_allocs = 0; + arena->total_size = 0; + arena->total_blocks = 1; + arena->total_block_size = DEFAULT_BLOCK_SIZE; + arena->total_big_blocks = 0; #endif - return arena; + return arena; } void PyArena_Free(PyArena *arena) { - int r; - assert(arena); + int r; + assert(arena); #if defined(Py_DEBUG) - /* - fprintf(stderr, - "alloc=%d size=%d blocks=%d block_size=%d big=%d objects=%d\n", - arena->total_allocs, arena->total_size, arena->total_blocks, - arena->total_block_size, arena->total_big_blocks, - PyList_Size(arena->a_objects)); - */ + /* + fprintf(stderr, + "alloc=%d size=%d blocks=%d block_size=%d big=%d objects=%d\n", + arena->total_allocs, arena->total_size, arena->total_blocks, + arena->total_block_size, arena->total_big_blocks, + PyList_Size(arena->a_objects)); + */ #endif - block_free(arena->a_head); - /* This property normally holds, except when the code being compiled - is sys.getobjects(0), in which case there will be two references. - assert(arena->a_objects->ob_refcnt == 1); - */ - - /* Clear all the elements from the list. This is necessary - to guarantee that they will be DECREFed. */ - r = PyList_SetSlice(arena->a_objects, - 0, PyList_GET_SIZE(arena->a_objects), NULL); - assert(r == 0); - assert(PyList_GET_SIZE(arena->a_objects) == 0); - Py_DECREF(arena->a_objects); - free(arena); + block_free(arena->a_head); + /* This property normally holds, except when the code being compiled + is sys.getobjects(0), in which case there will be two references. + assert(arena->a_objects->ob_refcnt == 1); + */ + + /* Clear all the elements from the list. This is necessary + to guarantee that they will be DECREFed. */ + r = PyList_SetSlice(arena->a_objects, + 0, PyList_GET_SIZE(arena->a_objects), NULL); + assert(r == 0); + assert(PyList_GET_SIZE(arena->a_objects) == 0); + Py_DECREF(arena->a_objects); + free(arena); } void * PyArena_Malloc(PyArena *arena, size_t size) { - void *p = block_alloc(arena->a_cur, size); - if (!p) - return PyErr_NoMemory(); + void *p = block_alloc(arena->a_cur, size); + if (!p) + return PyErr_NoMemory(); #if defined(Py_DEBUG) - arena->total_allocs++; - arena->total_size += size; + arena->total_allocs++; + arena->total_size += size; #endif - /* Reset cur if we allocated a new block. */ - if (arena->a_cur->ab_next) { - arena->a_cur = arena->a_cur->ab_next; + /* Reset cur if we allocated a new block. */ + if (arena->a_cur->ab_next) { + arena->a_cur = arena->a_cur->ab_next; #if defined(Py_DEBUG) - arena->total_blocks++; - arena->total_block_size += arena->a_cur->ab_size; - if (arena->a_cur->ab_size > DEFAULT_BLOCK_SIZE) - ++arena->total_big_blocks; + arena->total_blocks++; + arena->total_block_size += arena->a_cur->ab_size; + if (arena->a_cur->ab_size > DEFAULT_BLOCK_SIZE) + ++arena->total_big_blocks; #endif - } - return p; + } + return p; } int PyArena_AddPyObject(PyArena *arena, PyObject *obj) { - int r = PyList_Append(arena->a_objects, obj); - if (r >= 0) { - Py_DECREF(obj); - } - return r; + int r = PyList_Append(arena->a_objects, obj); + if (r >= 0) { + Py_DECREF(obj); + } + return r; } |