blob: 642d0769e21e6ffea5598583ac4f778579cde138 [file] [log] [blame]
/* Copyright (c) 2010 The Regents of the University of California
* Copyright (c) 2016 Google Inc
* Barret Rhoden <brho@cs.berkeley.edu>
* See LICENSE for details.
*
* Parlib's version of krefs. */
#pragma once
#include <stdint.h>
#include <assert.h>
#include <ros/common.h>
struct kref {
unsigned int refcnt;
void (*release)(struct kref *kref);
};
static void kref_init(struct kref *kref, void (*release)(struct kref *kref),
unsigned int init_ref)
{
kref->refcnt = init_ref;
kref->release = release;
}
/* Returns TRUE if successful. */
static bool kref_get_not_zero(struct kref *kref, unsigned int inc)
{
unsigned int old_ref, new_ref;
do {
old_ref = ACCESS_ONCE(kref->refcnt);
if (!old_ref)
return FALSE;
new_ref = old_ref + inc;
} while (!__sync_bool_compare_and_swap(&kref->refcnt, old_ref,
new_ref));
return TRUE;
}
static void kref_get(struct kref *kref, unsigned int inc)
{
assert(kref->refcnt);
__sync_fetch_and_add(&kref->refcnt, inc);
}
/* Returns TRUE if we released */
static bool kref_put(struct kref *kref)
{
unsigned int old_ref;
assert(kref->refcnt);
old_ref = __sync_sub_and_fetch(&kref->refcnt, 1);
if (old_ref)
return FALSE;
kref->release(kref);
return TRUE;
}