You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
kamailio/lib/cds/ref_cntr.h

158 lines
4.8 KiB

#ifndef __REFERENCE_CNTR_H
#define __REFERENCE_CNTR_H
#ifdef __cplusplus
extern "C" {
#endif
/** \ingroup cds
* @{
*
* \defgroup cds_ref_cnt Reference counting
*
* Experimental functions for reference counting (to simplify
* this code elsewhere).
*
* Reference counter (\ref reference_counter_data_t) holds integer number which
* should be changed using functions \ref add_reference and \ref
* remove_reference. Using these functions is the number read/changed from
* locked section guarded by one mutex from a set of 'group mutexes'.
*
* Often used scenario:
* - list of structures, change in the list (adding, removing) is guarded by
* one mutex,
* - each structure has reference counter, when the count is zero, the
* structure can be removed from the list and freed
*
* Note that mutex for adding references is needed because references are not
* added from critical section guarded by main list mutex but can be added whenever.
*
* Typical usage:
* \code
* struct some_structure {
* ...
* reference_counter_data_t ref;
* ...
* };
*
* reference_counter_group_t *some_grp;
*
* void init()
* {
* some_grp = init_reference_counter_group(16);
* }
*
* void destroy()
* {
* free_reference_counter_group(some_grp);
* }
*
* ...
*
* // adding a member:
* struct some_struct *ss = malloc(...);
* init_reference_counter(some_grp, &ss->ref);
* lock(list);
* add_to_list(ss);
* unlock(list);
*
* ...
* // adding a reference doesn't need to lock list
* // can be done only by a reference owner
* add_reference(&ss->ref);
*
* // releasing a member when not needed for caller and there is
* // no way how to obtain reference for released member
* // (no way how to find a member in list)
* if (remove_reference(&ss->ref)) {
* // last reference removed
* lock(list);
* remove_from_list(ss);
* free(ss);
* unlock(list);
* }
*
* // or
* // releasing a member when not needed for caller and it is possible
* // to 'search' in the list (reference to released member can be somehow
* // obtained by inspecting the list):
* lock(list);
* if (remove_reference(&ss->ref)) {
* // last reference removed
* remove_from_list(ss);
* free(ss);
* }
* unlock(list);
* \endcode
*
* \todo use atomic operations instead of locking
* @{ */
#include <cds/sync.h>
/** Structure holding reference counter value. */
typedef struct {
int cntr; /**< counter value */
cds_mutex_t *mutex; /**< mutex asigned to this reference counter */
} reference_counter_data_t;
/** Structure holding information about group of reference counters.
* It holds array of mutexes which are assigned to single reference
* counters in this group. The assignment is done using an operation
* on pointer to reference_counter_data_t. */
typedef struct {
int mutex_cnt; /**< number of mutexes for this group */
/** number of next mutex to be assigned - this member is NOT
* read/changed from critical section but it doesn't matter
* if it will be rewritten between processes because it is used
* for load distributing only (the worst thing that can happen
* is that the same mutex is assigned twice) */
int mutex_to_assign;
cds_mutex_t mutexes[1]; /**< array of mutexes (allocated together with the structure)*/
} reference_counter_group_t;
/** Initializes reference counter - sets its value to 1.
* After call to this function, the caller is owner of first
* reference. From now it can call other functions like
* \ref add_reference or \ref remove_reference.
*
* This function initializes the mutex - it chooses one from
* group mutexes. The mutex can not be changed after this
* call (it is only for reading). */
void init_reference_counter(reference_counter_group_t *grp, reference_counter_data_t *ref);
/** Adds reference - increments reference counter.
* This function can be called only by owner of at least one reference! */
void add_reference(reference_counter_data_t *ref);
/** Returns the value of reference counter. This function is mostly
* useless. */
int get_reference_count(reference_counter_data_t *ref);
/** Removes reference - decrements reference counter.
* This function can be called only by owner of at least one reference!
*
* \retval 0 if reference removed, but other references exist
* \retval 1 if removed last reference
* */
int remove_reference(reference_counter_data_t *ref);
/** Creates and initializes group of reference counters. All reference
* counters 'belonging' to this group are using the same set of mutexes. */
reference_counter_group_t *create_reference_counter_group(int mutex_cnt);
/** Destroys all resources used by reference counter group.
* After this function call no reference counter initialized
* by this group can be used. */
void free_reference_counter_group(reference_counter_group_t *grp);
/** @}
* @} */
#ifdef __cplusplus
}
#endif
#endif