mirror of
				https://github.com/python/cpython.git
				synced 2025-10-31 13:41:24 +00:00 
			
		
		
		
	
		
			
				
	
	
		
			128 lines
		
	
	
	
		
			2.7 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			128 lines
		
	
	
	
		
			2.7 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
| #include "Python.h"
 | |
| #include "pyarena.h"
 | |
| 
 | |
| /* An arena list is a linked list that can store either pointers or
 | |
|    PyObjects.  The type is clear from context.
 | |
|  */
 | |
| 
 | |
| typedef struct _arena_list {
 | |
|   struct _arena_list *al_next;
 | |
|   void *al_pointer;
 | |
| } PyArenaList;
 | |
| 
 | |
| /* There are two linked lists in an arena, one for malloc pointers and
 | |
|    one for PyObject.  For each list, there is a pointer to the head
 | |
|    and to the tail.  The head is used to free the list.  The tail is
 | |
|    used to add a new element to the list.
 | |
| 
 | |
|    The list always keeps one un-used node at the end of the list.
 | |
| */
 | |
| 
 | |
| struct _arena {
 | |
|   PyArenaList *a_malloc_head;
 | |
|   PyArenaList *a_malloc_tail;
 | |
|   PyArenaList *a_object_head;
 | |
|   PyArenaList *a_object_tail;
 | |
| };
 | |
| 
 | |
| static PyArenaList*
 | |
| PyArenaList_New(void) 
 | |
| {
 | |
|   PyArenaList *alist = (PyArenaList *)malloc(sizeof(PyArenaList));
 | |
|   if (!alist)
 | |
|     return NULL;
 | |
| 
 | |
|   alist->al_next = NULL;
 | |
|   alist->al_pointer = NULL;
 | |
|   return alist;
 | |
| }
 | |
| 
 | |
| static void
 | |
| PyArenaList_FreeObject(PyArenaList *alist) 
 | |
| {
 | |
|   while (alist) {
 | |
|     PyArenaList *prev;
 | |
|     Py_XDECREF((PyObject *)alist->al_pointer);
 | |
|     alist->al_pointer = NULL;
 | |
|     prev = alist;
 | |
|     alist = alist->al_next;
 | |
|     free(prev);
 | |
|   }
 | |
| }
 | |
| 
 | |
| static void
 | |
| PyArenaList_FreeMalloc(PyArenaList *alist)
 | |
| {
 | |
|   while (alist) {
 | |
|     PyArenaList *prev;
 | |
|     if (alist->al_pointer) {
 | |
|       free(alist->al_pointer);
 | |
|     }
 | |
|     alist->al_pointer = NULL;
 | |
|     prev = alist;
 | |
|     alist = alist->al_next;
 | |
|     free(prev);
 | |
|   }
 | |
| }
 | |
| 
 | |
| 
 | |
| PyArena *
 | |
| PyArena_New()
 | |
| {
 | |
|   PyArena* arena = (PyArena *)malloc(sizeof(PyArena));
 | |
|   if (!arena)
 | |
|     return NULL;
 | |
| 
 | |
|   arena->a_object_head = PyArenaList_New();
 | |
|   arena->a_object_tail = arena->a_object_head;
 | |
|   arena->a_malloc_head = PyArenaList_New();
 | |
|   arena->a_malloc_tail = arena->a_malloc_head;
 | |
|   return arena;
 | |
| }
 | |
| 
 | |
| void
 | |
| PyArena_Free(PyArena *arena)
 | |
| {
 | |
|   assert(arena);
 | |
|   PyArenaList_FreeObject(arena->a_object_head);
 | |
|   PyArenaList_FreeMalloc(arena->a_malloc_head);
 | |
|   free(arena);
 | |
| }
 | |
| 
 | |
| void *
 | |
| PyArena_Malloc(PyArena *arena, size_t size) 
 | |
| {
 | |
|   /* A better implementation might actually use an arena.  The current
 | |
|      approach is just a trivial implementation of the API that allows
 | |
|      it to be tested.
 | |
|   */
 | |
|   void *p;
 | |
|   assert(size != 0);
 | |
|   p = malloc(size);
 | |
|   if (p)
 | |
|     PyArena_AddMallocPointer(arena, p);
 | |
|   return p;
 | |
| }
 | |
| 
 | |
| int
 | |
| PyArena_AddMallocPointer(PyArena *arena, void *pointer) 
 | |
| {
 | |
|   PyArenaList *tail = arena->a_malloc_tail;
 | |
|   assert(pointer);
 | |
|   assert(tail->al_pointer != pointer);
 | |
|   tail->al_next = PyArenaList_New();
 | |
|   tail->al_pointer = pointer;
 | |
|   arena->a_malloc_tail = tail->al_next;
 | |
|   return 1;
 | |
| }
 | |
| 
 | |
| int
 | |
| PyArena_AddPyObject(PyArena *arena, PyObject *pointer) 
 | |
| {
 | |
|   PyArenaList *tail = arena->a_object_tail;
 | |
|   assert(pointer);
 | |
|   tail->al_next = PyArenaList_New();
 | |
|   tail->al_pointer = pointer;
 | |
|   arena->a_object_tail = tail->al_next;
 | |
|   return 1;
 | |
| }
 | 
