compat: add kref implementation
This is a very basic port of Linux' kref, we don't actually need atomics so we just use a simple counter. This is used by CCF to free unused clocks. Signed-off-by: Casey Connolly <casey.connolly@linaro.org>
This commit is contained in:
@@ -0,0 +1,124 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0-only */
|
||||
/*
|
||||
* kref.h - library routines for handling generic reference counted objects
|
||||
*
|
||||
* Copyright (C) 2004 Greg Kroah-Hartman <greg@kroah.com>
|
||||
* Copyright (C) 2004 IBM Corp.
|
||||
*
|
||||
* based on kobject.h which was:
|
||||
* Copyright (C) 2002-2003 Patrick Mochel <mochel@osdl.org>
|
||||
* Copyright (C) 2002-2003 Open Source Development Labs
|
||||
*/
|
||||
|
||||
#ifndef _KREF_H_
|
||||
#define _KREF_H_
|
||||
|
||||
#include <linux/compat.h>
|
||||
|
||||
struct kref {
|
||||
long refcount;
|
||||
};
|
||||
|
||||
#define KREF_INIT(n) { .refcount = REFCOUNT_INIT(n), }
|
||||
|
||||
/**
|
||||
* kref_init - initialize object.
|
||||
* @kref: object in question.
|
||||
*/
|
||||
static inline void kref_init(struct kref *kref)
|
||||
{
|
||||
kref->refcount = 1;
|
||||
}
|
||||
|
||||
static inline unsigned int kref_read(const struct kref *kref)
|
||||
{
|
||||
return kref->refcount;
|
||||
}
|
||||
|
||||
/**
|
||||
* kref_get - increment refcount for object.
|
||||
* @kref: object.
|
||||
*/
|
||||
static inline void kref_get(struct kref *kref)
|
||||
{
|
||||
kref->refcount++;
|
||||
}
|
||||
|
||||
/**
|
||||
* kref_put - Decrement refcount for object
|
||||
* @kref: Object
|
||||
* @release: Pointer to the function that will clean up the object when the
|
||||
* last reference to the object is released.
|
||||
*
|
||||
* Decrement the refcount, and if 0, call @release. The caller may not
|
||||
* pass NULL or kfree() as the release function.
|
||||
*
|
||||
* Return: 1 if this call removed the object, otherwise return 0. Beware,
|
||||
* if this function returns 0, another caller may have removed the object
|
||||
* by the time this function returns. The return value is only certain
|
||||
* if you want to see if the object is definitely released.
|
||||
*/
|
||||
static inline int kref_put(struct kref *kref, void (*release)(struct kref *kref))
|
||||
{
|
||||
if (--kref->refcount == 0) {
|
||||
release(kref);
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* kref_put_mutex - Decrement refcount for object
|
||||
* @kref: Object
|
||||
* @release: Pointer to the function that will clean up the object when the
|
||||
* last reference to the object is released.
|
||||
* @mutex: Mutex which protects the release function.
|
||||
*
|
||||
* This variant of kref_lock() calls the @release function with the @mutex
|
||||
* held. The @release function will release the mutex.
|
||||
*/
|
||||
static inline int kref_put_mutex(struct kref *kref,
|
||||
void (*release)(struct kref *kref),
|
||||
struct mutex *mutex)
|
||||
{
|
||||
return kref_put(kref, release);
|
||||
}
|
||||
|
||||
/**
|
||||
* kref_put_lock - Decrement refcount for object
|
||||
* @kref: Object
|
||||
* @release: Pointer to the function that will clean up the object when the
|
||||
* last reference to the object is released.
|
||||
* @lock: Spinlock which protects the release function.
|
||||
*
|
||||
* This variant of kref_lock() calls the @release function with the @lock
|
||||
* held. The @release function will release the lock.
|
||||
*/
|
||||
static inline int kref_put_lock(struct kref *kref,
|
||||
void (*release)(struct kref *kref),
|
||||
spinlock_t *lock)
|
||||
{
|
||||
return kref_put(kref, release);
|
||||
}
|
||||
|
||||
/**
|
||||
* kref_get_unless_zero - Increment refcount for object unless it is zero.
|
||||
* @kref: object.
|
||||
*
|
||||
* This function is intended to simplify locking around refcounting for
|
||||
* objects that can be looked up from a lookup structure, and which are
|
||||
* removed from that lookup structure in the object destructor.
|
||||
* Operations on such objects require at least a read lock around
|
||||
* lookup + kref_get, and a write lock around kref_put + remove from lookup
|
||||
* structure. Furthermore, RCU implementations become extremely tricky.
|
||||
* With a lookup followed by a kref_get_unless_zero *with return value check*
|
||||
* locking in the kref_put path can be deferred to the actual removal from
|
||||
* the lookup structure and RCU lookups become trivial.
|
||||
*
|
||||
* Return: non-zero if the increment succeeded. Otherwise return 0.
|
||||
*/
|
||||
static inline int kref_get_unless_zero(struct kref *kref)
|
||||
{
|
||||
return kref->refcount ? kref->refcount++ : 0;
|
||||
}
|
||||
#endif /* _KREF_H_ */
|
||||
Reference in New Issue
Block a user