Add debug functions
This commit is contained in:
@ -454,6 +454,24 @@ static inline bool refcount_remove_destructor(void *obj, void *key) {
|
|||||||
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
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
@ -250,7 +250,7 @@ end:
|
|||||||
* @param refs Where to store the refs
|
* @param refs Where to store the refs
|
||||||
* @return True on success
|
* @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) {
|
RefcountList **refs) {
|
||||||
if (ctx->held_refs_callback) {
|
if (ctx->held_refs_callback) {
|
||||||
return ctx->held_refs_callback(obj, refs, ctx->user_data);
|
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);
|
unlock_entry_mtx(ENTRY);
|
||||||
return success;
|
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;
|
||||||
|
}
|
||||||
|
@ -65,6 +65,10 @@ int main(int argc, const char **argv) {
|
|||||||
STATIC_A(1);
|
STATIC_A(1);
|
||||||
STATIC_A(2);
|
STATIC_A(2);
|
||||||
STATIC_A(3);
|
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");
|
A *a = make_a(c, 10, "Hello world\n");
|
||||||
assert(!refcount_context_is_static(c, a));
|
assert(!refcount_context_is_static(c, a));
|
||||||
@ -124,6 +128,7 @@ int main(int argc, const char **argv) {
|
|||||||
first->next = a;
|
first->next = a;
|
||||||
a = first;
|
a = first;
|
||||||
assert(refcount_context_num_refs(c, a) == 1);
|
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_ref(c, a);
|
||||||
refcount_context_unref(c, a);
|
refcount_context_unref(c, a);
|
||||||
|
Reference in New Issue
Block a user