Click
Loading...
Searching...
No Matches
ring.hh
1// -*- c-basic-offset: 4 -*-
2#ifndef CLICK_RING_HH
3#define CLICK_RING_HH
4
5#include <click/atomic.hh>
6#include <click/sync.hh>
7#if HAVE_DPDK
8# include <click/algorithm.hh>
9# include <rte_ring.h>
10# include <rte_errno.h>
11# include <click/dpdk_glue.hh>
12#endif
13#include <type_traits>
14
15CLICK_DECLS
16
17 template <typename T, size_t RING_SIZE> class BaseRing {
18
19 protected:
20
21 inline bool has_space() {
22 return head - tail < RING_SIZE;
23 }
24
25 inline bool is_empty() {
26 return head == tail;
27 }
28
29 public:
30 int id;
31 BaseRing() {
32 head = 0;
33 tail = 0;
34 }
35
36
37 inline T extract() {
38 if (!is_empty()) {
39 T &v = ring[tail % RING_SIZE];
40 tail++;
41 return v;
42 } else
43 return 0;
44 }
45
46 inline bool insert(T batch) {
47 if (has_space()) {
48 ring[head % RING_SIZE] = batch;
49 head++;
50 return true;
51 } else
52 return false;
53 }
54
55 inline unsigned int count() {
56 return head - tail;
57 }
58
59 T ring[RING_SIZE];
60 uint32_t head;
61 uint32_t tail;
62
63
64 inline void pool_transfer(unsigned int thread_from, unsigned int thread_to) {
65 (void)thread_from;
66 (void)thread_to;
67 }
68
69 inline void hint(unsigned int num, unsigned int thread_id) {
70 (void)num;
71 (void)thread_id;
72 }
73
74
75 };
76
77
83template <typename T> class SPSCDynamicRing {
84
85protected:
86 uint32_t _size;
87
88 inline uint32_t next_i(uint32_t i) {
89 if (i == _size -1)
90 return 0;
91 else
92 return i + 1;
93 }
94
95 inline void inc_i(uint32_t &i) {
96
97 if (i == _size -1 )
98 i = 0;
99 else
100 i++;
101 }
102
103 T* ring;
104public:
105 SPSCDynamicRing() : _size(0),ring(0) {
106 head = 0;
107 tail = 0;
108 }
109
111 if (_size)
112 delete[] ring;
113 }
114
115
116 inline T extract() {
117 if (!is_empty()) {
118 T &v = ring[tail];
119 inc_i(tail);
120 return v;
121 } else
122 return 0;
123 }
124
125 inline bool insert(T batch) {
126 if (!is_full()) {
127 ring[head] = batch;
128 inc_i(head);
129 return true;
130 } else
131 return false;
132 }
133
134 inline unsigned int count() {
135 int count = (int)head - (int)tail;
136 if (count < 0)
137 count += _size;
138 return count;
139 }
140
141 inline bool is_empty() {
142 return head == tail;
143 }
144
145 inline bool is_full() {
146 return next_i(head) == tail;
147 }
148
149
150 uint32_t head;
151 uint32_t tail;
152
153 inline bool initialized() {
154 return _size > 0;
155 }
156
157 inline void initialize(int size, const char* = 0) {
158 _size = size;
159 ring = new T[size];
160 }
161};
162
163template <typename T>
164using DynamicRing = SPSCDynamicRing<T>;
165
166#if HAVE_DPDK
170template <typename T> class MPMCDynamicRing {
171 protected:
172 rte_ring* _ring;
173 public:
174 MPMCDynamicRing() : _ring(0) {
175 static_assert(std::is_pointer<T>(), "MPMCDynamicRing can only be used with pointers");
176 }
177
178 inline void initialize(int size, const char* name, int flags = 0) {
179 assert(!_ring);
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));
184 }
185 }
186
187 inline bool insert(T o) {
188 return rte_ring_mp_enqueue(_ring, (void*)o) == 0;
189 }
190
191 inline T extract() {
192 T o;
193
194#if RTE_VERSION >= RTE_VERSION_NUM(17,5,0,0)
195 if (rte_ring_mc_dequeue_bulk(_ring, (void**)&o, 1, 0) == 0)
196#else
197 if (rte_ring_mc_dequeue_bulk(_ring, (void**)&o, 1) == 0)
198#endif
199 return 0;
200 else
201 return o;
202 }
203
204
205 inline bool is_empty() {
206 return rte_ring_empty(_ring);
207 }
208
209 inline bool is_full() {
210 return rte_ring_full(_ring);
211 }
212
213
215 rte_ring_free(_ring);
216 }
217};
218
219
220template <typename T> class MPSCDynamicRing : public MPMCDynamicRing<T> {
221 public:
222
223 inline void initialize(int size, const char* name) {
224 MPMCDynamicRing<T>::initialize(size, name, RING_F_SC_DEQ);
225 }
226
227 inline T extract() {
228 T o;
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)
231#else
232 if (rte_ring_sc_dequeue_bulk(this->_ring, (void**)&o, 1) == 0)
233#endif
234 return 0;
235 else
236 return o;
237 }
238};
239#else
245template <typename T> class MPMCDynamicRing : public SPSCDynamicRing<T> {
246 Spinlock _lock;
247
248public:
249
250 MPMCDynamicRing() : _lock() {
251
252 }
253
254 inline T extract() {
255 _lock.acquire();
257 _lock.release();
258 return v;
259 }
260
261 inline bool insert(T v) {
262 _lock.acquire();
264 _lock.release();
265 return r;
266 }
267
268};
269template <typename T> class MPSCDynamicRing : public MPMCDynamicRing<T> {};
270
271#endif
272
273
274template <typename T, size_t RING_SIZE> class Ring : public BaseRing<T,RING_SIZE> {};
275
276template <typename T> class CircleList {
277public:
278 CircleList() : _data(0), _maxsize(0),_size(0),_cur(0) {
279
280 }
281
282 CircleList(unsigned int max_size) : _data(0), _maxsize(max_size),_size(0),_cur(0) {
283
284 }
285
286 inline T& get() {
287 return _data[_cur % _size];
288 }
289
290 inline T& next() {
291 return _data[++_cur % _size];
292 }
293
294 inline void advance() {
295 ++_cur;
296 }
297
298 void append(T v) {
299 assert(_size < _maxsize);
300 if (!_data)
301 _data = new T[_maxsize];
302 _data[_size++] = v;
303 }
304
305 unsigned int size() {
306 return _size;
307 }
308
309 inline T& begin() {
310 return _data[0];
311 }
312
313 inline bool is_empty() {
314 return _size == 0;
315 }
316 private :
317 T* _data;
318 unsigned int _size;
319 unsigned int _maxsize;
320 unsigned int _cur;
321};
322
323#define SPSCRing Ring
324
325template <typename T, size_t MAX_SIZE> class MPMCLIFO {
326private:
327 SimpleSpinlock _lock;
328
329protected:
330
331 inline bool has_space() {
332 return _count < MAX_SIZE;
333 }
334
335 inline bool is_empty() {
336 return _first == 0;
337 }
338
339public:
340 int id;
341 T _first;
342 unsigned int _count;
343
344 MPMCLIFO() : _lock(), id(0),_first(0),_count(0) {
345
346 }
347
348
349 inline T extract() {
350 _lock.acquire();
351 if (is_empty()) {
352 _lock.release();
353 return 0;
354 }
355 T tmp = _first;
356 _first = _first->prev();
357 _count--;
358 _lock.release();
359 return tmp;
360 }
361
362 inline bool insert(T v) {
363 _lock.acquire();
364 if (!has_space()) {
365 _lock.release();
366 return false;
367 }
368 v->set_prev(_first);
369 _first = v;
370 _count++;
371 _lock.release();
372 return true;
373 }
374
375 inline unsigned int count() {
376 return _count;
377 }
378
379
380 inline void pool_transfer(unsigned int thread_from, unsigned int thread_to) {
381 (void)thread_from;
382 (void)thread_to;
383 }
384
385 inline void hint(unsigned int num, unsigned int thread_id) {
386 (void)num;
387 (void)thread_id;
388 }
389};
390
391
392template <typename T, size_t RING_SIZE> class MPMCRing : public SPSCRing<T, RING_SIZE> {
393 Spinlock _lock;
394
395
396public:
397 inline void acquire() {
398 _lock.acquire();
399 }
400
401 inline void release() {
402 _lock.release();
403 }
404
405 inline void release_tail() {
406 release();
407 }
408
409 inline void release_head() {
410 release();
411 }
412
413 inline void acquire_tail() {
414 acquire();
415 }
416
417 inline void acquire_head() {
418 acquire();
419 }
420
421public:
422
423 MPMCRing() : _lock() {
424
425 }
426
427 inline bool insert(T batch) {
428 acquire_head();
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++;
432 release_head();
433 return true;
434 } else {
435 release_head();
436 return false;
437 }
438 }
439
440 inline T extract() {
441 acquire_tail();
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++;
445 release_tail();
446 return v;
447 } else {
448 release_tail();
449 return 0;
450 }
451 }
452};
453
454template <typename T, size_t RING_SIZE> class SMPMCRing : public SPSCRing<T, RING_SIZE> {
455 SimpleSpinlock _lock_head;
456 SimpleSpinlock _lock_tail;
457
458 inline void release_tail() {
459 _lock_tail.release();
460 }
461
462 inline void release_head() {
463 _lock_head.release();
464 }
465
466 inline void acquire_tail() {
467 _lock_tail.acquire();
468 }
469
470 inline void acquire_head() {
471 _lock_head.acquire();
472 }
473public:
474 inline bool insert(T batch) {
475 acquire_head();
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++;
479 release_head();
480 click_compiler_fence();
481 return true;
482 } else {
483 release_head();
484 click_compiler_fence();
485 return false;
486 }
487 }
488
489 inline T extract() {
490 acquire_tail();
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++;
494 release_tail();
495 click_compiler_fence();
496 return v;
497 } else {
498 release_tail();
499 click_compiler_fence();
500 return 0;
501 }
502 }
503
504};
505
506template <typename T, size_t RING_SIZE> class MPSCRing : public SPSCRing<T, RING_SIZE> {
507 SimpleSpinlock _lock_head;
508
509 inline void release_head() {
510 _lock_head.release();
511 }
512
513 inline void acquire_head() {
514 _lock_head.acquire();
515 }
516public:
517
518 inline bool insert(T batch) {
519 acquire_head();
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++;
523 release_head();
524 return true;
525 } else {
526 release_head();
527 return false;
528 }
529 }
530};
531
532CLICK_ENDDECLS
533#endif
An atomic 32-bit integer.
Definition ring.hh:245
Definition ring.hh:83
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.