forked from amir/filehasher
Replacing Malloc and strdup in scan helper function with FileEntry and path arenas
This commit is contained in:
149
lf_mpmc.h
149
lf_mpmc.h
@@ -36,6 +36,8 @@ typedef struct {
|
||||
CACHE_ALIGN atomic_size_t head;
|
||||
CACHE_ALIGN atomic_size_t tail;
|
||||
|
||||
CACHE_ALIGN atomic_size_t work_count;
|
||||
|
||||
size_t capacity;
|
||||
size_t mask;
|
||||
|
||||
@@ -91,6 +93,7 @@ static void mpmc_init(MPMCQueue *q, size_t max_capacity) {
|
||||
|
||||
atomic_init(&q->head, 0);
|
||||
atomic_init(&q->tail, 0);
|
||||
atomic_init(&q->work_count, 0);
|
||||
|
||||
plat_sem_init(&q->items_sem, 0);
|
||||
}
|
||||
@@ -138,6 +141,7 @@ static void mpmc_commit_more(MPMCQueue *q) {
|
||||
/* ----------------------------------------------------------- */
|
||||
/* PUSH */
|
||||
/* ----------------------------------------------------------- */
|
||||
// Does not increment work
|
||||
static void mpmc_push(MPMCQueue *q, void *item) {
|
||||
MPMCSlot *slot;
|
||||
size_t pos;
|
||||
@@ -184,8 +188,55 @@ static void mpmc_push(MPMCQueue *q, void *item) {
|
||||
plat_sem_post(&q->items_sem, 1);
|
||||
}
|
||||
|
||||
// Increment work
|
||||
static void mpmc_push_work(MPMCQueue *q, void *item) {
|
||||
MPMCSlot *slot;
|
||||
size_t pos;
|
||||
|
||||
for (;;) {
|
||||
|
||||
pos = atomic_load_explicit(&q->tail, memory_order_relaxed);
|
||||
|
||||
// ensure the slot is committed BEFORE accessing it
|
||||
size_t committed =
|
||||
atomic_load_explicit(&q->committed, memory_order_relaxed);
|
||||
|
||||
if (unlikely(pos >= committed)) {
|
||||
mpmc_commit_more(q);
|
||||
continue;
|
||||
}
|
||||
|
||||
slot = &q->slots[pos & q->mask];
|
||||
|
||||
size_t seq = atomic_load_explicit(&slot->seq, memory_order_acquire);
|
||||
intptr_t diff = (intptr_t)seq - (intptr_t)pos;
|
||||
|
||||
if (likely(diff == 0)) {
|
||||
|
||||
if (atomic_compare_exchange_weak_explicit(&q->tail, &pos, pos + 1,
|
||||
memory_order_relaxed,
|
||||
memory_order_relaxed))
|
||||
break;
|
||||
|
||||
} else if (diff < 0) { // queue actually full
|
||||
|
||||
Sleep(1000);
|
||||
|
||||
} else { // waiting to grow
|
||||
|
||||
Sleep(0);
|
||||
}
|
||||
}
|
||||
|
||||
slot->data = item;
|
||||
|
||||
atomic_store_explicit(&slot->seq, pos + 1, memory_order_release);
|
||||
|
||||
atomic_fetch_add(&q->work_count, 1);
|
||||
plat_sem_post(&q->items_sem, 1);
|
||||
}
|
||||
/* ----------------------------------------------------------- */
|
||||
/* POP (blocking with semaphore) */
|
||||
/* POP */
|
||||
/* ----------------------------------------------------------- */
|
||||
static void *mpmc_pop(MPMCQueue *q) {
|
||||
|
||||
@@ -213,7 +264,7 @@ static void *mpmc_pop(MPMCQueue *q) {
|
||||
|
||||
} else { // slot is still transitioning (written by another thread)
|
||||
if (++spins > 10) {
|
||||
SwitchToThread(); // yield CPU
|
||||
Sleep(0); // yield CPU
|
||||
spins = 0;
|
||||
} else {
|
||||
cpu_pause();
|
||||
@@ -231,48 +282,48 @@ static void *mpmc_pop(MPMCQueue *q) {
|
||||
/* ----------------------------------------------------------- */
|
||||
/* TRY POP (non blocking) */
|
||||
/* ----------------------------------------------------------- */
|
||||
static b32 mpmc_try_pop(MPMCQueue *q, void **out) {
|
||||
|
||||
if (!plat_sem_trywait(&q->items_sem))
|
||||
return false;
|
||||
|
||||
MPMCSlot *slot;
|
||||
size_t pos;
|
||||
|
||||
int spins = 0;
|
||||
|
||||
for (;;) {
|
||||
|
||||
pos = atomic_load_explicit(&q->head, memory_order_relaxed);
|
||||
slot = &q->slots[pos & q->mask];
|
||||
|
||||
size_t seq = atomic_load_explicit(&slot->seq, memory_order_acquire);
|
||||
intptr_t diff = (intptr_t)seq - (intptr_t)(pos + 1);
|
||||
|
||||
if (likely(diff == 0)) {
|
||||
|
||||
if (atomic_compare_exchange_weak_explicit(&q->head, &pos, pos + 1,
|
||||
memory_order_relaxed,
|
||||
memory_order_relaxed))
|
||||
break;
|
||||
|
||||
} else {
|
||||
|
||||
if (++spins > 10) {
|
||||
SwitchToThread();
|
||||
spins = 0;
|
||||
} else {
|
||||
cpu_pause();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
*out = slot->data;
|
||||
|
||||
atomic_store_explicit(&slot->seq, pos + q->capacity, memory_order_release);
|
||||
|
||||
return true;
|
||||
}
|
||||
// static b32 mpmc_try_pop(MPMCQueue *q, void **out) {
|
||||
//
|
||||
// if (!plat_sem_trywait(&q->items_sem))
|
||||
// return false;
|
||||
//
|
||||
// MPMCSlot *slot;
|
||||
// size_t pos;
|
||||
//
|
||||
// int spins = 0;
|
||||
//
|
||||
// for (;;) {
|
||||
//
|
||||
// pos = atomic_load_explicit(&q->head, memory_order_relaxed);
|
||||
// slot = &q->slots[pos & q->mask];
|
||||
//
|
||||
// size_t seq = atomic_load_explicit(&slot->seq, memory_order_acquire);
|
||||
// intptr_t diff = (intptr_t)seq - (intptr_t)(pos + 1);
|
||||
//
|
||||
// if (likely(diff == 0)) {
|
||||
//
|
||||
// if (atomic_compare_exchange_weak_explicit(&q->head, &pos, pos + 1,
|
||||
// memory_order_relaxed,
|
||||
// memory_order_relaxed))
|
||||
// break;
|
||||
//
|
||||
// } else {
|
||||
//
|
||||
// if (++spins > 10) {
|
||||
// SwitchToThread();
|
||||
// spins = 0;
|
||||
// } else {
|
||||
// cpu_pause();
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// *out = slot->data;
|
||||
//
|
||||
// atomic_store_explicit(&slot->seq, pos + q->capacity, memory_order_release);
|
||||
//
|
||||
// return true;
|
||||
// }
|
||||
|
||||
/* ----------------------------------------------------------- */
|
||||
/* PUSH POISON */
|
||||
@@ -288,6 +339,16 @@ static void mpmc_producers_finished(MPMCQueue *q, u8 consumer_count) {
|
||||
}
|
||||
}
|
||||
|
||||
/* ----------------------------------------------------------- */
|
||||
/* Done */
|
||||
/* ----------------------------------------------------------- */
|
||||
static void mpmc_task_done(MPMCQueue *q, u8 consumer_count) {
|
||||
size_t prev = atomic_fetch_sub(&q->work_count, 1);
|
||||
if (prev == 1) {
|
||||
mpmc_producers_finished(q, consumer_count);
|
||||
}
|
||||
}
|
||||
|
||||
/* ----------------------------------------------------------- */
|
||||
/* MPMC Cleanup */
|
||||
/* ----------------------------------------------------------- */
|
||||
|
||||
Reference in New Issue
Block a user