X-Git-Url: http://git.efficios.com/?a=blobdiff_plain;f=include%2Fbabeltrace%2Fobject-internal.h;h=afb9e6eee3cb0cebe2137273bb1fbc637cd43d71;hb=cdc4693da047ef54d55bf17d803605e4880b734e;hp=afba44790723d212465bb9e423278e3ffb647970;hpb=83509119a945fc77faff869daaf48627e1c4b3fa;p=babeltrace.git diff --git a/include/babeltrace/object-internal.h b/include/babeltrace/object-internal.h index afba4479..afb9e6ee 100644 --- a/include/babeltrace/object-internal.h +++ b/include/babeltrace/object-internal.h @@ -27,22 +27,148 @@ * SOFTWARE. */ +#include #include +#include +#include +#include /** * All objects publicly exposed by Babeltrace APIs must contain this structure * as their first member. This allows the unification of all ref counting - * mechanism and may be used to provide more base functionality to all + * mechanisms and may be used to provide more base functionality to all * objects. */ struct bt_object { struct bt_ref ref_count; + /* Class-specific, optional release function. */ + bt_object_release_func release; + /* Class-specific, optional "parent is owner" notification listener. */ + bt_object_release_func parent_is_owner_listener; + /* @see doc/ref-counting.md */ + struct bt_object *parent; + + /* + * True if this object is shared, that is, it uses reference + * counting. + */ + bool is_shared; }; static inline -void bt_object_init(void *obj, bt_object_release_func release) +long bt_object_get_ref_count(const void *ptr) +{ + const struct bt_object *obj = ptr; + + return obj->ref_count.count; +} + +static inline +void bt_object_release(void *ptr) +{ + struct bt_object *obj = ptr; + +#ifdef BT_LOGV + BT_LOGV("Releasing object: addr=%p, ref-count=%lu", ptr, + obj->ref_count.count); +#endif + + if (obj && obj->release && bt_object_get_ref_count(obj) == 0) { + obj->release(obj); + } +} + +static inline +void generic_release(struct bt_object *obj) +{ + if (obj->parent) { + struct bt_object *parent = obj->parent; + +#ifdef BT_LOGV + BT_LOGV("Releasing parented object: addr=%p, ref-count=%lu, " + "parent-addr=%p, parent-ref-count=%lu", + obj, obj->ref_count.count, + parent, parent->ref_count.count); +#endif + + if (obj->parent_is_owner_listener) { + /* + * Object has a chance to destroy itself here + * under certain conditions and notify its + * parent. At this point the parent is + * guaranteed to exist because it's not put yet. + */ + obj->parent_is_owner_listener(obj); + } + + /* The release function will be invoked by the parent. */ + bt_put(parent); + } else { + bt_object_release(obj); + } +} + +static inline +struct bt_object *bt_object_borrow_parent(void *ptr) +{ + struct bt_object *obj = ptr; + + return obj ? obj->parent : NULL; +} + +static inline +struct bt_object *bt_object_get_parent(void *ptr) +{ + return bt_get(bt_object_borrow_parent(ptr)); +} + +static inline +void bt_object_set_parent(void *child_ptr, void *parent) +{ + struct bt_object *child = child_ptr; + + if (!child) { + return; + } + +#ifdef BT_LOGV + BT_LOGV("Setting object's parent: addr=%p, parent-addr=%p", + child_ptr, parent); +#endif + + /* + * It is assumed that a "child" being "parented" is publicly + * reachable. Therefore, a reference to its parent must be + * taken. The reference to the parent will be released once the + * object's reference count falls to zero. + */ + BT_PUT(child->parent); + child->parent = bt_get(parent); +} + +static inline +void bt_object_set_is_shared(struct bt_object *obj, bool is_shared) +{ + obj->is_shared = is_shared; +} + +static inline +void bt_object_init(void *ptr, bt_object_release_func release) +{ + struct bt_object *obj = ptr; + + obj->release = release; + obj->parent = NULL; + bt_object_set_is_shared(obj, true); + bt_ref_init(&obj->ref_count, generic_release); +} + +static inline +void bt_object_set_parent_is_owner_listener(void *obj, + bt_object_release_func cb) { - bt_ref_init(&((struct bt_object *) obj)->ref_count, release); + BT_ASSERT(obj); + ((struct bt_object *) obj)->parent_is_owner_listener = cb; } #endif /* BABELTRACE_OBJECT_INTERNAL_H */