|
|
|
@ -105,11 +105,9 @@ ck_fifo_spsc_init(struct ck_fifo_spsc *fifo, struct ck_fifo_spsc_entry *stub)
|
|
|
|
|
|
|
|
|
|
ck_spinlock_init(&fifo->m_head);
|
|
|
|
|
ck_spinlock_init(&fifo->m_tail);
|
|
|
|
|
ck_pr_store_ptr(&stub->next, NULL);
|
|
|
|
|
ck_pr_store_ptr(&fifo->head, stub);
|
|
|
|
|
ck_pr_store_ptr(&fifo->tail, stub);
|
|
|
|
|
ck_pr_store_ptr(&fifo->head_snapshot, stub);
|
|
|
|
|
ck_pr_store_ptr(&fifo->garbage, stub);
|
|
|
|
|
|
|
|
|
|
stub->next = NULL;
|
|
|
|
|
fifo->head = fifo->tail = fifo->head_snapshot = fifo->garbage = stub;
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
@ -119,33 +117,33 @@ ck_fifo_spsc_enqueue(struct ck_fifo_spsc *fifo,
|
|
|
|
|
void *value)
|
|
|
|
|
{
|
|
|
|
|
|
|
|
|
|
ck_pr_store_ptr(&entry->value, value);
|
|
|
|
|
ck_pr_store_ptr(&entry->next, NULL);
|
|
|
|
|
ck_pr_store_ptr(&fifo->tail->next, entry);
|
|
|
|
|
entry->value = value;
|
|
|
|
|
entry->next = NULL;
|
|
|
|
|
|
|
|
|
|
/* If stub->next is visible, guarantee that entry is consistent. */
|
|
|
|
|
ck_pr_fence_store();
|
|
|
|
|
ck_pr_store_ptr(&fifo->tail, entry);
|
|
|
|
|
ck_pr_store_ptr(&fifo->tail->next, entry);
|
|
|
|
|
fifo->tail = entry;
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
CK_CC_INLINE static bool
|
|
|
|
|
ck_fifo_spsc_dequeue(struct ck_fifo_spsc *fifo, void *value)
|
|
|
|
|
{
|
|
|
|
|
struct ck_fifo_spsc_entry *stub, *entry;
|
|
|
|
|
void *store;
|
|
|
|
|
struct ck_fifo_spsc_entry *entry;
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* The head pointer is guaranteed to always point to a stub entry.
|
|
|
|
|
* If the stub entry does not point to an entry, then the queue is
|
|
|
|
|
* empty.
|
|
|
|
|
*/
|
|
|
|
|
stub = ck_pr_load_ptr(&fifo->head);
|
|
|
|
|
ck_pr_fence_load();
|
|
|
|
|
entry = stub->next;
|
|
|
|
|
entry = ck_pr_load_ptr(&fifo->head->next);
|
|
|
|
|
if (entry == NULL)
|
|
|
|
|
return (false);
|
|
|
|
|
|
|
|
|
|
store = ck_pr_load_ptr(&entry->value);
|
|
|
|
|
ck_pr_store_ptr(value, store);
|
|
|
|
|
/* If entry is visible, guarantee store to value is visible. */
|
|
|
|
|
ck_pr_fence_load();
|
|
|
|
|
ck_pr_store_ptr(value, entry->value);
|
|
|
|
|
ck_pr_store_ptr(&fifo->head, entry);
|
|
|
|
|
return (true);
|
|
|
|
|
}
|
|
|
|
@ -157,21 +155,17 @@ ck_fifo_spsc_dequeue(struct ck_fifo_spsc *fifo, void *value)
|
|
|
|
|
CK_CC_INLINE static struct ck_fifo_spsc_entry *
|
|
|
|
|
ck_fifo_spsc_recycle(struct ck_fifo_spsc *fifo)
|
|
|
|
|
{
|
|
|
|
|
struct ck_fifo_spsc_entry *p, *garbage;
|
|
|
|
|
|
|
|
|
|
garbage = ck_pr_load_ptr(&fifo->garbage);
|
|
|
|
|
p = ck_pr_load_ptr(&fifo->head_snapshot);
|
|
|
|
|
struct ck_fifo_spsc_entry *garbage;
|
|
|
|
|
|
|
|
|
|
if (garbage == p) {
|
|
|
|
|
p = ck_pr_load_ptr(&fifo->head);
|
|
|
|
|
ck_pr_store_ptr(&fifo->head_snapshot, p);
|
|
|
|
|
if (garbage == p)
|
|
|
|
|
return (NULL);
|
|
|
|
|
if (fifo->head_snapshot == fifo->garbage) {
|
|
|
|
|
fifo->head_snapshot = ck_pr_load_ptr(&fifo->head);
|
|
|
|
|
if (fifo->head_snapshot == fifo->garbage)
|
|
|
|
|
return NULL;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
p = garbage;
|
|
|
|
|
ck_pr_store_ptr(&fifo->garbage, garbage->next);
|
|
|
|
|
return (p);
|
|
|
|
|
garbage = fifo->garbage;
|
|
|
|
|
fifo->garbage = garbage->next;
|
|
|
|
|
return (garbage);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
CK_CC_INLINE static bool
|
|
|
|
@ -222,12 +216,10 @@ CK_CC_INLINE static void
|
|
|
|
|
ck_fifo_mpmc_init(struct ck_fifo_mpmc *fifo, struct ck_fifo_mpmc_entry *stub)
|
|
|
|
|
{
|
|
|
|
|
|
|
|
|
|
ck_pr_store_ptr(&fifo->head.pointer, stub);
|
|
|
|
|
ck_pr_store_ptr(&fifo->head.generation, 0);
|
|
|
|
|
ck_pr_store_ptr(&fifo->tail.pointer, stub);
|
|
|
|
|
ck_pr_store_ptr(&fifo->tail.generation, 0);
|
|
|
|
|
ck_pr_store_ptr(&stub->next.pointer, NULL);
|
|
|
|
|
ck_pr_store_ptr(&stub->next.generation, 0);
|
|
|
|
|
stub->next.pointer = NULL;
|
|
|
|
|
stub->next.generation = NULL;
|
|
|
|
|
fifo->head.pointer = fifo->tail.pointer = stub;
|
|
|
|
|
fifo->head.generation = fifo->tail.generation = NULL;
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
@ -282,6 +274,7 @@ ck_fifo_mpmc_enqueue(struct ck_fifo_mpmc *fifo,
|
|
|
|
|
|
|
|
|
|
/* After a successful insert, forward the tail to the new entry. */
|
|
|
|
|
update.generation = tail.generation + 1;
|
|
|
|
|
ck_pr_fence_store();
|
|
|
|
|
ck_pr_cas_ptr_2(&fifo->tail, &tail, &update);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
@ -332,6 +325,7 @@ ck_fifo_mpmc_tryenqueue(struct ck_fifo_mpmc *fifo,
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* After a successful insert, forward the tail to the new entry. */
|
|
|
|
|
ck_pr_fence_store();
|
|
|
|
|
update.generation = tail.generation + 1;
|
|
|
|
|
ck_pr_cas_ptr_2(&fifo->tail, &tail, &update);
|
|
|
|
|
return true;
|
|
|
|
|