void *bt_get(void *ptr) { struct bt_object *obj = ptr; if (unlikely(!obj)) { goto end; } if (unlikely(!obj->ref_count.release)) { goto end; } if (unlikely(obj->parent && bt_object_get_ref_count(obj) == 0)) { BT_LOGV("Incrementing object's parent's reference count: " "addr=%p, parent-addr=%p", ptr, obj->parent); bt_get(obj->parent); } BT_LOGV("Incrementing object's reference count: %lu -> %lu: " "addr=%p, cur-count=%lu, new-count=%lu", obj->ref_count.count, obj->ref_count.count + 1, ptr, obj->ref_count.count, obj->ref_count.count + 1); bt_ref_get(&obj->ref_count); end: return obj; }
void *bt_get(void *ptr) { struct bt_object *obj = ptr; if (!obj) { goto end; } if (obj->parent && bt_object_get_ref_count(obj) == 0) { bt_get(obj->parent); } bt_ref_get(&obj->ref_count); end: return obj; }
static void release_event(struct bt_ctf_event *event) { if (bt_object_get_ref_count(event)) { /* * The event is being orphaned, but it must guarantee the * existence of its event class for the duration of its * lifetime. */ bt_get(event->event_class); BT_PUT(event->base.parent); } else { bt_object_release(event); } }
void bt_put(void *ptr) { struct bt_object *obj = ptr; if (unlikely(!obj)) { return; } if (unlikely(!obj->ref_count.release)) { return; } if (BT_LOG_ON_WARN && unlikely(bt_object_get_ref_count(obj) == 0)) { BT_LOGW("Decrementing a reference count set to 0: addr=%p", ptr); } BT_LOGV("Decrementing object's reference count: %lu -> %lu: " "addr=%p, cur-count=%lu, new-count=%lu", obj->ref_count.count, obj->ref_count.count - 1, ptr, obj->ref_count.count, obj->ref_count.count - 1); bt_ref_put(&obj->ref_count); }
static void test_example_scenario(void) { /** * Weak pointers to CTF-IR objects are to be used very carefully. * This is NOT a good practice and is strongly discouraged; this * is only done to facilitate the validation of expected reference * counts without affecting them by taking "real" references to the * objects. */ struct bt_ctf_trace *tc1 = NULL, *weak_tc1 = NULL; struct bt_ctf_stream_class *weak_sc1 = NULL, *weak_sc2 = NULL; struct bt_ctf_event_class *weak_ec1 = NULL, *weak_ec2 = NULL, *weak_ec3 = NULL; struct user user_a = { 0 }, user_b = { 0 }, user_c = { 0 }; /* The only reference which exists at this point is on TC1. */ tc1 = create_tc1(); ok(tc1, "Initialize trace"); if (!tc1) { return; } init_weak_refs(tc1, &weak_tc1, &weak_sc1, &weak_sc2, &weak_ec1, &weak_ec2, &weak_ec3); ok(bt_object_get_ref_count(weak_sc1) == 0, "Initial SC1 reference count is 0"); ok(bt_object_get_ref_count(weak_sc2) == 0, "Initial SC2 reference count is 0"); ok(bt_object_get_ref_count(weak_ec1) == 0, "Initial EC1 reference count is 0"); ok(bt_object_get_ref_count(weak_ec2) == 0, "Initial EC2 reference count is 0"); ok(bt_object_get_ref_count(weak_ec3) == 0, "Initial EC3 reference count is 0"); /* User A has ownership of the trace. */ BT_MOVE(user_a.tc, tc1); ok(bt_object_get_ref_count(user_a.tc) == 1, "TC1 reference count is 1"); /* User A acquires a reference to SC2 from TC1. */ user_a.sc = bt_ctf_trace_get_stream_class(user_a.tc, 1); ok(user_a.sc, "User A acquires SC2 from TC1"); ok(bt_object_get_ref_count(weak_tc1) == 2, "TC1 reference count is 2"); ok(bt_object_get_ref_count(weak_sc2) == 1, "SC2 reference count is 1"); /* User A acquires a reference to EC3 from SC2. */ user_a.ec = bt_ctf_stream_class_get_event_class(user_a.sc, 0); ok(user_a.ec, "User A acquires EC3 from SC2"); ok(bt_object_get_ref_count(weak_tc1) == 2, "TC1 reference count is 2"); ok(bt_object_get_ref_count(weak_sc2) == 2, "SC2 reference count is 2"); ok(bt_object_get_ref_count(weak_ec3) == 1, "EC3 reference count is 1"); /* User A releases its reference to SC2. */ diag("User A releases SC2"); BT_PUT(user_a.sc); /* * We keep the pointer to SC2 around to validate its reference * count. */ ok(bt_object_get_ref_count(weak_tc1) == 2, "TC1 reference count is 2"); ok(bt_object_get_ref_count(weak_sc2) == 1, "SC2 reference count is 1"); ok(bt_object_get_ref_count(weak_ec3) == 1, "EC3 reference count is 1"); /* User A releases its reference to TC1. */ diag("User A releases TC1"); BT_PUT(user_a.tc); /* * We keep the pointer to TC1 around to validate its reference * count. */ ok(bt_object_get_ref_count(weak_tc1) == 1, "TC1 reference count is 1"); ok(bt_object_get_ref_count(weak_sc2) == 1, "SC2 reference count is 1"); ok(bt_object_get_ref_count(weak_ec3) == 1, "EC3 reference count is 1"); /* User B acquires a reference to SC1. */ diag("User B acquires a reference to SC1"); user_b.sc = bt_get(weak_sc1); ok(bt_object_get_ref_count(weak_tc1) == 2, "TC1 reference count is 2"); ok(bt_object_get_ref_count(weak_sc1) == 1, "SC1 reference count is 1"); /* User C acquires a reference to EC1. */ diag("User C acquires a reference to EC1"); user_c.ec = bt_ctf_stream_class_get_event_class(user_b.sc, 0); ok(bt_object_get_ref_count(weak_ec1) == 1, "EC1 reference count is 1"); ok(bt_object_get_ref_count(weak_sc1) == 2, "SC1 reference count is 2"); /* User A releases its reference on EC3. */ diag("User A releases its reference on EC3"); BT_PUT(user_a.ec); ok(bt_object_get_ref_count(weak_ec3) == 0, "EC3 reference count is 1"); ok(bt_object_get_ref_count(weak_sc2) == 0, "SC2 reference count is 0"); ok(bt_object_get_ref_count(weak_tc1) == 1, "TC1 reference count is 1"); /* User B releases its reference on SC1. */ diag("User B releases its reference on SC1"); BT_PUT(user_b.sc); ok(bt_object_get_ref_count(weak_sc1) == 1, "SC1 reference count is 1"); /* * User C is the sole owner of an object and is keeping the whole * trace hierarchy "alive" by holding a reference to EC1. */ ok(bt_object_get_ref_count(weak_tc1) == 1, "TC1 reference count is 1"); ok(bt_object_get_ref_count(weak_sc1) == 1, "SC1 reference count is 1"); ok(bt_object_get_ref_count(weak_sc2) == 0, "SC2 reference count is 0"); ok(bt_object_get_ref_count(weak_ec1) == 1, "EC1 reference count is 1"); ok(bt_object_get_ref_count(weak_ec2) == 0, "EC2 reference count is 0"); ok(bt_object_get_ref_count(weak_ec3) == 0, "EC3 reference count is 0"); /* Reclaim last reference held by User C. */ BT_PUT(user_c.ec); }