Add multi-thread support

This commit is contained in:
2025-09-06 04:29:50 -07:00
parent 814234603d
commit 97d1b4a701
8 changed files with 277 additions and 151 deletions

View File

@ -5,6 +5,7 @@
#define INCLUDED_REFCOUNT_ALLOCATOR_H
#include <ht.h>
#include <refcount/config.h>
#include <stdbool.h>
#include <stddef.h>

View File

@ -0,0 +1,12 @@
#ifndef INCLUDED_REFCOUNT_CONFIG_H
#define INCLUDED_REFCOUNT_CONFIG_H
#cmakedefine REFCOUNT_HAS_THREADS
#if defined(REFCOUNT_HAS_THREADS) \
&& (!defined(__STDC_VERSION__) || __STDC_VERSION__ < 201112L)
# error \
"RefCount needs to be compiled with at least C11 for thread support to work."
#endif
#endif

View File

@ -5,6 +5,7 @@
#define INCLUDED_REFCOUNT_LIST_H
#include <refcount/allocator.h>
#include <refcount/config.h>
#include <stdarg.h>
#include <stddef.h> // for NULL

View File

@ -5,10 +5,16 @@
#define INCLUDED_REFCOUNT_REFCOUNT_H
#include <ht.h>
#include <refcount/config.h>
#include <refcount/list.h>
#include <stdbool.h>
#include <stdint.h>
#ifdef REFCOUNT_HAS_THREADS
# include <stdatomic.h>
# include <threads.h>
#endif
#ifdef __cplusplus
extern "C" {
#endif
@ -57,29 +63,12 @@ typedef struct RefcountContext {
RefcountList *static_objects; //!< List of static objects registered with
//!< this context.
RefcountList *gc_roots; //!< List of garbage collector roots.
#ifdef REFCOUNT_HAS_THREADS
mtx_t so_mtx; //<! Mutex protecting static_objects.
mtx_t gr_mtx; //<! Mutex protecting gc_roots.
#endif
} RefcountContext;
/**
* Enumeration of operations that may cause the debug breakpoint to be called.
*/
typedef enum {
REFCOUNT_OPER_DEINIT_STATIC,
REFCOUNT_OPER_FLOAT,
} RefcountOperation;
/**
* Type for a function to be called when some kind of error occurs. It should
* take a #RefcountOperation, a #RefcountContext pointer, and the object on
* which the error occurred.
* @param oper The operation that failed
* @param ctx The context the operation was performed on
* @param obj The object that caused the failure
*/
typedef void (*refcount_debug_callback_t)(RefcountOperation oper,
RefcountContext *ctx, void *obj);
extern refcount_debug_callback_t refcount_debug_breakpoint;
extern RefcountContext *refcount_default_context;
RefcountContext *
@ -90,6 +79,20 @@ refcount_make_context(size_t entry_offset,
void refcount_context_destroy(RefcountContext *ctx);
/**
* Structure holding the required information for a weak reference. That is, a
* reference that does not prevent an object from being de-allocated.
*/
typedef struct RefcountWeakref {
#ifdef REFCOUNT_HAS_THREADS
_Atomic uint64_t ref_count; //!< Reference count of this weakref (atomic).
mtx_t mtx; //!< Mutex protecting both the weakref and it's object.
#else
uint64_t ref_count; //!< Reference count of this weakref.
#endif
void *data; //<! The object this weak ref references (not the entry).
} RefcountWeakref;
/**
* Opaque struct holding reference data for an object. This should be included
* as a non-pointer member of the struct you are trying to track, e.g.
@ -103,8 +106,7 @@ void refcount_context_destroy(RefcountContext *ctx);
*/
typedef struct RefcountEntry {
bool is_static; //!< Whether the object is static.
RefcountList *weak_refs; //<! List of #RefcountWeakref structures for
//<! holding thread safe weak references.
RefcountWeakref *weak_ref; //<! Weakref for this entry.
union {
struct {
uint64_t ref_count; //!< The object's reference count.
@ -115,16 +117,6 @@ typedef struct RefcountEntry {
} impl;
} RefcountEntry;
/**
* Structure holding the required information for a weak reference. That is, a
* reference that does not prevent an object from being de-allocated.
*/
typedef struct RefcountWeakref {
RefcountList *entry; //!< Link in the #RefcountEntry list of the object this
//!< references that points to this reference.
void *data; //<! The object this weak ref references (not the entry).
} RefcountWeakref;
/**
* Return a pointer to the entry associated with an object.
* @param ctx The #RefcountContext
@ -154,12 +146,12 @@ static inline bool refcount_context_is_static(const RefcountContext *ctx,
* @param obj The object
* @return The number of references the object has
*/
static inline size_t refcount_context_num_refs(const RefcountContext *ctx,
void *obj) {
static inline uint64_t refcount_context_num_refs(const RefcountContext *ctx,
void *obj) {
return REFCOUNT_OBJECT_ENTRY(ctx, obj)->impl.counted.ref_count;
}
void refcount_context_init_obj(const RefcountContext *ctx, void *obj);
bool refcount_context_init_obj(const RefcountContext *ctx, void *obj);
bool refcount_context_init_static(RefcountContext *ctx, void *obj);
@ -199,19 +191,11 @@ RefcountWeakref *refcount_context_make_weakref(const RefcountContext *ctx,
void refcount_context_destroy_weakref(const RefcountContext *ctx,
RefcountWeakref *wr);
/**
* Return weather the object referenced by a weak reference still exists.
* @param ctx The #RefcountContext
* @param wr The weak reference
* @return Weather the reference is still valid
*/
static inline bool refcount_context_weakref_is_valid(const RefcountContext *ctx,
RefcountWeakref *wr) {
return wr->data;
}
bool refcount_context_weakref_is_valid(const RefcountContext *ctx,
RefcountWeakref *wr);
void *refcount_context_ref_weakref(const RefcountContext *ctx,
const RefcountWeakref *wr);
RefcountWeakref *wr);
/**
* Convenience function that calls #refcount_context_ref_weakref followed by
@ -238,9 +222,6 @@ static inline void *refcount_context_strengthen(const RefcountContext *ctx,
static inline RefcountWeakref *refcount_context_weaken(RefcountContext *ctx,
void *obj) {
RefcountWeakref *wr = refcount_context_make_weakref(ctx, obj);
if (!wr) {
return NULL;
}
refcount_context_unref(ctx, obj);
return wr;
}