8# include <click/algorithm.hh>
10# include <rte_errno.h>
11# include <click/dpdk_glue.hh>
17 template <
typename T,
size_t RING_SIZE>
class BaseRing {
21 inline bool has_space() {
22 return head - tail < RING_SIZE;
25 inline bool is_empty() {
39 T &v = ring[tail % RING_SIZE];
46 inline bool insert(T batch) {
48 ring[head % RING_SIZE] = batch;
55 inline unsigned int count() {
64 inline void pool_transfer(
unsigned int thread_from,
unsigned int thread_to) {
69 inline void hint(
unsigned int num,
unsigned int thread_id) {
88 inline uint32_t next_i(uint32_t i) {
95 inline void inc_i(uint32_t &i) {
125 inline bool insert(T batch) {
134 inline unsigned int count() {
135 int count = (int)head - (
int)tail;
141 inline bool is_empty() {
145 inline bool is_full() {
146 return next_i(head) == tail;
153 inline bool initialized() {
157 inline void initialize(
int size,
const char* = 0) {
175 static_assert(std::is_pointer<T>(),
"MPMCDynamicRing can only be used with pointers");
178 inline void initialize(
int size,
const char* name,
int flags = 0) {
180 assert(dpdk_enabled);
181 _ring = rte_ring_create(name, next_pow2(size), SOCKET_ID_ANY, flags);
182 if (unlikely(_ring == 0)) {
183 click_chatter(
"Could not create DPDK ring error %d: %s",rte_errno,rte_strerror(rte_errno));
187 inline bool insert(T o) {
188 return rte_ring_mp_enqueue(_ring, (
void*)o) == 0;
194#if RTE_VERSION >= RTE_VERSION_NUM(17,5,0,0)
195 if (rte_ring_mc_dequeue_bulk(_ring, (
void**)&o, 1, 0) == 0)
197 if (rte_ring_mc_dequeue_bulk(_ring, (
void**)&o, 1) == 0)
205 inline bool is_empty() {
206 return rte_ring_empty(_ring);
209 inline bool is_full() {
210 return rte_ring_full(_ring);
215 rte_ring_free(_ring);
220template <
typename T>
class MPSCDynamicRing :
public MPMCDynamicRing<T> {
223 inline void initialize(
int size,
const char* name) {
229#if RTE_VERSION >= RTE_VERSION_NUM(17,5,0,0)
230 if (rte_ring_sc_dequeue_bulk(this->_ring, (
void**)&o, 1, 0) == 0)
232 if (rte_ring_sc_dequeue_bulk(this->_ring, (
void**)&o, 1) == 0)
261 inline bool insert(T v) {
269template <
typename T>
class MPSCDynamicRing :
public MPMCDynamicRing<T> {};
274template <
typename T,
size_t RING_SIZE>
class Ring :
public BaseRing<T,RING_SIZE> {};
276template <
typename T>
class CircleList {
278 CircleList() : _data(0), _maxsize(0),_size(0),_cur(0) {
282 CircleList(
unsigned int max_size) : _data(0), _maxsize(max_size),_size(0),_cur(0) {
287 return _data[_cur % _size];
291 return _data[++_cur % _size];
294 inline void advance() {
299 assert(_size < _maxsize);
301 _data =
new T[_maxsize];
305 unsigned int size() {
313 inline bool is_empty() {
319 unsigned int _maxsize;
325template <
typename T,
size_t MAX_SIZE>
class MPMCLIFO {
331 inline bool has_space() {
332 return _count < MAX_SIZE;
335 inline bool is_empty() {
344 MPMCLIFO() : _lock(), id(0),_first(0),_count(0) {
356 _first = _first->prev();
362 inline bool insert(T v) {
375 inline unsigned int count() {
380 inline void pool_transfer(
unsigned int thread_from,
unsigned int thread_to) {
385 inline void hint(
unsigned int num,
unsigned int thread_id) {
392template <
typename T,
size_t RING_SIZE>
class MPMCRing :
public SPSCRing<T, RING_SIZE> {
397 inline void acquire() {
401 inline void release() {
405 inline void release_tail() {
409 inline void release_head() {
413 inline void acquire_tail() {
417 inline void acquire_head() {
423 MPMCRing() : _lock() {
427 inline bool insert(T batch) {
429 if (SPSCRing<T,RING_SIZE>::has_space()) {
430 SPSCRing<T,RING_SIZE>::ring[SPSCRing<T,RING_SIZE>::head % RING_SIZE] = batch;
431 SPSCRing<T,RING_SIZE>::head++;
442 if (!SPSCRing<T,RING_SIZE>::is_empty()) {
443 T &v = SPSCRing<T,RING_SIZE>::ring[SPSCRing<T,RING_SIZE>::tail % RING_SIZE];
444 SPSCRing<T,RING_SIZE>::tail++;
454template <
typename T,
size_t RING_SIZE>
class SMPMCRing :
public SPSCRing<T, RING_SIZE> {
458 inline void release_tail() {
462 inline void release_head() {
463 _lock_head.release();
466 inline void acquire_tail() {
470 inline void acquire_head() {
471 _lock_head.acquire();
474 inline bool insert(T batch) {
476 if (SPSCRing<T,RING_SIZE>::has_space()) {
477 SPSCRing<T,RING_SIZE>::ring[SPSCRing<T,RING_SIZE>::head % RING_SIZE] = batch;
478 SPSCRing<T,RING_SIZE>::head++;
480 click_compiler_fence();
484 click_compiler_fence();
491 if (!SPSCRing<T,RING_SIZE>::is_empty()) {
492 T &v = SPSCRing<T,RING_SIZE>::ring[SPSCRing<T,RING_SIZE>::tail % RING_SIZE];
493 SPSCRing<T,RING_SIZE>::tail++;
495 click_compiler_fence();
499 click_compiler_fence();
506template <
typename T,
size_t RING_SIZE>
class MPSCRing :
public SPSCRing<T, RING_SIZE> {
509 inline void release_head() {
513 inline void acquire_head() {
514 _lock_head.acquire();
518 inline bool insert(T batch) {
520 if (SPSCRing<T,RING_SIZE>::has_space()) {
521 SPSCRing<T,RING_SIZE>::ring[SPSCRing<T,RING_SIZE>::head % RING_SIZE] = batch;
522 SPSCRing<T,RING_SIZE>::head++;
An atomic 32-bit integer.
A non-recursive spinlock for SMP Click threads.
Definition sync.hh:587
void release()
Releases the SimpleSpinlock.
Definition sync.hh:665
void acquire()
Acquires the SimpleSpinlock.
Definition sync.hh:628
A recursive spinlock for SMP Click threads.
Definition sync.hh:439
void release()
Releases the Spinlock.
Definition sync.hh:534
void acquire()
Acquires the Spinlock.
Definition sync.hh:488
Classes for synchronizing among multiple CPUs, particularly in the Linux kernel.