blob: 990589742b9af23c8543844691ca757d40f7dd00 [file] [log] [blame]
#pragma once
#include <pthread.h>
static void (* REF_free)(void *) = free;
static void * (* REF_realloc)(void *, size_t) = realloc;
static void * (* REF_malloc)(size_t) = malloc;
struct refcount_ {
pthread_mutex_t mux;
unsigned int count;
char data[];
};
#define ref_upcast(DAT) \
(struct refcount_ *)((char *)(DAT - offsetof(struct refcount_, data)))
#define ref_barrier(CODE) \
pthread_mutex_lock(&refc->mux); \
CODE \
pthread_mutex_unlock(&refc->mux)
static inline void
ref_init_functions(void *(*mallocf)(size_t),
void * (*callocf)(size_t, size_t),
void *(*reallocf)(void *, size_t),
void (* freef)(void *))
{
REF_malloc = mallocf;
REF_realloc = reallocf;
REF_free = freef;
}
static unsigned int
ref_inc(void * buf)
{
struct refcount_ * refc = ref_upcast(buf);
unsigned int refs;
ref_barrier({ refs = ++refc->count; });
return refs;
}
static unsigned int
ref_dec(void * buf)
{
struct refcount_ * refc = ref_upcast(buf);
unsigned int refs;
ref_barrier({ refc->count -= 1; refs = refc->count; });
return refs;
}
static inline void *
ref_malloc(size_t size)
{
struct refcount_ * refc;
pthread_mutexattr_t attr;
refc = REF_malloc(sizeof(*refc) + size);
refc->count = 1;
pthread_mutexattr_init(&attr);
pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE);
pthread_mutex_init(&refc->mux, &attr);
return refc->data;
}
static void
ref_free(void * buf)
{
struct refcount_ * refc = ref_upcast(buf);
ref_barrier({
if (--refc->count == 0)
{
pthread_mutex_unlock(&refc->mux);
return REF_free(refc);
}
});
}