Super Light Weight Reference counting
Venkatesh Srinivas
me at endeavour.zapto.org
Tue Dec 21 09:24:58 PST 2010
Hi,
I had a need for a very light-weight reference counting system in
kernel (much lighter than sysref), so I came up with:
ref.h :=====================
cat struct kref {
void *priv;
int refcount;
};
typedef struct kref *kref_t;
void kref_init(struct kref *ref, void *priv1, int count);
void kref_inc(struct kref *ref);
void kref_dec(struct kref *ref, void (*deconstruct)(void*, void*), void *priv2);
kern_ref.c :=========================
#include <sys/atomic.h>
void
kref_init(struct kref *ref, void *priv, int count)
{
ref->refcount = count;
ref->priv = priv;
}
void
kref_inc(struct kref *ref)
{
atomic_add_int(&ref->refcount, 1);
}
void
kref_dec(struct kref *ref, void (*deconstruct)(void *, void *), void *priv2)
{
int val;
val = atomic_fetchadd_int(&ref->refcount, -1);
if (val == 1)
deconstruct(ref->priv, priv2);
}
--------
The intended lifecycle for something would be :
struct thing {
struct kref ref;
};
struct thing *thingy = kmalloc(sizeof(struct thing), M_AWESOME);
kref_init(&thingy->ref, thingy, 1);
. ..
kref_inc(&thingy->ref);
. ..
kref_dec(&thingy->ref, kfree, M_AWESOME);
. ..
kref_dec(&thingy->ref, kfree, M_AWESOME);
Object is freed! (The deconstructor is called on the 1 -> 0
transition (the last one out turns off the lights))
Since "an object cannot synchronize its own visibility", kref_inc and
kref_dec must be synchronized at a higher level; directly using them
invites races (imagine entering a kref_inc ; you compute the address
of the refcount; then a concurrent kref_dec frees the structure. then
you go ahead and LOCK ADD. oops.)
Aggelos Economopoulos suggested on IRC the rename from kern_ref to
kref, suggested moving the deconstructor from a per-ref field to an
argument to kref_dec, and that references only needed one priv pointer
(the original had two, to support kfree).
Any criticisms or thoughts would be very welcome!
Thanks,
-- vs
More information about the Kernel
mailing list