Circular queues implementations and a test.

- naive circular queue, described in the article "A Scalable, Portable, and
 Memory-Efficient Lock-Free FIFO Queue" by Ruslan Nikolaev:
https://drops.dagstuhl.de/opus/volltexte/2019/11335/pdf/LIPIcs-DISC-2019-28.pdf
- circular queue, proposed by Valentin Bartenev in the "Unit router application
IPC" design draft
This commit is contained in:
Max Romanov
2020-08-11 19:20:32 +03:00
parent a1e9df2aef
commit a82cf4ffb6
4 changed files with 938 additions and 0 deletions

146
src/nxt_nvbcq.h Normal file
View File

@@ -0,0 +1,146 @@
/*
* Copyright (C) NGINX, Inc.
*/
#ifndef _NXT_NVBCQ_H_INCLUDED_
#define _NXT_NVBCQ_H_INCLUDED_
/* Numeric VBart Circular Queue */
#define NXT_NVBCQ_SIZE 16384
typedef uint32_t nxt_nvbcq_atomic_t;
struct nxt_nvbcq_s {
nxt_nvbcq_atomic_t head;
nxt_nvbcq_atomic_t entries[NXT_NVBCQ_SIZE];
nxt_nvbcq_atomic_t tail;
};
typedef struct nxt_nvbcq_s nxt_nvbcq_t;
static inline nxt_nvbcq_atomic_t
nxt_nvbcq_head(nxt_nvbcq_t const volatile *q)
{
return q->head;
}
static inline nxt_nvbcq_atomic_t
nxt_nvbcq_tail(nxt_nvbcq_t const volatile *q)
{
return q->tail;
}
static inline void
nxt_nvbcq_tail_cmp_inc(nxt_nvbcq_t volatile *q, nxt_nvbcq_atomic_t t)
{
nxt_atomic_cmp_set(&q->tail, t, t + 1);
}
static inline nxt_nvbcq_atomic_t
nxt_nvbcq_index(nxt_nvbcq_t const volatile *q, nxt_nvbcq_atomic_t i)
{
return i % NXT_NVBCQ_SIZE;
}
static inline nxt_nvbcq_atomic_t
nxt_nvbcq_map(nxt_nvbcq_t const volatile *q, nxt_nvbcq_atomic_t i)
{
return i % NXT_NVBCQ_SIZE;
}
static inline nxt_nvbcq_atomic_t
nxt_nvbcq_empty(nxt_nvbcq_t const volatile *q)
{
return NXT_NVBCQ_SIZE;
}
static void
nxt_nvbcq_init(nxt_nvbcq_t volatile *q)
{
nxt_nvbcq_atomic_t i;
q->head = 0;
for (i = 0; i < NXT_NVBCQ_SIZE; i++) {
q->entries[i] = NXT_NVBCQ_SIZE;
}
q->tail = NXT_NVBCQ_SIZE;
}
static void
nxt_nvbcq_enqueue(nxt_nvbcq_t volatile *q, nxt_nvbcq_atomic_t val)
{
nxt_nvbcq_atomic_t t, h, i;
t = nxt_nvbcq_tail(q);
h = t - NXT_NVBCQ_SIZE;
for ( ;; ) {
i = nxt_nvbcq_map(q, t);
if (q->entries[i] == NXT_NVBCQ_SIZE
&& nxt_atomic_cmp_set(&q->entries[i], NXT_NVBCQ_SIZE, val))
{
nxt_nvbcq_tail_cmp_inc(q, t);
return;
}
if ((t - h) == NXT_NVBCQ_SIZE) {
h = nxt_nvbcq_head(q);
if ((t - h) == NXT_NVBCQ_SIZE) {
return;
}
}
t++;
}
}
static nxt_nvbcq_atomic_t
nxt_nvbcq_dequeue(nxt_nvbcq_t volatile *q)
{
nxt_nvbcq_atomic_t h, t, i, e;
h = nxt_nvbcq_head(q);
t = h + NXT_NVBCQ_SIZE;
for ( ;; ) {
i = nxt_nvbcq_map(q, h);
e = q->entries[i];
if (e < NXT_NVBCQ_SIZE
&& nxt_atomic_cmp_set(&q->entries[i], e, NXT_NVBCQ_SIZE))
{
nxt_atomic_cmp_set(&q->head, h, h + 1);
return e;
}
if ((t - h) == NXT_NVBCQ_SIZE) {
t = nxt_nvbcq_tail(q);
if ((t - h) == NXT_NVBCQ_SIZE) {
return NXT_NVBCQ_SIZE;
}
}
h++;
}
}
#endif /* _NXT_NVBCQ_H_INCLUDED_ */