[utils/lfq] Clarify and document the lock-free queue API.
authorAlex Rønne Petersen <alexrp@xamarin.com>
Fri, 8 Apr 2016 01:48:42 +0000 (03:48 +0200)
committerAlex Rønne Petersen <alexrp@xamarin.com>
Fri, 8 Apr 2016 17:55:10 +0000 (19:55 +0200)
mono/utils/lock-free-alloc.c
mono/utils/lock-free-queue.c
mono/utils/lock-free-queue.h
msvc/mono.def
msvc/monosgen.def

index e879d910f1c2e60fe32934c079f98eb840b24169..3be8342a49873dbc9e2796d44a76a81d5a9302e3 100644 (file)
@@ -277,7 +277,7 @@ desc_put_partial (gpointer _desc)
 
        g_assert (desc->anchor.data.state != STATE_FULL);
 
-       mono_lock_free_queue_node_free (&desc->node);
+       mono_lock_free_queue_node_unpoison (&desc->node);
        mono_lock_free_queue_enqueue (&desc->heap->sc->partial, &desc->node);
 }
 
index 464419960de18f73df442a23632400e78c5799ad..fbf02f523b8aae960d3e6940df6ffe4f4976ead6 100644 (file)
@@ -61,6 +61,9 @@
 #define END_MARKER     ((MonoLockFreeQueueNode *volatile)-2)
 #define FREE_NEXT      ((MonoLockFreeQueueNode *volatile)-3)
 
+/*
+ * Initialize a lock-free queue in-place at @q.
+ */
 void
 mono_lock_free_queue_init (MonoLockFreeQueue *q)
 {
@@ -77,17 +80,30 @@ mono_lock_free_queue_init (MonoLockFreeQueue *q)
        q->has_dummy = 1;
 }
 
+/*
+ * Initialize @node's state. If @poison is TRUE, @node may not be enqueued to a
+ * queue - @mono_lock_free_queue_node_unpoison must be called first; otherwise,
+ * the node can be enqueued right away.
+ *
+ * The poisoning feature is mainly intended for ensuring correctness in complex
+ * lock-free code that uses the queue. For example, in some code that reuses
+ * nodes, nodes can be poisoned when they're dequeued, and then unpoisoned and
+ * enqueued in their hazard free callback.
+ */
 void
-mono_lock_free_queue_node_init (MonoLockFreeQueueNode *node, gboolean to_be_freed)
+mono_lock_free_queue_node_init (MonoLockFreeQueueNode *node, gboolean poison)
 {
-       node->next = to_be_freed ? INVALID_NEXT : FREE_NEXT;
+       node->next = poison ? INVALID_NEXT : FREE_NEXT;
 #ifdef QUEUE_DEBUG
        node->in_queue = FALSE;
 #endif
 }
 
+/*
+ * Unpoisons @node so that it may be enqueued.
+ */
 void
-mono_lock_free_queue_node_free (MonoLockFreeQueueNode *node)
+mono_lock_free_queue_node_unpoison (MonoLockFreeQueueNode *node)
 {
        g_assert (node->next == INVALID_NEXT);
 #ifdef QUEUE_DEBUG
@@ -96,6 +112,10 @@ mono_lock_free_queue_node_free (MonoLockFreeQueueNode *node)
        node->next = FREE_NEXT;
 }
 
+/*
+ * Enqueue @node to @q. @node must have been initialized by a prior call to
+ * @mono_lock_free_queue_node_init, and must not be in a poisoned state.
+ */
 void
 mono_lock_free_queue_enqueue (MonoLockFreeQueue *q, MonoLockFreeQueueNode *node)
 {
@@ -158,7 +178,7 @@ static void
 free_dummy (gpointer _dummy)
 {
        MonoLockFreeQueueDummy *dummy = (MonoLockFreeQueueDummy *) _dummy;
-       mono_lock_free_queue_node_free (&dummy->node);
+       mono_lock_free_queue_node_unpoison (&dummy->node);
        g_assert (dummy->in_use);
        mono_memory_write_barrier ();
        dummy->in_use = 0;
@@ -208,6 +228,11 @@ try_reenqueue_dummy (MonoLockFreeQueue *q)
        return TRUE;
 }
 
+/*
+ * Dequeues a node from @q. Returns NULL if no nodes are available. The returned
+ * node is hazardous and must be freed with @mono_thread_hazardous_try_free or
+ * @mono_thread_hazardous_queue_free - it must not be freed directly.
+ */
 MonoLockFreeQueueNode*
 mono_lock_free_queue_dequeue (MonoLockFreeQueue *q)
 {
index 6ae52471e5b4967467b88eb319fabf67944216f9..300b4556ef251f3fb64274a8a4fe7c0d6d592059 100644 (file)
@@ -58,8 +58,8 @@ typedef struct {
 
 MONO_API void mono_lock_free_queue_init (MonoLockFreeQueue *q);
 
-MONO_API void mono_lock_free_queue_node_init (MonoLockFreeQueueNode *node, gboolean to_be_freed);
-MONO_API void mono_lock_free_queue_node_free (MonoLockFreeQueueNode *node);
+MONO_API void mono_lock_free_queue_node_init (MonoLockFreeQueueNode *node, gboolean poison);
+MONO_API void mono_lock_free_queue_node_unpoison (MonoLockFreeQueueNode *node);
 
 MONO_API void mono_lock_free_queue_enqueue (MonoLockFreeQueue *q, MonoLockFreeQueueNode *node);
 
index 17580cece36a95c448fc92237e82bee5f6b1cddb..8392a8c693d0ffc3c43544747d5a976253d74651 100644 (file)
@@ -496,7 +496,7 @@ mono_load_remote_field_new
 mono_lock_free_queue_dequeue
 mono_lock_free_queue_enqueue
 mono_lock_free_queue_init
-mono_lock_free_queue_node_free
+mono_lock_free_queue_node_unpoison
 mono_lock_free_queue_node_init
 mono_locks_dump
 mono_lookup_icall_symbol
index e4ca56dd9c680869385e9777e64d7618cca228e3..eee61f0242607037e52f1ea8ba04f48fba57c491 100644 (file)
@@ -498,7 +498,7 @@ mono_load_remote_field_new
 mono_lock_free_queue_dequeue
 mono_lock_free_queue_enqueue
 mono_lock_free_queue_init
-mono_lock_free_queue_node_free
+mono_lock_free_queue_node_unpoison
 mono_lock_free_queue_node_init
 mono_locks_dump
 mono_lookup_icall_symbol