|
@@ -5,36 +5,151 @@
|
|
|
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;
|
|
|
- cds_mutex_t *mutex;
|
|
|
+ int cntr; /**< counter value */
|
|
|
+ cds_mutex_t *mutex; /**< mutex asigned to this reference counter */
|
|
|
} reference_counter_data_t;
|
|
|
-
|
|
|
-/* these functions can be called only by owner of at least one reference */
|
|
|
-/* owner is somebody who:
|
|
|
- * - created a referenced structure
|
|
|
- * - added a reference
|
|
|
- * - got a reference by an ovner
|
|
|
- */
|
|
|
-
|
|
|
-void init_reference_counter(reference_counter_data_t *ref);
|
|
|
+
|
|
|
+/** 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);
|
|
|
|
|
|
-/* returns:
|
|
|
- * 0 if reference removed, but exist other references
|
|
|
- * 1 if removed last refernce and the element SHOULD be freed
|
|
|
+/** Removes reference - decrements reference counter.
|
|
|
+ * This function can be called only by owner of at least one reference!
|
|
|
*
|
|
|
- * usage:
|
|
|
- *
|
|
|
- * some_structure *ss;
|
|
|
- * ...
|
|
|
- * if (remove_reference(&ss->ref)) cds_free(&ss->ref);
|
|
|
+ * \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
|