initial add

This commit is contained in:
Jeremy Tregunna 2016-04-24 22:14:47 -06:00
commit bcb1714206
No known key found for this signature in database
GPG Key ID: 1A042D7269D00255
9 changed files with 451 additions and 0 deletions

36
.gitignore vendored Normal file
View File

@ -0,0 +1,36 @@
# Object files
*.o
*.ko
*.obj
*.elf
# Precompiled Headers
*.gch
*.pch
# Libraries
*.lib
*.a
*.la
*.lo
# Shared objects (inc. Windows DLLs)
*.dll
*.so
*.so.*
*.dylib
# Executables
*.exe
*.out
*.app
*.i*86
*.x86_64
*.hex
# Debug files
*.dSYM/
*.su
# Tests
tests

19
Makefile Normal file
View File

@ -0,0 +1,19 @@
CC=clang
CFLAGS=-Wall -Wextra -Werror -Os -I/usr/local/include
OBJECTS=refuse.o deque.o
LIB=librefuse.a
all: lib
lib: $(OBJECTS)
$(AR) rcs $(LIB) $(OBJECTS)
clean:
$(RM) $(OBJECTS) $(LIB) tests
test: lib
$(CC) $(CFLAGS) -I/usr/local/include tests.c -o tests librefuse.a -L/usr/local/lib -lcheck
.c.o:
$(CC) $(CFLAGS) -c $< -o $@

9
README.md Normal file
View File

@ -0,0 +1,9 @@
# Refuse
Refuse is an implementation of a garbage collector based on the idea of
deferring increments, allocating new objects as dead (reference count = 0), and
only marking objects as live, as references can be found. Additionally, the
object header to be used with the collector is packed for compactness. These
three things, should help increase performance substantially over standard
reference count garbage collectors.

115
deque.c Normal file
View File

@ -0,0 +1,115 @@
#include <stdlib.h>
#include <assert.h>
#include "deque.h"
typedef struct refnode_s
{
struct refnode_s* next;
struct refnode_s* prev;
refhdr_t* obj;
} refnode_t;
struct refdeque_s
{
refnode_t* head;
refnode_t* tail;
};
refdeque_t* refdeque_alloc()
{
refdeque_t* deque = malloc(sizeof(refdeque_t));
if(deque != NULL) {
deque->head = deque->tail = NULL;
}
return deque;
}
void refdeque_release(refdeque_t* deque)
{
free(deque);
deque = NULL;
}
bool refdeque_empty(refdeque_t* deque)
{
return deque->head == NULL;
}
void refdeque_push_front(refdeque_t* deque, refhdr_t* hdr)
{
refnode_t* node = malloc(sizeof(refnode_t));
assert(node != NULL);
node->obj = hdr;
node->next = deque->head;
node->prev = NULL;
if(deque->tail == NULL) {
deque->head = deque->tail = node;
} else {
deque->head->prev = node;
deque->head = node;
}
}
void refdeque_push_back(refdeque_t* deque, refhdr_t* hdr)
{
refnode_t* node = malloc(sizeof(refnode_t));
assert(node != NULL);
node->obj = hdr;
node->prev = deque->tail;
node->next = NULL;
if(deque->head == NULL) {
deque->head = deque->tail = node;
} else {
deque->tail->next = node;
deque->tail = node;
}
}
refhdr_t* refdeque_pop_front(refdeque_t* deque)
{
if(deque->head == NULL) {
return NULL;
}
refhdr_t* hdr = deque->head->obj;
refnode_t* node = deque->head;
if(deque->head == deque->tail) {
deque->head = deque->tail = NULL;
} else {
deque->head = node->next;
}
free(node);
return hdr;
}
refhdr_t* refdeque_pop_back(refdeque_t* deque)
{
if(deque->tail == NULL) {
return NULL;
}
refhdr_t* hdr = deque->tail->obj;
refnode_t* node = deque->tail;
if(deque->tail == deque->head) {
deque->tail = deque->head = NULL;
} else {
deque->tail = node->prev;
}
free(node);
return hdr;
}
void refdeque_foreach(refdeque_t* deque, void (^each)(refhdr_t* hdr))
{
if(deque->head == NULL) {
return;
}
refnode_t* current = deque->head;
while(current != NULL) {
if(each != NULL) {
each(current->obj);
}
current = current->next;
}
}

21
deque.h Normal file
View File

@ -0,0 +1,21 @@
// Refuse
// Copyright © 2016, Jeremy Tregunna, All Rights Reserved.
#ifndef __REFUSE__DEQUE_H__
#define __REFUSE__DEQUE_H__
#include <stdbool.h>
#include "types.h"
typedef struct refdeque_s refdeque_t;
refdeque_t* refdeque_alloc();
void refdeque_release(refdeque_t*);
bool refdeque_empty(refdeque_t*);
void refdeque_push_front(refdeque_t*, refhdr_t*);
void refdeque_push_back(refdeque_t*, refhdr_t*);
refhdr_t* refdeque_pop_front(refdeque_t*);
refhdr_t* refdeque_pop_back(refdeque_t*);
void refdeque_foreach(refdeque_t*, void (^)(refhdr_t*));
#endif // !__REFUSE__DEQUE_H__

92
refuse.c Normal file
View File

@ -0,0 +1,92 @@
#include <sys/types.h>
#include <stdio.h>
#include <stdlib.h>
#include "refuse.h"
static inline refhdr_t* _refuse_header(void* ptr)
{
return (refhdr_t*)((char*)ptr - sizeof(refhdr_t));
}
refuse_t* refuse_new(void)
{
refuse_t* refuse = malloc(sizeof(refuse_t));
refuse->dec = refdeque_alloc();
refuse->mod = refdeque_alloc();
return refuse;
}
void refuse_destroy(refuse_t* refuse)
{
refdeque_release(refuse->dec);
refdeque_release(refuse->mod);
free(refuse);
refuse = NULL;
}
void refuse_reconcile(refuse_t* refuse)
{
refhdr_t* h = refdeque_pop_front(refuse->mod);
while(h != NULL) {
if(h->new) {
h->new = 0;
}
if(h->dirty) {
h->dirty = 0;
} else {
h->retainCount++;
}
h = refdeque_pop_front(refuse->mod);
}
refhdr_t* hdr = refdeque_pop_front(refuse->dec);
while(hdr != NULL) {
hdr->retainCount--;
if(hdr->retainCount == 0) {
// Iterate children, delete children
free(hdr);
}
hdr = refdeque_pop_front(refuse->dec);
}
}
void* refuse_alloc(__unused refuse_t* refuse, size_t size)
{
refhdr_t* o = (refhdr_t*)calloc(sizeof(refhdr_t) + size, 1);
char* ptr = (char*)o + sizeof(refhdr_t);
o->new = 1;
o->dirty = 0;
o->retainCount = 0;
return ptr;
}
void refuse_set_dirty(__unused refuse_t* refuse, void* ptr)
{
refhdr_t* hdr = _refuse_header(ptr);
hdr->dirty = 1;
}
void refuse_retain(refuse_t* refuse, void* ptr)
{
refhdr_t* o;
char* cptr = (char*)ptr;
cptr -= sizeof(refhdr_t);
o = (refhdr_t*)cptr;
if(o->dirty) {
return;
}
refdeque_push_back(refuse->mod, o);
}
void refuse_release(refuse_t* refuse, void* ptr)
{
refhdr_t* hdr = _refuse_header(ptr);
refdeque_push_back(refuse->dec, hdr);
}

33
refuse.h Normal file
View File

@ -0,0 +1,33 @@
// Refuse
// Copyright © 2016, Jeremy Tregunna, All Rights Reserved.
#ifndef __REFUSE__REFUSE_H__
#define __REFUSE__REFUSE_H__
#ifdef __cplusplus
extern "C" {
#endif
#include <stdint.h>
#include "types.h"
#include "deque.h"
typedef struct
{
refdeque_t* dec;
refdeque_t* mod;
} refuse_t;
extern refuse_t* refuse_new(void);
extern void* refuse_alloc(refuse_t*, size_t);
extern void refuse_destroy(refuse_t*);
extern void refuse_set_dirty(refuse_t*, void*);
extern void refuse_reconcile(refuse_t*);
extern void refuse_retain(refuse_t*, void*);
extern void refuse_release(refuse_t*, void*);
#ifdef __cplusplus
}
#endif
#endif // !__REFUSE__REFUSE_H__

112
tests.c Normal file
View File

@ -0,0 +1,112 @@
#pragma GCC diagnostic ignored "-Wmissing-field-initializers"
#pragma GCC diagnostic ignored "-Wtype-limits"
#include <stdlib.h>
#include <check.h>
#include "refuse.h"
#include "deque.h"
struct mock
{
int a;
};
START_TEST(test_refuse_new)
{
refuse_t* refuse = refuse_new();
ck_assert(refuse != NULL);
}
END_TEST
START_TEST(test_refuse_alloc_1)
{
refuse_t* refuse = refuse_new();
struct mock* t = refuse_alloc(refuse, sizeof(struct mock));
ck_assert(t != NULL);
refhdr_t* hdr = (refhdr_t*)((char*)t - sizeof(refhdr_t));
ck_assert_int_eq(hdr->retainCount, 0);
ck_assert_int_eq(hdr->new, 1);
ck_assert_int_eq(hdr->dirty, 0);
}
END_TEST
START_TEST(test_refuse_retain_1)
{
refuse_t* refuse = refuse_new();
struct mock* t = refuse_alloc(refuse, sizeof(struct mock));
t->a = 42;
refuse_retain(refuse, t);
refhdr_t* hdr = (refhdr_t*)((char*)t - sizeof(refhdr_t));
ck_assert_int_eq(hdr->retainCount, 0);
ck_assert_int_eq(hdr->new, 1);
ck_assert_int_eq(hdr->dirty, 0);
refhdr_t* popped = refdeque_pop_back(refuse->mod);
struct mock* s = (struct mock*)((char*)popped + sizeof(refhdr_t));
ck_assert_int_eq(s->a, 42);
}
END_TEST
START_TEST(test_refuse_retain_2)
{
refuse_t* refuse = refuse_new();
struct mock* t = refuse_alloc(refuse, sizeof(struct mock));
refuse_retain(refuse, t);
refhdr_t* hdr = (refhdr_t*)((char*)t - sizeof(refhdr_t));
ck_assert_int_eq(hdr->retainCount, 0);
ck_assert_int_eq(hdr->new, 1);
ck_assert_int_eq(hdr->dirty, 0);
refuse_reconcile(refuse);
ck_assert_int_eq(hdr->new, 0);
ck_assert_int_eq(hdr->retainCount, 1);
}
END_TEST
START_TEST(test_refuse_release_1)
{
refuse_t* refuse = refuse_new();
struct mock* t = refuse_alloc(refuse, sizeof(struct mock));
refuse_retain(refuse, t);
refuse_reconcile(refuse);
refhdr_t* hdr = (refhdr_t*)((char*)t - sizeof(refhdr_t));
ck_assert_int_eq(hdr->retainCount, 1);
refuse_release(refuse, t);
ck_assert_int_eq(hdr->retainCount, 1);
refuse_reconcile(refuse);
ck_assert_int_eq(hdr->retainCount, 0);
}
END_TEST
static Suite* refuse_suite(void)
{
Suite *s = suite_create("refuse");
TCase* tc_refuse_new = tcase_create("refuse_new");
tcase_add_test(tc_refuse_new, test_refuse_new);
suite_add_tcase(s, tc_refuse_new);
TCase* tc_refuse_alloc = tcase_create("refuse_alloc");
tcase_add_test(tc_refuse_alloc, test_refuse_alloc_1);
suite_add_tcase(s, tc_refuse_alloc);
TCase* tc_refuse_retain = tcase_create("refuse_retain");
tcase_add_test(tc_refuse_retain, test_refuse_retain_1);
tcase_add_test(tc_refuse_retain, test_refuse_retain_2);
suite_add_tcase(s, tc_refuse_retain);
TCase* tc_refuse_release = tcase_create("refuse_release");
tcase_add_test(tc_refuse_release, test_refuse_release_1);
suite_add_tcase(s, tc_refuse_release);
return s;
}
int main(void)
{
int number_failed;
Suite *s = refuse_suite();
SRunner *sr = srunner_create(s);
srunner_run_all(sr, CK_NORMAL);
number_failed = srunner_ntests_failed(sr);
srunner_free(sr);
return (number_failed == 0) ? EXIT_SUCCESS : EXIT_FAILURE;
}

14
types.h Normal file
View File

@ -0,0 +1,14 @@
// Refuse
// Copyright © 2016, Jeremy Tregunna, All Rights Reserved.
#ifndef __REFUSE__TYPES_H__
#define __REFUSE__TYPES_H__
typedef struct refhdr_s
{
unsigned int retainCount:30;
unsigned int new:1;
unsigned int dirty:1;
} refhdr_t;
#endif // !__REFUSE__TYPES_H__