entry->state = DFE_STATE_USED;
- mono_memory_write_barrier ();
+ mono_memory_barrier ();
do {
num_used = num_used_delayed_free_entries;
if (num_used > index)
break;
} while (InterlockedCompareExchange (&num_used_delayed_free_entries, index + 1, num_used) != num_used);
+
+ mono_memory_write_barrier ();
}
static gboolean
entry = get_delayed_free_entry (index - 1);
} while (InterlockedCompareExchange (&entry->state, DFE_STATE_BUSY, DFE_STATE_USED) != DFE_STATE_USED);
+ /* Reading the item must happen before CASing the state. */
mono_memory_barrier ();
*item = entry->item;
entry->state = DFE_STATE_FREE;
+ mono_memory_write_barrier ();
+
return TRUE;
}
static gboolean
is_pointer_hazardous (gpointer p)
{
- int i;
+ int i, j;
int highest = highest_small_id;
g_assert (highest < hazard_table_size);
for (i = 0; i <= highest; ++i) {
- if (hazard_table [i].hazard_pointers [0] == p
- || hazard_table [i].hazard_pointers [1] == p)
- return TRUE;
+ for (j = 0; j < HAZARD_POINTER_COUNT; ++j) {
+ if (hazard_table [i].hazard_pointers [j] == p)
+ return TRUE;
+ }
}
return FALSE;
return p;
/* Make it hazardous */
mono_hazard_pointer_set (hp, hazard_index, mono_lls_pointer_unmask (p));
+
+ mono_memory_barrier ();
+
/* Check that it's still the same. If not, try
again. */
if (*pp != p) {
try_again:
prev = &list->head;
+
+ /*
+ * prev is not really a hazardous pointer, but we return prev
+ * in hazard pointer 2, so we set it here. Note also that
+ * prev is not a pointer to a node. We use here the fact that
+ * the first element in a node is the next pointer, so it
+ * works, but it's not pretty.
+ */
mono_hazard_pointer_set (hp, 2, prev);
- cur = mono_lls_pointer_unmask (get_hazardous_pointer ((gpointer*)prev, hp, 1));
+ cur = get_hazardous_pointer_with_mask ((gpointer*)prev, hp, 1);
while (1) {
if (cur == NULL)
next = get_hazardous_pointer_with_mask ((gpointer*)&cur->next, hp, 0);
cur_key = cur->key;
+ /*
+ * We need to make sure that we dereference prev below
+ * after reading cur->next above, so we need a read
+ * barrier.
+ */
+ mono_memory_read_barrier ();
+
if (*prev != cur)
goto try_again;
mono_hazard_pointer_set (hp, 2, cur);
} else {
next = mono_lls_pointer_unmask (next);
- if (InterlockedCompareExchangePointer ((volatile gpointer*)prev, next, cur) == next) {
+ if (InterlockedCompareExchangePointer ((volatile gpointer*)prev, next, cur) == cur) {
+ /* The hazard pointer must be cleared after the CAS. */
+ mono_memory_write_barrier ();
+ mono_hazard_pointer_clear (hp, 1);
if (list->free_node_func)
mono_thread_hazardous_free_or_queue (cur, list->free_node_func);
} else
value->next = cur;
mono_hazard_pointer_set (hp, 0, value);
+ /* The CAS must happen after setting the hazard pointer. */
+ mono_memory_write_barrier ();
if (InterlockedCompareExchangePointer ((volatile gpointer*)prev, value, cur) == cur)
return TRUE;
}
cur = mono_hazard_pointer_get_val (hp, 1);
prev = mono_hazard_pointer_get_val (hp, 2);
+ g_assert (cur == value);
+
if (InterlockedCompareExchangePointer ((volatile gpointer*)&cur->next, mask (next, 1), next) != next)
continue;
+ /* The second CAS must happen before the first. */
+ mono_memory_write_barrier ();
if (InterlockedCompareExchangePointer ((volatile gpointer*)prev, next, cur) == cur) {
+ /* The CAS must happen before the hazard pointer clear. */
+ mono_memory_write_barrier ();
+ mono_hazard_pointer_clear (hp, 1);
if (list->free_node_func)
mono_thread_hazardous_free_or_queue (value, list->free_node_func);
} else
typedef struct _MonoLinkedListSetNode MonoLinkedListSetNode;
struct _MonoLinkedListSetNode {
+ /* next must be the first element in this struct! */
MonoLinkedListSetNode *next;
uintptr_t key;
};
*/
#define MONO_LLS_FOREACH(list, element) {\
MonoLinkedListSetNode *__cur; \
- for (__cur = list->head; __cur; __cur = mono_lls_pointer_unmask (__cur->next)) \
+ for (__cur = (list)->head; __cur; __cur = mono_lls_pointer_unmask (__cur->next)) \
if (!mono_lls_pointer_get_mark (__cur->next)) { \
- element = (typeof(element))__cur; \
+ (element) = (typeof((element)))__cur; \
#define MONO_LLS_END_FOREACH }}
#define MONO_LLS_FOREACH_SAFE(list, element) {\
MonoThreadHazardPointers *__hp = mono_hazard_pointer_get (); \
MonoLinkedListSetNode *__cur, *__next; \
- for (__cur = mono_lls_pointer_unmask (get_hazardous_pointer ((gpointer volatile*)&list->head, __hp, 1)); \
+ for (__cur = mono_lls_pointer_unmask (get_hazardous_pointer ((gpointer volatile*)&(list)->head, __hp, 1)); \
__cur; \
__cur = mono_lls_info_step (__next, __hp)) { \
__next = get_hazardous_pointer_with_mask ((gpointer volatile*)&__cur->next, __hp, 0); \
if (!mono_lls_pointer_get_mark (__next)) { \
- element = (typeof(element))__cur;
+ (element) = (typeof((element)))__cur;
#define MONO_LLS_END_FOREACH_SAFE \
} \