akaros/kern/include/kref.h
<<
>>
Prefs
   1/* Copyright (c) 2010 The Regents of the University of California
   2 * Barret Rhoden <brho@cs.berkeley.edu>
   3 * See LICENSE for details.
   4 *
   5 * Kernel reference counting, based on Linux's kref:
   6 * - http://www.kroah.com/linux/talks/ols_2004_kref_paper/
   7 *          Reprint-Kroah-Hartman-OLS2004.pdf
   8 * - http://lwn.net/Articles/336224/
   9 * - Linux's Documentation/kref.txt
  10 *
  11 * See our Documentation/kref.txt for more info. */
  12
  13#pragma once
  14
  15#include <atomic.h>
  16#include <assert.h>
  17
  18/* Current versions of Linux pass in 'release' on the kref_put() callsite to
  19 * save on space in whatever struct these are embedded in.  We don't, since it's
  20 * a little more complicated and we will probably change the release function a
  21 * lot for subsystems in development. */
  22struct kref {
  23        atomic_t refcount;
  24        void (*release)(struct kref *kref);
  25};
  26
  27/* Helper for some debugging situations */
  28static long kref_refcnt(struct kref *kref)
  29{
  30        return atomic_read(&kref->refcount);
  31}
  32
  33static void kref_init(struct kref *kref, void (*release)(struct kref *kref),
  34                      unsigned int init)
  35{
  36        assert(release);
  37        atomic_init(&kref->refcount, init);
  38        kref->release = release;
  39}
  40
  41/* Will blindly incref */
  42static struct kref *__kref_get(struct kref *kref, unsigned int inc)
  43{
  44        atomic_add(&kref->refcount, inc);
  45        return kref;
  46}
  47
  48/* Returns the kref ptr on success, 0 on failure */
  49static struct kref *kref_get_not_zero(struct kref *kref, unsigned int inc)
  50{
  51        if (atomic_add_not_zero(&kref->refcount, inc))
  52                return kref;
  53        else
  54                return 0;
  55}
  56
  57/* Will panic on zero */
  58static struct kref *kref_get(struct kref *kref, unsigned int inc)
  59{
  60        kref = kref_get_not_zero(kref, inc);
  61        assert(kref);
  62        return kref;
  63}
  64
  65/* Returns True if we hit 0 and executed 'release', False otherwise */
  66static bool kref_put(struct kref *kref)
  67{
  68        assert(kref_refcnt(kref) > 0);          /* catch some bugs */
  69        if (atomic_sub_and_test(&kref->refcount, 1)) {
  70                kref->release(kref);
  71                return TRUE;
  72        }
  73        return FALSE;
  74}
  75
  76/* Dev / debugging function to catch the attempted freeing of objects we don't
  77 * know how to free yet. */
  78static void fake_release(struct kref *kref)
  79{
  80        panic("Cleaning up this object is not supported!\n");
  81}
  82