2 * mono-linked-list-set.h: A lock-free split ordered list.
5 * Rodrigo Kumpera (kumpera@gmail.com)
10 #ifndef __MONO_SPLIT_ORDERED_LIST_H__
11 #define __MONO_SPLIT_ORDERED_LIST_H__
13 #include <mono/utils/hazard-pointer.h>
14 #include <mono/utils/mono-membar.h>
16 typedef struct _MonoLinkedListSetNode MonoLinkedListSetNode;
18 struct _MonoLinkedListSetNode {
19 /* next must be the first element in this struct! */
20 MonoLinkedListSetNode *next;
25 MonoLinkedListSetNode *head;
26 void (*free_node_func)(void *);
30 static inline gpointer
31 mono_lls_pointer_unmask (gpointer p)
33 return (gpointer)((uintptr_t)p & ~(uintptr_t)0x3);
36 static inline uintptr_t
37 mono_lls_pointer_get_mark (gpointer n)
39 return (uintptr_t)n & 0x1;
43 Those are low level operations. prev, cur, next are returned in the hazard pointer table.
44 You must manually clean the hazard pointer table after using them.
48 mono_lls_init (MonoLinkedListSet *list, void (*free_node_func)(void *));
51 mono_lls_find (MonoLinkedListSet *list, MonoThreadHazardPointers *hp, uintptr_t key);
54 mono_lls_insert (MonoLinkedListSet *list, MonoThreadHazardPointers *hp, MonoLinkedListSetNode *value);
57 mono_lls_remove (MonoLinkedListSet *list, MonoThreadHazardPointers *hp, MonoLinkedListSetNode *value);
60 get_hazardous_pointer_with_mask (gpointer volatile *pp, MonoThreadHazardPointers *hp, int hazard_index);
62 static inline gboolean
63 mono_lls_filter_accept_all (gpointer elem)
69 * These macros assume that no other threads are actively modifying the list.
72 #define MONO_LLS_FOREACH_FILTERED(list, type, elem, filter) \
74 MonoLinkedListSet *list__ = (list); \
75 for (MonoLinkedListSetNode *cur__ = list__->head; cur__; cur__ = (MonoLinkedListSetNode *) mono_lls_pointer_unmask (cur__->next)) { \
76 if (!mono_lls_pointer_get_mark (cur__->next)) { \
77 type *elem = (type *) cur__; \
80 #define MONO_LLS_FOREACH_END \
86 #define MONO_LLS_FOREACH(list, type, elem) \
87 MONO_LLS_FOREACH_FILTERED ((list), type, elem, mono_lls_filter_accept_all)
90 * These macros can be used while other threads are potentially modifying the
91 * list, but they only provide a snapshot of the list as a result.
93 * NOTE: Do NOT break out of the loop through any other means than a break
94 * statement, as other ways of breaking the loop will skip past important
98 #define MONO_LLS_FOREACH_FILTERED_SAFE(list, type, elem, filter) \
100 /* NOTE: Keep this macro's code in sync with the mono_lls_find () logic. */ \
101 MonoLinkedListSet *list__ = (list); \
102 MonoThreadHazardPointers *hp__ = mono_hazard_pointer_get (); \
103 gboolean progress__ = FALSE; \
105 gboolean restart__; \
108 MonoLinkedListSetNode **prev__ = &list__->head; \
109 mono_hazard_pointer_set (hp__, 2, prev__); \
110 MonoLinkedListSetNode *cur__ = (MonoLinkedListSetNode *) get_hazardous_pointer_with_mask ((gpointer *) prev__, hp__, 1); \
115 MonoLinkedListSetNode *next__ = (MonoLinkedListSetNode *) get_hazardous_pointer_with_mask ((gpointer *) &cur__->next, hp__, 0); \
116 uintptr_t ckey__ = cur__->key; \
117 mono_memory_read_barrier (); \
118 if (*prev__ != cur__) { \
122 if (!mono_lls_pointer_get_mark (next__)) { \
123 if (!progress__ || ckey__ > hkey__) { \
126 type *elem = (type *) cur__; \
127 if (filter (elem)) { \
128 gboolean broke__ = TRUE; \
129 gboolean done__ = FALSE; \
137 #define MONO_LLS_FOREACH_SAFE_END \
146 prev__ = &cur__->next; \
147 mono_hazard_pointer_set (hp__, 2, cur__); \
149 next__ = (MonoLinkedListSetNode *) mono_lls_pointer_unmask (next__); \
150 if (InterlockedCompareExchangePointer ((volatile gpointer *) prev__, next__, cur__) == cur__) { \
151 mono_memory_write_barrier (); \
152 mono_hazard_pointer_clear (hp__, 1); \
153 if (list__->free_node_func) { \
154 mono_thread_hazardous_queue_free (cur__, list__->free_node_func); \
161 cur__ = (MonoLinkedListSetNode *) mono_lls_pointer_unmask (next__); \
162 mono_hazard_pointer_set (hp__, 1, cur__); \
164 } while (restart__); \
165 mono_hazard_pointer_clear (hp__, 0); \
166 mono_hazard_pointer_clear (hp__, 1); \
167 mono_hazard_pointer_clear (hp__, 2); \
170 #define MONO_LLS_FOREACH_SAFE(list, type, elem) \
171 MONO_LLS_FOREACH_FILTERED_SAFE ((list), type, elem, mono_lls_filter_accept_all)
173 #endif /* __MONO_SPLIT_ORDERED_LIST_H__ */