加入 Gitee
与超过 1200万 开发者一起发现、参与优秀开源项目,私有仓库也完全免费 :)
免费加入
文件
克隆/下载
refcount.h 8.20 KB
一键复制 编辑 原始数据 按行查看 历史
/*! \file refcount.h
* \author Lorenzo Miniero <lorenzo@meetecho.com>
* \copyright GNU General Public License v3
* \brief Reference counter mechanism
* \details Implementation of a simple reference counter that can be
* used to keep track of memory management in Janus, in order to avoid
* the need for timed garbage collectord and the like which have proven
* ineffective in the past (e.g., crashes whenever race conditions
* occurred). This implementation is heavily based on an excellent
* <a href="http://nullprogram.com/blog/2015/02/17/">blog post</a>
* written by Chris Wellons.
*
* Objects interested in leveraging this reference counter mechanism
* must add a janus_refcount instance as one of the members of the object
* itself, and then call janus_refcall_init() to set it up. Initializing
* the reference counter just needs a pointer to the function to invoke
* when the object needs to be destroyed (counter reaches 0), while it
* will automatically set the counter to 1. To increase and decrease the
* counter just call janus_refcount_increase() and janus_refcount_decrease().
* When the counter reaches 0, the function passed when initializing it will
* be invoked: this means it's up to you to then free all the resources
* the object may have allocated. Notice that if this involves other
* objects that are reference counted, freeing the resource will just
* mean decreasing the related counter, and not destroying it right away.
*
* The free function must be defined like this:
*
\verbatim
void my_free_function(janus_refcount *counter);
\endverbatim
*
* Since the reference counter cannot know the size of the object to be
* freed, or where in the list of members the counter has been placed,
* retrieving the pointer to the object to free is up to you, using the
* janus_refcount_containerof macro. This is an example of how the
* free function we have defined above may be implemented:
*
\verbatim
typedef my_struct {
int number;
char *string;
janus_refcount myref;
}
void my_free_function(janus_refcount *counter) {
struct my_struct *my_object = janus_refcount_containerof(counter, struct my_struct, myref);
if(my_object->string)
free(my_object->string);
free(my_object);
}
\endverbatim
*
* \ingroup core
* \ref core
*/
#ifndef JANUS_REFCOUNT_H
#define JANUS_REFCOUNT_H
#include <glib.h>
#include "mutex.h"
//~ #define REFCOUNT_DEBUG
extern int refcount_debug;
/*! \brief Macro to programmatically address the object itself from its counter
* \details \c refptr is the pointer to the janus_refcount instance, \c type
* is the type of the object itself (e.g., <code>struct mystruct</code>),
* while \c member is how the janus_refcount instance is called in the
* object that contains it. */
#define janus_refcount_containerof(refptr, type, member) \
((type *)((char *)(refptr) - offsetof(type, member)))
/*! \brief Janus reference counter structure */
typedef struct janus_refcount janus_refcount;
struct janus_refcount {
/*! \brief The reference counter itself */
gint count;
/*! \brief Pointer to the function that will be used to free the object */
void (*free)(const janus_refcount *);
};
#ifdef REFCOUNT_DEBUG
/* Reference counters debugging */
extern GHashTable *counters;
extern janus_mutex counters_mutex;
#define janus_refcount_track(refp) { \
janus_mutex_lock(&counters_mutex); \
if(counters == NULL) \
counters = g_hash_table_new(NULL, NULL); \
g_hash_table_insert(counters, refp, refp); \
janus_mutex_unlock(&counters_mutex); \
}
#define janus_refcount_untrack(refp) { \
janus_mutex_lock(&counters_mutex); \
g_hash_table_remove(counters, refp); \
janus_mutex_unlock(&counters_mutex); \
}
#endif
/*! \brief Janus reference counter initialization (debug according to settings)
* \note Also sets the counter to 1 automatically, so no need to increase
* it again manually via janus_refcount_increase() after the initialization
* @param refp Pointer to the Janus reference counter instance
* @param free_fn Pointer to the function to invoke when the object the counter
* refers to needs to be destroyed */
#define janus_refcount_init(refp, free_fn) { \
if(!refcount_debug) { \
janus_refcount_init_nodebug(refp, free_fn); \
} else { \
janus_refcount_init_debug(refp, free_fn); \
} \
}
/*! \brief Janus reference counter initialization (no debug)
* \note Also sets the counter to 1 automatically, so no need to increase
* it again manually via janus_refcount_increase() after the initialization
* @param refp Pointer to the Janus reference counter instance
* @param free_fn Pointer to the function to invoke when the object the counter
* refers to needs to be destroyed */
#ifdef REFCOUNT_DEBUG
#define janus_refcount_init_nodebug(refp, free_fn) { \
(refp)->count = 1; \
(refp)->free = free_fn; \
janus_refcount_track((refp)); \
}
#else
#define janus_refcount_init_nodebug(refp, free_fn) { \
(refp)->count = 1; \
(refp)->free = free_fn; \
}
#endif
/*! \brief Janus reference counter initialization (debug)
* \note Also sets the counter to 1 automatically, so no need to increase
* it again manually via janus_refcount_increase() after the initialization
* @param refp Pointer to the Janus reference counter instance
* @param free_fn Pointer to the function to invoke when the object the counter
* refers to needs to be destroyed */
#ifdef REFCOUNT_DEBUG
#define janus_refcount_init_debug(refp, free_fn) { \
(refp)->count = 1; \
JANUS_PRINT("[%s:%s:%d:init] %p (%d)\n", __FILE__, __FUNCTION__, __LINE__, refp, (refp)->count); \
(refp)->free = free_fn; \
janus_refcount_track((refp)); \
}
#else
#define janus_refcount_init_debug(refp, free_fn) { \
(refp)->count = 1; \
JANUS_PRINT("[%s:%s:%d:init] %p (%d)\n", __FILE__, __FUNCTION__, __LINE__, refp, (refp)->count); \
(refp)->free = free_fn; \
}
#endif
/*! \brief Increase the Janus reference counter (debug according to settings)
* @param refp Pointer to the Janus reference counter instance */
#define janus_refcount_increase(refp) { \
if(!refcount_debug) { \
janus_refcount_increase_nodebug(refp); \
} else { \
janus_refcount_increase_debug(refp); \
} \
}
/*! \brief Increase the Janus reference counter (no debug)
* @param refp Pointer to the Janus reference counter instance */
#define janus_refcount_increase_nodebug(refp) { \
g_atomic_int_inc((gint *)&(refp)->count); \
}
/*! \brief Increase the Janus reference counter (debug)
* @param refp Pointer to the Janus reference counter instance */
#define janus_refcount_increase_debug(refp) { \
JANUS_PRINT("[%s:%s:%d:increase] %p (%d)\n", __FILE__, __FUNCTION__, __LINE__, refp, (refp)->count+1); \
g_atomic_int_inc((gint *)&(refp)->count); \
}
/*! \brief Decrease the Janus reference counter (debug according to settings)
* \note Will invoke the \c free function if the counter reaches 0
* @param refp Pointer to the Janus reference counter instance */
#define janus_refcount_decrease(refp) { \
if(!refcount_debug) { \
janus_refcount_decrease_nodebug(refp); \
} else { \
janus_refcount_decrease_debug(refp); \
} \
}
/*! \brief Decrease the Janus reference counter (debug)
* \note Will invoke the \c free function if the counter reaches 0
* @param refp Pointer to the Janus reference counter instance */
#ifdef REFCOUNT_DEBUG
#define janus_refcount_decrease_debug(refp) { \
JANUS_PRINT("[%s:%s:%d:decrease] %p (%d)\n", __FILE__, __FUNCTION__, __LINE__, refp, (refp)->count-1); \
if(g_atomic_int_dec_and_test((gint *)&(refp)->count)) { \
(refp)->free(refp); \
janus_refcount_untrack((refp)); \
} \
}
#else
#define janus_refcount_decrease_debug(refp) { \
JANUS_PRINT("[%s:%s:%d:decrease] %p (%d)\n", __FILE__, __FUNCTION__, __LINE__, refp, (refp)->count-1); \
if(g_atomic_int_dec_and_test((gint *)&(refp)->count)) { \
(refp)->free(refp); \
} \
}
#endif
/*! \brief Decrease the Janus reference counter (no debug)
* \note Will invoke the \c free function if the counter reaches 0
* @param refp Pointer to the Janus reference counter instance */
#ifdef REFCOUNT_DEBUG
#define janus_refcount_decrease_nodebug(refp) { \
if(g_atomic_int_dec_and_test((gint *)&(refp)->count)) { \
(refp)->free(refp); \
janus_refcount_untrack((refp)); \
} \
}
#else
#define janus_refcount_decrease_nodebug(refp) { \
if(g_atomic_int_dec_and_test((gint *)&(refp)->count)) { \
(refp)->free(refp); \
} \
}
#endif
#endif
Loading...
马建仓 AI 助手
尝试更多
代码解读
代码找茬
代码优化