From e0429cf6cae3a0e424c3303ba285e2fbf39be45e Mon Sep 17 00:00:00 2001 From: Avril Date: Mon, 16 Nov 2020 15:22:09 +0000 Subject: [PATCH] start weak --- Makefile | 6 ++--- include/rc.h | 32 ++++++++++++++++++++++-- src/rc.c | 69 +++++++++++++++++++++++++++++++++++++++++++++++----- 3 files changed, 96 insertions(+), 11 deletions(-) diff --git a/Makefile b/Makefile index 762f9ff..5337336 100644 --- a/Makefile +++ b/Makefile @@ -1,10 +1,10 @@ SRC = $(wildcard src/*.c) INCLUDE = include -CFLAGS = -Wall $(addprefix -I,$(INCLUDE)) --std=gnu11 -pedantic -CFLAGS+= -O3 -flto -fgraphite +CFLAGS?= -O3 -flto -fgraphite +CFLAGS+= -Wall $(addprefix -I,$(INCLUDE)) --std=gnu11 -pedantic -LDFLAGS = -O3 -flto +LDFLAGS?= -O3 -flto OBJ:= obj diff --git a/include/rc.h b/include/rc.h index f23cb2a..d113d4b 100644 --- a/include/rc.h +++ b/include/rc.h @@ -1,6 +1,7 @@ #ifndef _RC_H #define _RC_H + #ifdef __cplusplus #define _rc_restrict __restrict extern "C" { @@ -8,17 +9,44 @@ extern "C" { #define _rc_restrict restrict #endif +#include + #ifndef __GNUC__ #define _rc_attr(_) #else #define _rc_attr(v) __attribute__(v) #endif +#define _rc_alloc_fn _rc_attr((returns_nonnull, malloc)) +#define _rc_gmut_fn _rc_attr((nonnull)) +#define _rc_mut_fn _rc_attr((pure, nonnull)) +#define _rc_fn _rc_attr((const, nonnull)) + +#if __bool_true_false_are_defined +#define RC_TRUE true +#define RC_FALSE false +typedef bool rc_bool; +#else +#define RC_TRUE 1 +#define RC_FALSE 0 +typedef int rc_bool; +#endif + typedef struct rc* rc_t; +typedef struct rc_weak rc_weak_t; + +typedef void* _rc_attr((may_alias)) rc_ptr_t; +typedef const void* _rc_attr((may_alias)) rc_const_ptr_t; void* _rc_restrict rc_malloc(size_t sz) _rc_attr((malloc, alloc_size(1), returns_nonnull)); -void rc_free(void* ptr) _rc_attr((nonnull)); -void* _rc_attr((may_alias)) rc_clone(void* ptr) _rc_attr((pure, nonnull, returns_nonnull)); +void rc_free(rc_ptr_t ptr) _rc_gmut_fn; +rc_ptr_t rc_clone(rc_const_ptr_t ptr) _rc_mut_fn _rc_attr((returns_nonnull)); + +size_t rc_refs(rc_const_ptr_t ptr)_rc_fn; +rc_bool rc_is_valid(rc_const_ptr_t ptr) _rc_fn; + +rc_weak_t* _rc_restrict rc_create_weak(rc_const_ptr_t ptr) _rc_gmut_fn _rc_alloc_fn; +void rc_weak_free(rc_weak_t* _rc_restrict ptr) _rc_gmut_fn; #ifdef __cplusplus } diff --git a/src/rc.c b/src/rc.c index 530ac2e..99baff0 100644 --- a/src/rc.c +++ b/src/rc.c @@ -7,13 +7,21 @@ #define RC_CHK 0xabadcafe + struct rc { uint32_t check; _Atomic size_t refs; + _Atomic size_t weak_refs; + //TODO: Keep all weak pointers here. rc_weak_free() should remove its own pointer address from that. uint8_t ptr[]; }; +struct rc_weak { + _Atomic int is_valid; + const struct rc* _rc_attr((may_alias)) _ptr; +}; + _rc_attr((noreturn)) static void panic(const char* string, ...) { va_list args; @@ -34,14 +42,26 @@ _rc_attr((noinline, noreturn, cold)) static void _fail_invptr() { panic("malloc() failed to allocate %d bytes (%d + sizeof(struct rc))", sz+sizeof(struct rc), sz); } +_rc_attr((artificial, const, always_inline)) inline static const struct rc* ptr_crev(const void* ptr) +{ + if (!ptr) _fail_invptr(); + return (const struct rc*)(((const uint8_t*)ptr) - sizeof(struct rc)); +} -_rc_attr((artificial, always_inline)) inline static rc_t ptr_rev(void* ptr) +_rc_attr((artificial, const, always_inline)) inline static rc_t ptr_rev(void* ptr) { if (!ptr) _fail_invptr(); return (rc_t)(((uint8_t*)ptr) - sizeof(struct rc)); } -_rc_attr((nonnull)) inline static void rc_checkptr(const rc_t rc) + +_rc_attr((artificial, const, always_inline)) inline static rc_t ptr_ucrev(const void* ptr) +{ + if (!ptr) _fail_invptr(); + return (rc_t)(((uintptr_t)ptr) - sizeof(struct rc)); +} + +_rc_attr((nonnull)) inline static void rc_checkptr(const struct rc* rc) { if (rc->check != RC_CHK) _fail_invptr(); } @@ -54,21 +74,58 @@ _rc_attr((nonnull)) inline static void rc_checkptr(const rc_t rc) rc->check = RC_CHK; rc->refs = 1; + rc->weak_refs =0; return (void*) rc->ptr; } - _rc_attr((nonnull)) void rc_free(void* ptr) + _rc_gmut_fn void rc_free(rc_ptr_t ptr) { register rc_t rc = ptr_rev(ptr); rc_checkptr(rc); if (!--rc->refs) free(rc); } -_rc_attr((pure, nonnull, returns_nonnull)) void* _rc_attr((may_alias)) rc_clone(void* ptr) +_rc_mut_fn _rc_attr((returns_nonnull)) rc_ptr_t rc_clone(rc_const_ptr_t ptr) { - register rc_t rc = ptr_rev(ptr); + register rc_t rc = ptr_ucrev(ptr); rc_checkptr(rc); ++rc->refs; - return ptr; + return rc->ptr; +} + +_rc_fn size_t rc_refs(rc_const_ptr_t ptr) +{ + register const struct rc* rc = ptr_crev(ptr); + rc_checkptr(rc); + return rc->refs; +} + +_rc_fn rc_bool rc_is_valid(rc_const_ptr_t ptr) +{ + register const struct rc* rc = ptr_crev(ptr); + return rc->check == RC_CHK + && rc->refs>0; +} + +_rc_alloc_fn _rc_gmut_fn rc_weak_t* _rc_restrict rc_create_weak(rc_const_ptr_t ptr) +{ + register rc_t rc = ptr_ucrev(ptr); + rc_weak_t* weak = calloc(sizeof(rc_weak_t), 1); + + weak->_ptr = rc; + weak->is_valid = 1; + + rc->weak_refs++; + return weak; +} + +_rc_gmut_fn void rc_weak_free(rc_weak_t* _rc_restrict ptr) +{ + if (ptr->is_valid) { + struct rc* _rc_attr((may_alias)) rc = (struct rc* _rc_attr((may_alias)))ptr->_ptr; + rc_checkptr(rc); + rc->weak_refs--; + } + free(ptr); }