/* * 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_ */