on master help sign in
Clean up C heap RTS code.
commit557fbe39b525e7ca62aa532dfcac8ae0ead8747d authorMatus Tejiscak <ziman@functor.sk> dateSun 24 Jan 2016, 18:33 (11 years ago) parent6b4cb6f
5 files changed+60−40
rts/idris_gc.c+3−3 rts/idris_heap.c+5−11 rts/idris_heap.h+31−7 rts/idris_rts.c+4−8 rts/idris_rts.h+17−11
rts/idris_gc.c+3−3
@@ -137,11 +137,11 @@ void idris_gc(VM* vm) {
137137 vm->heap.size += vm->heap.growth;
138138 }
139139
140− STATS_LEAVE_GC(vm->stats, vm->heap.size, vm->heap.next - vm->heap.heap)
141− HEAP_CHECK(vm)
142−
143140 // finally, sweep the C heap
144141 c_heap_sweep(&vm->c_heap);
142+
143+ STATS_LEAVE_GC(vm->stats, vm->heap.size, vm->heap.next - vm->heap.heap)
144+ HEAP_CHECK(vm)
145145}
146146
147147void idris_gcInfo(VM* vm, int doGC) {
rts/idris_heap.c+5−11
@@ -5,7 +5,7 @@
55#include <stddef.h>
66#include <stdio.h>
77
8−void c_heap_free(CHeapItem * item)
8+static void c_heap_free_item(CHeapItem * item)
99{
1010 // fix links
1111 if (item->next != NULL)
@@ -21,13 +21,7 @@ void c_heap_free(CHeapItem * item)
2121 free(item);
2222}
2323
24−CHeapItem * c_heap_allocate(size_t size, CDataFinalizer_t * finalizer)
25−{
26− void * data = (void *) malloc(size);
27− return c_heap_create_item(data, finalizer);
28−}
29−
30−CHeapItem * c_heap_create_item(void * data, CDataFinalizer_t * finalizer)
24+CHeapItem * c_heap_create_item(void * data, CDataFinalizer * finalizer)
3125{
3226 CHeapItem * item = (CHeapItem *) malloc(sizeof(CHeapItem));
3327
@@ -75,7 +69,7 @@ void c_heap_sweep(CHeap * heap)
7569 CHeapItem * unused_item = p;
7670 p = p->next;
7771
78− c_heap_free(unused_item);
72+ c_heap_free_item(unused_item);
7973 }
8074 }
8175}
@@ -89,11 +83,11 @@ void c_heap_destroy(CHeap * heap)
8983{
9084 while (heap->first != NULL)
9185 {
92− c_heap_free(heap->first); // will update heap->first via the backward link
86+ c_heap_free_item(heap->first); // will update heap->first via the backward link
9387 }
9488}
9589
96−/* Used for initializing the heap. */
90+/* Used for initializing the FP heap. */
9791void alloc_heap(Heap * h, size_t heap_size, size_t growth, char * old)
9892{
9993 char * mem = malloc(heap_size);
rts/idris_heap.h+31−7
@@ -6,32 +6,56 @@
66
77/* *** C heap ***
88 * Objects with finalizers. Mark&sweep-collected.
9+ *
10+ * The C heap is implemented as a doubly linked list
11+ * of pointers coupled with their finalizers.
912 */
1013
11−typedef void CDataFinalizer_t(void *);
14+typedef void CDataFinalizer(void *);
1215
1316typedef struct CHeapItem {
17+ /// Payload.
1418 void * data;
15− CDataFinalizer_t * finalizer; // should free() the passed data pointer, too
19+
20+ /// Finalizer that will be called on the payload pointer.
21+ /// Its job is to deallocate all associated resources,
22+ /// including the memory pointed to by `data` (if any).
23+ CDataFinalizer * finalizer;
24+
25+ /// The mark bit set by the FP heap traversal,
26+ /// cleared by C heap sweep.
1627 bool is_used;
28+
29+ /// Next item in the C heap.
1730 struct CHeapItem * next;
31+
32+ /// Pointer to the previous next-pointer.
1833 struct CHeapItem ** prev_next;
1934} CHeapItem;
2035
2136typedef struct CHeap {
37+ /// The first item in the heap. NULL if the heap is empty.
2238 CHeapItem * first;
2339} CHeap;
2440
41+/// Create a C heap.
2542void c_heap_init(CHeap * c_heap);
26−void c_heap_destroy(CHeap * c_heap); // will call finalizers on everything
43+
44+/// Destroy the given C heap. Will not deallocate the given pointer.
45+/// Will call finalizers & deallocate all blocks in the heap.
46+void c_heap_destroy(CHeap * c_heap);
47+
48+/// Insert the given item into the heap if it's not there yet.
2749void c_heap_insert_if_needed(CHeap * c_heap, CHeapItem * item);
50+
51+/// Mark the given item as used.
2852void c_heap_mark_item(CHeapItem * item);
53+
54+/// Sweep the C heap, finalizing and freeing unused blocks.
2955void c_heap_sweep(CHeap * c_heap);
30−CHeapItem * c_heap_create_item(void * data, CDataFinalizer_t * finalizer);
3156
32−// this is the function to use in C binding code
33−CHeapItem * c_heap_allocate(size_t size, CDataFinalizer_t * finalizer);
34−void c_heap_free(CHeapItem * item);
57+/// Create a C heap item from its payload and finalizer.
58+CHeapItem * c_heap_create_item(void * data, CDataFinalizer * finalizer);
3559
3660/* *** Idris heap **
3761 * Objects without finalizers. Cheney-collected.
rts/idris_rts.c+4−8
@@ -127,21 +127,17 @@ Stats terminate(VM* vm) {
127127 return stats;
128128}
129129
130−CData cdata_allocate(size_t size, CDataFinalizer_t finalizer)
130+CData cdata_allocate(size_t size, CDataFinalizer finalizer)
131131{
132− return c_heap_allocate(size, finalizer);
132+ void * data = (void *) malloc(size);
133+ return cdata_manage(data, finalizer);
133134}
134135
135−CData cdata_manage(void * data, CDataFinalizer_t finalizer)
136+CData cdata_manage(void * data, CDataFinalizer finalizer)
136137{
137138 return c_heap_create_item(data, finalizer);
138139}
139140
140−void cdata_free(CData cd)
141−{
142− c_heap_free(cd);
143−}
144−
145141void idris_requireAlloc(size_t size) {
146142#ifdef HAS_PTHREAD
147143 VM* vm = pthread_getspecific(vm_key);
rts/idris_rts.h+17−11
@@ -119,21 +119,27 @@ typedef struct VM_t VM;
119119 *
120120 * Although not enforced in code, CData is meant to be opaque
121121 * and non-RTS code (such as libraries or C bindings) should
122− * access it only in the following three ways:
122+ * access only its (void *) field called "data".
123123 *
124− * CData cd = cdata_allocate(...);
125− * or
126− * void * ptr = malloc(...);
127− * CData cd = cdata_manage(ptr, ...);
128− *
129− * use(cd->data);
130− * cdata_free(cd); // optionally
124+ * Feel free to mutate cd->data; the heap does not care
125+ * about its particular value. However, keep in mind
126+ * that it must not break Idris's referential transparency.
131127 *
128+ * If you call cdata_allocate or cdata_manage, the resulting
129+ * CData object *must* be returned from your FFI function so
130+ * that it is inserted in the C heap. Otherwise the memory
131+ * will be leaked.
132132 */
133+
134+/// C data block. Contains (void * data).
133135typedef CHeapItem * CData;
134−CData cdata_manage(void * data, CDataFinalizer_t * finalizer);
135−CData cdata_allocate(size_t size, CDataFinalizer_t * finalizer);
136−void cdata_free(CData cd); // explicit freeing not required but available
136+
137+/// Allocate memory, returning the corresponding C data block.
138+CData cdata_allocate(size_t size, CDataFinalizer * finalizer);
139+
140+/// Wrap a pointer as a C data block.
141+CData cdata_manage(void * data, CDataFinalizer * finalizer);
142+
137143
138144// Create a new VM
139145VM* init_vm(int stack_size, size_t heap_size,