[2019-12] [threads] Add back mono_threads_attach_tools_thread as a public API (#18074)
[mono-project.git] / mono / utils / refcount.h
blobb8dc9dcbe29c11a1509cc599f7001ece7818dc05
1 /**
2 * \file
3 */
5 #ifndef __MONO_UTILS_REFCOUNT_H__
6 #define __MONO_UTILS_REFCOUNT_H__
8 #include <glib.h>
9 #include <config.h>
11 #include "atomic.h"
14 * Mechanism for ref-counting which tries to be as user-friendly as possible. Instead of being a wrapper around
15 * user-provided data, it is embedded into the user data.
17 * This introduces some constraints on the MonoRefCount field:
18 * - it needs to be called "ref"
19 * - it cannot be a pointer
22 typedef struct {
23 guint32 ref;
24 void (*destructor) (gpointer data);
25 } MonoRefCount;
27 #define mono_refcount_init(v,destructor) do { mono_refcount_initialize (&(v)->ref, (destructor)); } while (0)
28 #define mono_refcount_inc(v) (mono_refcount_increment (&(v)->ref),(v))
29 #define mono_refcount_tryinc(v) (mono_refcount_tryincrement (&(v)->ref))
30 #define mono_refcount_dec(v) (mono_refcount_decrement (&(v)->ref))
32 static inline void
33 mono_refcount_initialize (MonoRefCount *refcount, void (*destructor) (gpointer data))
35 refcount->ref = 1;
36 refcount->destructor = destructor;
39 static inline gboolean
40 mono_refcount_tryincrement (MonoRefCount *refcount)
42 guint32 oldref, newref;
44 g_assert (refcount);
46 do {
47 oldref = refcount->ref;
48 if (oldref == 0)
49 return FALSE;
51 newref = oldref + 1;
52 } while (mono_atomic_cas_i32 ((gint32*) &refcount->ref, (gint32)newref, (gint32)oldref) != (gint32)oldref);
54 return TRUE;
57 static inline void
58 mono_refcount_increment (MonoRefCount *refcount)
60 if (!mono_refcount_tryincrement (refcount))
61 g_error ("%s: cannot increment a ref with value 0", __func__);
64 static inline guint32
65 mono_refcount_decrement (MonoRefCount *refcount)
67 guint32 oldref, newref;
69 g_assert (refcount);
71 do {
72 oldref = refcount->ref;
73 if (oldref == 0)
74 g_error ("%s: cannot decrement a ref with value 0", __func__);
76 newref = oldref - 1;
77 } while (mono_atomic_cas_i32 ((gint32*) &refcount->ref, (gint32)newref, (gint32)oldref) != (gint32)oldref);
79 if (newref == 0 && refcount->destructor)
80 refcount->destructor ((gpointer) refcount);
82 return newref;
85 #endif /* __MONO_UTILS_REFCOUNT_H__ */