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