/* SPDX-License-Identifier: BSD-2-Clause */ /* * Copyright (c) 2017, Linaro Limited */ #ifndef __KERNEL_REFCOUNT_H #define __KERNEL_REFCOUNT_H #include /* * Reference counter * * When val is 0, refcount_inc() does not change the value and returns false. * Otherwise, it increments the value and returns true. * * refcount_dec() decrements the value and returns true when the call * caused the value to become 0, false otherwise. * * Since each call to refcount_dec() is supposed to match a call to * refcount_inc(), refcount_dec() called for val == 0 should never happen. * * This behaviour makes this pattern possible: * if (!refcount_inc(r)) { * mutex_lock(m); * // Some other thread may have initialized o by now so check that * // we still need to initialize o. * if (!o) { * o = initialize(); * refcount_set(r, 1); * } * mutex_unlock(m); * } * * or * if (refcount_dec(r)) { * mutex_lock(m); * // Now that we have the mutex o can't be ininialized/uninitialized * // by any other thread, check that the refcount value is still 0 * // to guard against the thread above already having reinitialized o * if (!refcount_val(r) && o) * uninitialize(o) * mutex_unlock(m); * } * * where r if the reference counter, o is the object and m the mutex * protecting the object. */ struct refcount { unsigned int val; }; /* Increases refcount by 1, return true if val > 0 else false */ bool refcount_inc(struct refcount *r); /* Decreases refcount by 1, return true if val == 0 else false */ bool refcount_dec(struct refcount *r); static inline void refcount_set(struct refcount *r, unsigned int val) { atomic_store_uint(&r->val, val); } static inline unsigned int refcount_val(struct refcount *r) { return atomic_load_uint(&r->val); } #endif /*!__KERNEL_REFCOUNT_H*/