1/* @title: Multi-Producer Multi-Consumer Queue */
2#pragma once
3#include <stdatomic.h>
4#include <stdbool.h>
5#include <stddef.h>
6#include <stdint.h>
7
8struct mpmc_slot {
9 _Atomic uint64_t seq;
10 uintptr_t data;
11};
12
13struct mpmc_queue {
14 size_t capacity;
15 size_t mask;
16 _Atomic uint64_t head;
17 _Atomic uint64_t tail;
18 struct mpmc_slot *slots;
19};
20
21#define MPMC_QUEUE_INIT \
22 (struct mpmc_queue) { \
23 .capacity = 0, .mask = 0, .head = 0, .tail = 0, .slots = NULL \
24 }
25
26bool mpmc_queue_init(struct mpmc_queue *q, size_t capacity);
27
28void mpmc_queue_init_static(struct mpmc_queue *q, struct mpmc_slot *slots,
29 size_t capacity);
30
31void mpmc_queue_destroy(struct mpmc_queue *q);
32
33bool mpmc_queue_enqueue(struct mpmc_queue *q, void *ptr);
34bool mpmc_queue_enqueue_uintptr(struct mpmc_queue *q, uintptr_t val);
35
36bool mpmc_queue_dequeue(struct mpmc_queue *q, void **out_ptr);
37bool mpmc_queue_dequeue_uintptr(struct mpmc_queue *q, uintptr_t *out_val);
38
39static inline bool mpmc_queue_empty(const struct mpmc_queue *q) {
40 uint64_t h = atomic_load_explicit(&q->head, memory_order_relaxed);
41 uint64_t t = atomic_load_explicit(&q->tail, memory_order_relaxed);
42 return h == t;
43}
44
45static inline size_t mpmc_queue_capacity(const struct mpmc_queue *q) {
46 return q->capacity;
47}
48