Merge pull request #5714 from alexischr/update_bockbuild
[mono.git] / mono / utils / refcount.h
1 /**
2  * \file
3  */
4
5 #ifndef __MONO_UTILS_REFCOUNT_H__
6 #define __MONO_UTILS_REFCOUNT_H__
7
8 #include <glib.h>
9 #include <config.h>
10
11 #include "atomic.h"
12
13 /*
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.
16  *
17  * This introduces some constraints on the MonoRefCount field:
18  *  - it needs to be called "ref"
19  *  - it cannot be a pointer
20  */
21
22 typedef struct {
23         guint32 ref;
24         void (*destructor) (gpointer data);
25 } MonoRefCount;
26
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) do { mono_refcount_decrement (&(v)->ref); } while (0)
31
32 static inline void
33 mono_refcount_initialize (MonoRefCount *refcount, void (*destructor) (gpointer data))
34 {
35         refcount->ref = 1;
36         refcount->destructor = destructor;
37 }
38
39 static inline gboolean
40 mono_refcount_tryincrement (MonoRefCount *refcount)
41 {
42         guint32 oldref, newref;
43
44         g_assert (refcount);
45
46         do {
47                 oldref = refcount->ref;
48                 if (oldref == 0)
49                         return FALSE;
50
51                 newref = oldref + 1;
52         } while (InterlockedCompareExchange ((gint32*) &refcount->ref, newref, oldref) != oldref);
53
54         return TRUE;
55 }
56
57 static inline void
58 mono_refcount_increment (MonoRefCount *refcount)
59 {
60         if (!mono_refcount_tryincrement (refcount))
61                 g_error ("%s: cannot increment a ref with value 0", __func__);
62 }
63
64 static inline void
65 mono_refcount_decrement (MonoRefCount *refcount)
66 {
67         guint32 oldref, newref;
68
69         g_assert (refcount);
70
71         do {
72                 oldref = refcount->ref;
73                 if (oldref == 0)
74                         g_error ("%s: cannot decrement a ref with value 0", __func__);
75
76                 newref = oldref - 1;
77         } while (InterlockedCompareExchange ((gint32*) &refcount->ref, newref, oldref) != oldref);
78
79         if (newref == 0 && refcount->destructor)
80                 refcount->destructor ((gpointer) refcount);
81 }
82
83 #endif /* __MONO_UTILS_REFCOUNT_H__ */