Add debug functions

This commit is contained in:
2025-09-09 05:45:57 -07:00
parent aec2f6145e
commit 403618888c
3 changed files with 69 additions and 1 deletions

View File

@ -454,6 +454,24 @@ static inline bool refcount_remove_destructor(void *obj, void *key) {
key);
}
// Debug Functions
uint64_t refcount_debug_context_count_object(const RefcountContext *ctx,
void *obj, void *target);
/**
* Same as #refcount_debug_context_count_object, but only operates on the global
* context.
* @param obj The root object
* @param target The object to look for
* @return The number of times the target appeared in the reference tree of the
* root
*/
static inline uint64_t refcount_debug_count_object(void *obj, void *target) {
return refcount_debug_context_count_object(refcount_default_context, obj,
target);
}
#ifdef __cplusplus
}
#endif

View File

@ -250,7 +250,7 @@ end:
* @param refs Where to store the refs
* @return True on success
*/
static inline bool obj_held_refs(RefcountContext *ctx, void *obj,
static inline bool obj_held_refs(const RefcountContext *ctx, void *obj,
RefcountList **refs) {
if (ctx->held_refs_callback) {
return ctx->held_refs_callback(obj, refs, ctx->user_data);
@ -843,3 +843,48 @@ bool refcount_context_remove_destructor(const RefcountContext *ctx, void *obj,
unlock_entry_mtx(ENTRY);
return success;
}
// Debug Functions
/**
* Count all instances of a target object by walking the references of some root
* object. This is for debug purposes only. The root is not included in the
* count (as in, if `obj == target`, it will not be counted).
* @param ctx The #RefcountContext
* @param obj The root object
* @param target The object to look for
* @return The number of times the target appeared in the reference tree of the
* root
*/
uint64_t refcount_debug_context_count_object(const RefcountContext *ctx,
void *obj, void *target) {
static const HTTableFunctions SEEN_FNS = {
.destroy_key = NULL,
.destroy_value = NULL,
.equal = ht_intptr_equal_callback,
.hash = ht_intptr_hash_callback,
.user_data = NULL,
};
if (!obj) {
return 0;
}
RefcountList *queue = NULL;
obj_held_refs(ctx, obj, &queue);
uint64_t total_count = 0;
HTTable *seen = ht_new(&SEEN_FNS, &ctx->ht_alloc, NULL);
while (queue) {
void *cur = queue->data;
queue = refcount_list_pop_full(queue, NULL, &ctx->alloc);
// count NULL
if (cur == target) {
++total_count;
}
// but don't try to descend into it
if (cur && !ht_has(seen, cur)) {
ht_insert(seen, cur, NULL);
obj_held_refs(ctx, cur, &queue);
}
}
ht_free(seen);
return total_count;
}

View File

@ -65,6 +65,10 @@ int main(int argc, const char **argv) {
STATIC_A(1);
STATIC_A(2);
STATIC_A(3);
assert(refcount_debug_context_count_object(c, &static_a_1, static_a_1.next)
== 1);
assert(refcount_debug_context_count_object(c, &static_a_1, static_a_2.next)
== 0);
A *a = make_a(c, 10, "Hello world\n");
assert(!refcount_context_is_static(c, a));
@ -124,6 +128,7 @@ int main(int argc, const char **argv) {
first->next = a;
a = first;
assert(refcount_context_num_refs(c, a) == 1);
assert(refcount_debug_context_count_object(c, a, a) == 1);
refcount_context_ref(c, a);
refcount_context_unref(c, a);