/**
|
* \file
|
*/
|
|
#ifndef __MONO_UTILS_REFCOUNT_H__
|
#define __MONO_UTILS_REFCOUNT_H__
|
|
#include <glib.h>
|
#include <config.h>
|
|
#include "atomic.h"
|
|
/*
|
* Mechanism for ref-counting which tries to be as user-friendly as possible. Instead of being a wrapper around
|
* user-provided data, it is embedded into the user data.
|
*
|
* This introduces some constraints on the MonoRefCount field:
|
* - it needs to be called "ref"
|
* - it cannot be a pointer
|
*/
|
|
typedef struct {
|
guint32 ref;
|
void (*destructor) (gpointer data);
|
} MonoRefCount;
|
|
#define mono_refcount_init(v,destructor) do { mono_refcount_initialize (&(v)->ref, (destructor)); } while (0)
|
#define mono_refcount_inc(v) (mono_refcount_increment (&(v)->ref),(v))
|
#define mono_refcount_tryinc(v) (mono_refcount_tryincrement (&(v)->ref))
|
#define mono_refcount_dec(v) do { mono_refcount_decrement (&(v)->ref); } while (0)
|
|
static inline void
|
mono_refcount_initialize (MonoRefCount *refcount, void (*destructor) (gpointer data))
|
{
|
refcount->ref = 1;
|
refcount->destructor = destructor;
|
}
|
|
static inline gboolean
|
mono_refcount_tryincrement (MonoRefCount *refcount)
|
{
|
guint32 oldref, newref;
|
|
g_assert (refcount);
|
|
do {
|
oldref = refcount->ref;
|
if (oldref == 0)
|
return FALSE;
|
|
newref = oldref + 1;
|
} while (mono_atomic_cas_i32 ((gint32*) &refcount->ref, (gint32)newref, (gint32)oldref) != (gint32)oldref);
|
|
return TRUE;
|
}
|
|
static inline void
|
mono_refcount_increment (MonoRefCount *refcount)
|
{
|
if (!mono_refcount_tryincrement (refcount))
|
g_error ("%s: cannot increment a ref with value 0", __func__);
|
}
|
|
static inline void
|
mono_refcount_decrement (MonoRefCount *refcount)
|
{
|
guint32 oldref, newref;
|
|
g_assert (refcount);
|
|
do {
|
oldref = refcount->ref;
|
if (oldref == 0)
|
g_error ("%s: cannot decrement a ref with value 0", __func__);
|
|
newref = oldref - 1;
|
} while (mono_atomic_cas_i32 ((gint32*) &refcount->ref, (gint32)newref, (gint32)oldref) != (gint32)oldref);
|
|
if (newref == 0 && refcount->destructor)
|
refcount->destructor ((gpointer) refcount);
|
}
|
|
#endif /* __MONO_UTILS_REFCOUNT_H__ */
|