commit
0e3c5739c3
@ -0,0 +1,4 @@
|
||||
*.o
|
||||
*~
|
||||
*.a
|
||||
*.so
|
@ -0,0 +1,39 @@
|
||||
SRC = $(wildcard src/*.c)
|
||||
INCLUDE = include
|
||||
|
||||
CFLAGS = -Wall $(addprefix -I,$(INCLUDE)) --std=gnu11 -pedantic
|
||||
CFLAGS+= -O3 -flto -fgraphite
|
||||
|
||||
LDFLAGS = -O3 -flto
|
||||
|
||||
OBJ:= obj
|
||||
|
||||
STATIC = $(addprefix $(OBJ)/static/,$(SRC:.c=.o))
|
||||
SHARED = $(addprefix $(OBJ)/shared/,$(SRC:.c=.o))
|
||||
|
||||
BUILD = librc
|
||||
|
||||
.PHONY: all
|
||||
all: dirs $(BUILD)
|
||||
|
||||
dirs:
|
||||
@mkdir -p obj/{shared,static}/src
|
||||
|
||||
obj/static/%.o: %.c
|
||||
$(CC) -c $< $(CFLAGS) -o $@
|
||||
|
||||
obj/shared/%.o: %.c
|
||||
$(CC) -fPIC -c $< $(CFLAGS) -o $@
|
||||
|
||||
$(BUILD).a: $(STATIC)
|
||||
ar rcs $@ $^
|
||||
|
||||
$(BUILD).so: $(SHARED)
|
||||
$(CC) -shared $^ $(CFLAGS) -o $@ $(LDFLAGS)
|
||||
strip $@
|
||||
|
||||
$(BUILD): $(BUILD).a $(BUILD).so
|
||||
|
||||
clean:
|
||||
rm -f $(BUILD).{a,so}
|
||||
rm -rf obj
|
@ -0,0 +1,27 @@
|
||||
#ifndef _RC_H
|
||||
#define _RC_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
#define _rc_restrict __restrict
|
||||
extern "C" {
|
||||
#else
|
||||
#define _rc_restrict restrict
|
||||
#endif
|
||||
|
||||
#ifndef __GNUC__
|
||||
#define _rc_attr(_)
|
||||
#else
|
||||
#define _rc_attr(v) __attribute__(v)
|
||||
#endif
|
||||
|
||||
typedef struct rc* rc_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));
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* _RC_H */
|
@ -0,0 +1,74 @@
|
||||
#include <stdlib.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <stdarg.h>
|
||||
|
||||
#include <rc.h>
|
||||
|
||||
#define RC_CHK 0xabadcafe
|
||||
|
||||
struct rc {
|
||||
uint32_t check;
|
||||
_Atomic size_t refs;
|
||||
|
||||
uint8_t ptr[];
|
||||
};
|
||||
|
||||
_rc_attr((noreturn)) static void panic(const char* string, ...)
|
||||
{
|
||||
va_list args;
|
||||
va_start(args, string);
|
||||
fprintf(stderr, "(librc) Fatal error: ");
|
||||
vfprintf(stderr, string, args);
|
||||
va_end(args);
|
||||
fprintf(stderr, "\n");
|
||||
abort();
|
||||
}
|
||||
|
||||
_rc_attr((noinline, noreturn, cold)) static void _fail_invptr()
|
||||
{
|
||||
panic("Invalid RC pointer");
|
||||
}
|
||||
|
||||
_rc_attr((noinline, noreturn, cold)) static void _fail_malloc(size_t sz)
|
||||
{
|
||||
panic("malloc() failed to allocate %d bytes (%d + sizeof(struct rc))", sz+sizeof(struct rc), sz);
|
||||
}
|
||||
|
||||
_rc_attr((artificial, 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)
|
||||
{
|
||||
if (rc->check != RC_CHK) _fail_invptr();
|
||||
}
|
||||
|
||||
_rc_attr((malloc, alloc_size(1), returns_nonnull)) void* restrict rc_malloc(size_t sz)
|
||||
{
|
||||
register rc_t rc = malloc(sz + sizeof(struct rc));
|
||||
|
||||
if (!rc) _fail_malloc(sz);
|
||||
|
||||
rc->check = RC_CHK;
|
||||
rc->refs = 1;
|
||||
|
||||
return (void*) rc->ptr;
|
||||
}
|
||||
|
||||
_rc_attr((nonnull)) void rc_free(void* 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)
|
||||
{
|
||||
register rc_t rc = ptr_rev(ptr);
|
||||
rc_checkptr(rc);
|
||||
++rc->refs;
|
||||
return ptr;
|
||||
}
|
Loading…
Reference in new issue