ck_fifo: Add back-off and remove recycle.

Recycle will just be a bottleneck. The MPMC interface should instead
return a junk pointer and allow the user to manage its lifetime in
a way they see fit.
ck_pring
Samy Al Bahra 14 years ago
parent d7d1dfbf50
commit beafb7d78e

@ -28,6 +28,7 @@
#ifndef _CK_FIFO_H #ifndef _CK_FIFO_H
#define _CK_FIFO_H #define _CK_FIFO_H
#include <ck_backoff.h>
#include <ck_cc.h> #include <ck_cc.h>
#include <ck_md.h> #include <ck_md.h>
#include <ck_pr.h> #include <ck_pr.h>
@ -178,6 +179,7 @@ CK_CC_INLINE static void
ck_fifo_mpmc_enqueue(struct ck_fifo_mpmc *fifo, struct ck_fifo_mpmc_entry *entry, void *value) ck_fifo_mpmc_enqueue(struct ck_fifo_mpmc *fifo, struct ck_fifo_mpmc_entry *entry, void *value)
{ {
struct ck_fifo_mpmc_pointer tail, next, update; struct ck_fifo_mpmc_pointer tail, next, update;
ck_backoff_t backoff = CK_BACKOFF_INITIALIZER;
/* /*
* Prepare the upcoming node and make sure to commit the updates * Prepare the upcoming node and make sure to commit the updates
@ -195,8 +197,10 @@ ck_fifo_mpmc_enqueue(struct ck_fifo_mpmc *fifo, struct ck_fifo_mpmc_entry *entry
next.generation = ck_pr_load_ptr(&tail.pointer->next.generation); next.generation = ck_pr_load_ptr(&tail.pointer->next.generation);
next.pointer = ck_pr_load_ptr(&tail.pointer->next.pointer); next.pointer = ck_pr_load_ptr(&tail.pointer->next.pointer);
if (ck_pr_load_ptr(&fifo->tail.generation) != tail.generation) if (ck_pr_load_ptr(&fifo->tail.generation) != tail.generation) {
ck_backoff_eb(&backoff);
continue; continue;
}
if (next.pointer != NULL) { if (next.pointer != NULL) {
/* /*
@ -217,6 +221,8 @@ ck_fifo_mpmc_enqueue(struct ck_fifo_mpmc *fifo, struct ck_fifo_mpmc_entry *entry
update.generation = next.generation + 1; update.generation = next.generation + 1;
if (ck_pr_cas_ptr_2(&tail.pointer->next, &next, &update) == true) if (ck_pr_cas_ptr_2(&tail.pointer->next, &next, &update) == true)
break; break;
ck_backoff_eb(&backoff);
} }
} }
@ -230,6 +236,7 @@ CK_CC_INLINE static bool
ck_fifo_mpmc_dequeue(struct ck_fifo_mpmc *fifo, void *value) ck_fifo_mpmc_dequeue(struct ck_fifo_mpmc *fifo, void *value)
{ {
struct ck_fifo_mpmc_pointer head, tail, next, update; struct ck_fifo_mpmc_pointer head, tail, next, update;
ck_backoff_t backoff = CK_BACKOFF_INITIALIZER;
for (;;) { for (;;) {
head.generation = ck_pr_load_ptr(&fifo->head.generation); head.generation = ck_pr_load_ptr(&fifo->head.generation);
@ -262,30 +269,14 @@ ck_fifo_mpmc_dequeue(struct ck_fifo_mpmc *fifo, void *value)
update.generation = head.generation + 1; update.generation = head.generation + 1;
if (ck_pr_cas_ptr_2(&fifo->head, &head, &update) == true) if (ck_pr_cas_ptr_2(&fifo->head, &head, &update) == true)
break; break;
ck_backoff_eb(&backoff);
} }
} }
return (true); return (true);
} }
CK_CC_INLINE static struct ck_fifo_mpmc_entry *
ck_fifo_mpmc_recycle(struct ck_fifo_mpmc *fifo)
{
struct ck_fifo_mpmc_pointer garbage;
struct ck_fifo_mpmc_entry *p;
garbage.generation = ck_pr_load_ptr(&fifo->garbage.generation);
garbage.pointer = ck_pr_load_ptr(&fifo->garbage.pointer);
p = ck_pr_load_ptr(&fifo->head_snapshot);
if (garbage.pointer == p) {
p = ck_pr_load_ptr(&fifo->head.pointer);
ck_pr_store_ptr(&fifo->head_snapshot, p);
}
return (NULL);
}
#define CK_FIFO_MPMC_ISEMPTY(f) ((f)->head.pointer->next.pointer == NULL) #define CK_FIFO_MPMC_ISEMPTY(f) ((f)->head.pointer->next.pointer == NULL)
#define CK_FIFO_MPMC_FIRST(f) ((f)->head.pointer->next.pointer) #define CK_FIFO_MPMC_FIRST(f) ((f)->head.pointer->next.pointer)
#define CK_FIFO_MPMC_NEXT(m) ((m)->next.pointer) #define CK_FIFO_MPMC_NEXT(m) ((m)->next.pointer)

Loading…
Cancel
Save