|  | /* 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; | 
|  | } |