Data Structures | |
| struct | lu_ref |
Mostly for debugging.
Suppose there is a reference counted data-structure struct foo. To track who acquired references to instance of struct foo, add lu_ref field to it:
struct foo { atomic_t foo_refcount; struct lu_ref foo_reference; ... };
foo::foo_reference has to be initialized by calling lu_ref_init(). Typically there will be functions or macros to increment and decrement foo::foo_refcount, let's say they are foo_get(struct foo *foo) and foo_put(struct foo *foo), respectively.
Whenever foo_get() is called to acquire a reference on a foo, lu_ref_add() has to be called to insert into foo::foo_reference a record, describing acquired reference. Dually, lu_ref_del() removes matching record. Typical usages are:
struct bar *bar; // bar owns a reference to foo. bar->bar_foo = foo_get(foo); lu_ref_add(&foo->foo_reference, "bar", bar); ... // reference from bar to foo is released. lu_ref_del(&foo->foo_reference, "bar", bar); foo_put(bar->bar_foo); // current thread acquired a temporary reference to foo. foo_get(foo); lu_ref_add(&foo->reference, __FUNCTION__, cfs_current()); ... // temporary reference is released. lu_ref_del(&foo->reference, __FUNCTION__, cfs_current()); foo_put(foo);
Et cetera. Often it makes sense to include lu_ref_add() and lu_ref_del() calls into foo_get() and foo_put(). When an instance of struct foo is destroyed, lu_ref_fini() has to be called that checks that no pending references remain. lu_ref_print() can be used to dump a list of pending references, while hunting down a leak.
For objects to which a large number of references can be acquired, lu_ref_del() can become cpu consuming, as it has to scan the list of references. To work around this, remember result of lu_ref_add() (usually in the same place where pointer to struct foo is stored), and use lu_ref_del_at():
// There is a large number of bar's for a single foo. bar->bar_foo = foo_get(foo); bar->bar_foo_ref = lu_ref_add(&foo->foo_reference, "bar", bar); ... // reference from bar to foo is released. lu_ref_del_at(&foo->foo_reference, bar->bar_foo_ref, "bar", bar); foo_put(bar->bar_foo);
lu_ref interface degrades gracefully in case of memory shortages.