Move GC code to separate source file.
This commit is contained in:
77
src/gc.c
Normal file
77
src/gc.c
Normal file
@@ -0,0 +1,77 @@
|
||||
#include "gc.h"
|
||||
#include "refcount.h"
|
||||
#include <stdlib.h>
|
||||
|
||||
void libab_gc_list_init(libab_gc_list* list) {
|
||||
list->head = list->tail = NULL;
|
||||
}
|
||||
|
||||
void _gc_count_visit(libab_ref_count* ref, libab_visitor_function_ptr func, void* data) {
|
||||
if(ref->strong && ref->visit_children) ref->visit_children(ref->data, func, data);
|
||||
}
|
||||
void libab_gc_visit(libab_ref* ref, libab_visitor_function_ptr func, void* data) {
|
||||
_gc_count_visit(ref->count, func, data);
|
||||
}
|
||||
|
||||
void _libab_gc_list_append(libab_gc_list* list,
|
||||
libab_ref_count* node) {
|
||||
if(node->next) node->next->prev = node->prev;
|
||||
if(node->prev) node->prev->next = node->next;
|
||||
|
||||
node->prev = list->tail;
|
||||
node->next = NULL;
|
||||
if(list->head) {
|
||||
list->tail->next = node;
|
||||
} else {
|
||||
list->head = node;
|
||||
}
|
||||
list->tail = node;
|
||||
}
|
||||
void libab_gc_add(libab_ref* ref,
|
||||
libab_visit_function_ptr visit_children,
|
||||
libab_gc_list* list) {
|
||||
ref->count->visit_children = visit_children;
|
||||
_libab_gc_list_append(list, ref->count);
|
||||
}
|
||||
|
||||
void _gc_decrement(libab_ref_count* count, void* data) {
|
||||
count->gc--;
|
||||
}
|
||||
void _gc_save(libab_ref_count* count, void* data) {
|
||||
libab_gc_list* list = data;
|
||||
if(count->gc != -1) {
|
||||
count->gc = -1;
|
||||
_libab_gc_list_append(list, count);
|
||||
_gc_count_visit(count, _gc_save, data);
|
||||
}
|
||||
}
|
||||
|
||||
void libab_gc_run(libab_gc_list* list) {
|
||||
libab_gc_list safe;
|
||||
libab_ref_count* head;
|
||||
size_t count = 0;
|
||||
|
||||
head = list->head;
|
||||
while(head) {
|
||||
head->gc = head->weak;
|
||||
}
|
||||
|
||||
head = list->head;
|
||||
while(head) {
|
||||
_gc_count_visit(head, _gc_decrement, NULL);
|
||||
}
|
||||
|
||||
head = list->head;
|
||||
while(head) {
|
||||
_gc_count_visit(head, _gc_save, &safe);
|
||||
}
|
||||
|
||||
head = list->head;
|
||||
while(head) {
|
||||
count++;
|
||||
}
|
||||
printf("Can free %d\n", count);
|
||||
|
||||
list->head = safe.head;
|
||||
list->tail = safe.tail;
|
||||
}
|
||||
@@ -21,76 +21,6 @@ libab_result libab_ref_new(libab_ref* ref, void* data,
|
||||
|
||||
void libab_ref_null(libab_ref* ref) { ref->null = 1; }
|
||||
|
||||
void _ref_gc_count_visit(libab_ref_count* ref, libab_visitor_function_ptr func, void* data) {
|
||||
if(ref->strong && ref->visit_children) ref->visit_children(ref->data, func, data);
|
||||
}
|
||||
void libab_ref_gc_visit(libab_ref* ref, libab_visitor_function_ptr func, void* data) {
|
||||
_ref_gc_count_visit(ref->count, func, data);
|
||||
}
|
||||
|
||||
void _libab_ref_gc_list_append(libab_ref_gc_list* list,
|
||||
libab_ref_count* node) {
|
||||
if(node->next) node->next->prev = node->prev;
|
||||
if(node->prev) node->prev->next = node->next;
|
||||
|
||||
node->prev = list->tail;
|
||||
node->next = NULL;
|
||||
if(list->head) {
|
||||
list->tail->next = node;
|
||||
} else {
|
||||
list->head = node;
|
||||
}
|
||||
list->tail = node;
|
||||
}
|
||||
void libab_ref_gc_add(libab_ref* ref,
|
||||
libab_visit_function_ptr visit_children,
|
||||
libab_ref_gc_list* list) {
|
||||
ref->count->visit_children = visit_children;
|
||||
_libab_ref_gc_list_append(list, ref->count);
|
||||
}
|
||||
|
||||
void _ref_gc_decrement(libab_ref_count* count, void* data) {
|
||||
count->gc--;
|
||||
}
|
||||
void _ref_gc_save(libab_ref_count* count, void* data) {
|
||||
libab_ref_gc_list* list = data;
|
||||
if(count->gc != -1) {
|
||||
count->gc = -1;
|
||||
_libab_ref_gc_list_append(list, count);
|
||||
_ref_gc_count_visit(count, _ref_gc_save, data);
|
||||
}
|
||||
}
|
||||
|
||||
void libab_ref_gc_run(libab_ref_gc_list* list) {
|
||||
libab_ref_gc_list safe;
|
||||
libab_ref_count* head;
|
||||
size_t count = 0;
|
||||
|
||||
head = list->head;
|
||||
while(head) {
|
||||
head->gc = head->weak;
|
||||
}
|
||||
|
||||
head = list->head;
|
||||
while(head) {
|
||||
_ref_gc_count_visit(head, _ref_gc_decrement, NULL);
|
||||
}
|
||||
|
||||
head = list->head;
|
||||
while(head) {
|
||||
_ref_gc_count_visit(head, _ref_gc_save, &safe);
|
||||
}
|
||||
|
||||
head = list->head;
|
||||
while(head) {
|
||||
count++;
|
||||
}
|
||||
printf("Can free %d\n", count);
|
||||
|
||||
list->head = safe.head;
|
||||
list->tail = safe.tail;
|
||||
}
|
||||
|
||||
void _libab_ref_changed(libab_ref* ref) {
|
||||
if (ref->count->strong == 0) {
|
||||
ref->count->strong--;
|
||||
|
||||
Reference in New Issue
Block a user