#include <mono/metadata/object.h>
#include <mono/metadata/mono-cq.h>
#include <mono/metadata/mono-mlist.h>
+#include <mono/utils/mono-memory-model.h>
#define CQ_DEBUG(...)
//#define CQ_DEBUG(...) g_message(__VA_ARGS__)
g_assert (monocq_item_vtable);
}
queue = (MonoCQItem *) mono_object_new_fast (monocq_item_vtable);
- queue->array = mono_array_new (domain, mono_defaults.object_class, CQ_ARRAY_SIZE);
- queue->array_state = mono_array_new (domain, mono_defaults.byte_class, CQ_ARRAY_SIZE);
+ MONO_OBJECT_SETREF (queue, array, mono_array_new (domain, mono_defaults.object_class, CQ_ARRAY_SIZE));
+ MONO_OBJECT_SETREF (queue, array_state, mono_array_new (domain, mono_defaults.byte_class, CQ_ARRAY_SIZE));
return queue;
}
if (!cq)
return;
- memset (cq, 0, sizeof (MonoCQ));
+ mono_gc_bzero (cq, sizeof (MonoCQ));
MONO_GC_UNREGISTER_ROOT (cq->tail);
MONO_GC_UNREGISTER_ROOT (cq->head);
g_free (cq);
CQ_DEBUG ("Adding node");
n = mono_mlist_alloc ((MonoObject *) mono_cqitem_alloc ());
prev_tail = cq->tail;
- prev_tail->next = n;
+ MONO_OBJECT_SETREF (prev_tail, next, n);
cq->tail = n;
}
if (InterlockedCompareExchange (&queue->last, pos + 1, pos) == pos) {
mono_array_setref (queue->array, pos, obj);
+ STORE_STORE_FENCE;
mono_array_set (queue->array_state, char, pos, TRUE);
if ((pos + 1) == CQ_ARRAY_SIZE) {
CQ_DEBUG ("enqueue(): pos + 1 == CQ_ARRAY_SIZE, %d. Adding node.", CQ_ARRAY_SIZE);
while (mono_array_get (queue->array_state, char, pos) == FALSE) {
SleepEx (0, FALSE);
}
+ LOAD_LOAD_FENCE;
*obj = mono_array_get (queue->array, MonoObject *, pos);
+
+ /*
+ Here don't need to fence since the only spot that reads it is the one above.
+ Additionally, the first store is superfluous, so it can happen OOO with the second.
+ */
mono_array_set (queue->array, MonoObject *, pos, NULL);
mono_array_set (queue->array_state, char, pos, FALSE);
+
+ /*
+ We should do a STORE_LOAD fence here to make sure subsequent loads see new state instead
+ of the above stores. We can safely ignore this as the only issue of seeing a stale value
+ is the thread yielding. Given how unfrequent this will be in practice, we better avoid the
+ very expensive STORE_LOAD fence.
+ */
+
if ((pos + 1) == CQ_ARRAY_SIZE) {
mono_cq_remove_node (cq);
}