Click
Loading...
Searching...
No Matches
sync.hh
Go to the documentation of this file.
1// -*- c-basic-offset: 4 -*-
2#ifndef CLICK_SYNC_HH
3#define CLICK_SYNC_HH
4#include <click/machine.hh>
5#include <click/glue.hh>
6#include <click/atomic.hh>
7#if CLICK_LINUXMODULE || (CLICK_USERLEVEL && HAVE_MULTITHREAD)
8# define CLICK_MULTITHREAD_SPINLOCK 1
9#endif
10#if CLICK_USERLEVEL && !NDEBUG
11# define SPINLOCK_ASSERTLEVEL "<-999>"
12#else
13# define SPINLOCK_ASSERTLEVEL "<1>"
14#endif
15CLICK_DECLS
16
17
55template <typename T>
57{
58private:
59 struct A_t{
60 T v;
61 } CLICK_CACHE_ALIGN;
62
63 typedef struct A_t AT;
64
65 void initialize(unsigned int n, T v) {
66 _size = n;
67 storage = CLICK_ALIGNED_NEW(AT,_size);
68 for (unsigned i = 0; i < n; i++) {
69 storage[i].v = v;
70 }
71 }
72
73 //Disable copy constructor. It will always be a user error
74 per_thread (const per_thread<T> &);
75public:
76 explicit per_thread() {
77 _size = click_max_cpu_ids();
78 storage = CLICK_ALIGNED_NEW(AT,_size);
79 for (unsigned i = 0; i < _size; i++) {
80 new (&storage[i].v) T;
81 }
82 }
83
84 explicit per_thread(T v) {
85 initialize(click_max_cpu_ids(),v);
86 }
87
88 explicit per_thread(T v, int n) {
89 initialize(n,v);
90 }
91
97 void resize(unsigned int max_cpu_id, T v) {
98 CLICK_ALIGNED_DELETE(storage, AT, _size);
99 initialize(max_cpu_id,v);
100 }
101
102 ~per_thread() {
103 if (_size) {
104 CLICK_ALIGNED_DELETE(storage,AT,_size);
105 _size = 0;
106 }
107 }
108
109 inline T* operator->() const {
110 return &(storage[click_current_cpu_id()].v);
111 }
112 inline T& operator*() const {
113 return storage[click_current_cpu_id()].v;
114 }
115
116 inline T& operator+=(const T& add) const {
117 storage[click_current_cpu_id()].v += add;
118 return storage[click_current_cpu_id()].v;
119 }
120
121 inline T& operator++() const { // prefix ++
122 return ++(storage[click_current_cpu_id()].v);
123 }
124
125 inline T operator++(int) const { // postfix ++
126 return storage[click_current_cpu_id()].v++;
127 }
128
129 inline T& operator--() const {
130 return --(storage[click_current_cpu_id()].v);
131 }
132
133 inline T operator--(int) const {
134 return storage[click_current_cpu_id()].v--;
135 }
136
137 inline T& operator=(T value) const {
138 storage[click_current_cpu_id()].v = value;
139 return storage[click_current_cpu_id()].v;
140 }
141
142 inline void operator=(const per_thread<T>& pt) {
143 if (_size != pt._size) {
144 if (storage)
145 CLICK_ALIGNED_DELETE(storage,AT, _size);
146 storage = CLICK_ALIGNED_NEW(AT, _size);
147 }
148 for (int i = 0; i < pt.weight(); i++) {
149 storage[i] = pt.storage[i];
150 }
151 }
152
153 inline void set(T v) {
154 storage[click_current_cpu_id()].v = v;
155 }
156
157 inline void setAll(T v) {
158 for (int i = 0; i < click_max_cpu_ids(); i++)
159 storage[i].v = v;
160 }
161
162 inline T& get() const{
163 return storage[click_current_cpu_id()].v;
164 }
165
166 inline const T& cst() const{
167 return storage[click_current_cpu_id()].v;
168 }
169
176 inline T& get_value_for_thread(int thread_id) const{
177 return storage[thread_id].v;
178 }
179
180 inline void set_value_for_thread(int thread_id, T v) {
181 storage[thread_id].v = v;
182 }
183
190 inline T& get_value(int i) const {
191 return get_value_for_thread(i);
192 }
193
194 inline void set_value(int i, T v) {
195 set_value_for_thread(i, v);
196 }
197
203 inline unsigned weight() const {
204 return _size;
205 }
206
207 inline unsigned int get_mapping(int i) {
208 return i;
209 }
210
211 class const_iterator {public:
212 const_iterator(const per_thread<T>* t,unsigned pos) {
213 _t = t;
214 _pos = pos;
215 }
216 const per_thread<T>* _t;
217 unsigned _pos;
218 T& operator*() const {
219 return _t->get_value(_pos);
220 }
221 bool operator!=(const const_iterator &o) const {
222 return _pos != o._pos;
223 }
224 void operator++() {
225 _pos++;
226 }
227 };
228
229 const_iterator begin() const {
230 return const_iterator(this,0);
231 }
232
233 const_iterator end() const {
234 return const_iterator(this,_size);
235 }
236
237 class iterator {public:
238 iterator(per_thread<T>* t,unsigned pos) {
239 _t = t;
240 _pos = pos;
241 }
242 const per_thread<T>* _t;
243 unsigned _pos;
244 T& operator*() const {
245 return _t->get_value(_pos);
246 }
247 bool operator!=(const iterator &o) const {
248 return _pos != o._pos;
249 }
250 void operator++() {
251 _pos++;
252 }
253 };
254
255 iterator begin() {
256 return iterator(this,0);
257 }
258
259 iterator end() {
260 return iterator(this,_size);
261 }
262protected:
263 AT* storage;
264 unsigned _size;
265};
266
271template <typename T>
273{
274public:
275 explicit not_per_thread() {
276 }
277
278 explicit not_per_thread(T _v) {
279 v = _v;
280 }
281
282 inline T* operator->() {
283 return &(v);
284 }
285
286
287 inline T& operator*() {
288 return v;
289 }
290
291 inline T& get() {
292 return v;
293 }
294
295 inline const T& cst() const {
296 return v;
297 }
298
299 inline constexpr int weight() const {
300 return 1;
301 }
302
303 inline T& get_value(int) {
304 return v;
305 }
306
307 class const_iterator {public:
308 const_iterator(const not_per_thread<T>* t,unsigned pos) {
309 _t = t;
310 _pos = pos;
311 }
312 const not_per_thread<T>* _t;
313 unsigned _pos;
314 const T& operator*() const {
315 return _t->v;
316 }
317 bool operator!=(const const_iterator &o) const {
318 return _pos != o._pos;
319 }
320 void operator++() {
321 _pos++;
322 }
323 };
324
325 const_iterator begin() const {
326 return const_iterator(this,0);
327 }
328
329 const_iterator end() const {
330 return const_iterator(this, 1);
331 }
332
333 class iterator {public:
334 iterator(not_per_thread<T>* t,unsigned pos) {
335 _t = t;
336 _pos = pos;
337 }
339 unsigned _pos;
340 T& operator*() const {
341 return _t->v;
342 }
343 bool operator!=(const iterator &o) const {
344 return _pos != o._pos;
345 }
346 void operator++() {
347 _pos++;
348 }
349 };
350
351 iterator begin() {
352 return iterator(this,0);
353 }
354
355 iterator end() {
356 return iterator(this, 1);
357 }
358private:
359 T v;
360};
361
362
363#define PER_THREAD_SET(pt,value) \
364 for (unsigned i = 0; i < pt.weight(); i++) { \
365 pt.set_value(i, value); \
366 }
367
368#define PER_THREAD_POINTER_SET(pt,member,value) \
369 for (unsigned i = 0; i < pt.weight(); i++) { \
370 pt.get_value(i)->member = value; \
371 }
372
373#define PER_THREAD_MEMBER_SET(pt,member,value) \
374 for (unsigned i = 0; i < pt.weight(); i++) { \
375 pt.get_value(i).member = value; \
376 }
377
378#define PER_THREAD_VECTOR_SET(pt,member,value) \
379 for (unsigned i = 0; i < pt.weight(); i++) { \
380 for (int j = 0; j < pt.get_value(i).size(); j++) \
381 (pt.get_value(i))[j].member = value; \
382 }
383
384#define PER_THREAD_SUM(type, var, pt) \
385 type var = 0; \
386 for (unsigned i = 0; i < pt.weight(); i++) { \
387 var += pt.get_value(i); \
388 }
389
390#define PER_THREAD_POINTER_SUM(type, var, pt, member) \
391 type var = 0; \
392 for (unsigned i = 0; i < pt.weight(); i++) { \
393 var += pt.get_value(i)->member; \
394 }
395
396#define PER_THREAD_MEMBER_SUM(type, var, pt, member) \
397 type var = 0; \
398 for (unsigned i = 0; i < pt.weight(); i++) { \
399 var += pt.get_value(i).member; \
400 }
401
402#define PER_THREAD_VECTOR_SUM(type, var, pt, index, member) \
403 type var = 0; \
404 for (unsigned i = 0; i < pt.weight(); i++) { \
405 var += pt.get_value(i)[index].member; \
406 }
407
408
409
439class Spinlock { public:
440
441 inline Spinlock();
442 inline ~Spinlock();
443
444 inline void acquire();
445 inline void release();
446 inline bool attempt();
447 inline bool nested() const;
448
449#if CLICK_MULTITHREAD_SPINLOCK
450 private:
451
452 atomic_uint32_t _lock;
453 int32_t _depth;
454 click_processor_t _owner;
455#endif
456
457};
458
460inline
462#if CLICK_MULTITHREAD_SPINLOCK
463 : _depth(0), _owner(click_invalid_processor())
464#endif
465{
466#if CLICK_MULTITHREAD_SPINLOCK
467 _lock = 0;
468#endif
469}
470
471inline
472Spinlock::~Spinlock()
473{
474#if CLICK_MULTITHREAD_SPINLOCK
475 if (_depth != 0)
476 click_chatter(SPINLOCK_ASSERTLEVEL "Spinlock::~Spinlock(): assertion \"_depth == 0\" failed");
477#endif
478}
479
487inline void
489{
490#if CLICK_MULTITHREAD_SPINLOCK
491 click_processor_t my_cpu = click_get_processor();
492 if (_owner != my_cpu) {
493 while (_lock.swap(1) != 0)
494 do {
495 click_relax_fence();
496 } while (_lock != 0);
497 _owner = my_cpu;
498 }
499 _depth++;
500#endif
501}
502
509inline bool
511{
512#if CLICK_MULTITHREAD_SPINLOCK
513 click_processor_t my_cpu = click_get_processor();
514 if (_owner != my_cpu) {
515 if (_lock.swap(1) != 0) {
516 click_put_processor();
517 return false;
518 }
519 _owner = my_cpu;
520 }
521 _depth++;
522 return true;
523#else
524 return true;
525#endif
526}
527
533inline void
535{
536#if CLICK_MULTITHREAD_SPINLOCK
537 if (unlikely(_owner != click_current_processor()))
538 click_chatter(SPINLOCK_ASSERTLEVEL "Spinlock::release(): assertion \"owner == click_current_processor()\" failed");
539 if (likely(_depth > 0)) {
540 if (--_depth == 0) {
541 _owner = click_invalid_processor();
542 _lock = 0;
543 }
544 } else
545 click_chatter(SPINLOCK_ASSERTLEVEL "Spinlock::release(): assertion \"_depth > 0\" failed");
546 click_put_processor();
547#endif
548}
549
553inline bool
555{
556#if CLICK_MULTITHREAD_SPINLOCK
557 return _depth > 1;
558#else
559 return false;
560#endif
561}
562
563
587class SimpleSpinlock { public:
588
589 inline SimpleSpinlock();
590 inline ~SimpleSpinlock();
591
592 inline void acquire();
593 inline void release();
594 inline bool attempt();
595
596#if CLICK_LINUXMODULE
597 private:
598 spinlock_t _lock;
599#elif CLICK_MULTITHREAD_SPINLOCK
600 private:
601 atomic_uint32_t _lock;
602#endif
603
604};
605
607inline
609{
610#if CLICK_LINUXMODULE
611 spin_lock_init(&_lock);
612#elif CLICK_MULTITHREAD_SPINLOCK
613 _lock = 0;
614#endif
615}
616
617inline
618SimpleSpinlock::~SimpleSpinlock()
619{
620}
621
627inline void
629{
630#if CLICK_LINUXMODULE
631 spin_lock(&_lock);
632#elif CLICK_MULTITHREAD_SPINLOCK
633 while (_lock.swap(1) != 0) {
634 do {
635 click_relax_fence();
636 } while (_lock != 0);
637 }
638#endif
639}
640
647inline bool
649{
650#if CLICK_LINUXMODULE
651 return spin_trylock(&_lock);
652#elif CLICK_MULTITHREAD_SPINLOCK
653 return _lock.swap(1) == 0;
654#else
655 return true;
656#endif
657}
658
664inline void
666{
667#if CLICK_LINUXMODULE
668 spin_unlock(&_lock);
669#elif CLICK_MULTITHREAD_SPINLOCK
670 _lock = 0;
671#endif
672}
673
674
697class SpinlockIRQ { public:
698
699 inline SpinlockIRQ();
700
701#if CLICK_LINUXMODULE
702 typedef unsigned long flags_t;
703#else
704 typedef int flags_t;
705#endif
706
707 inline flags_t acquire() CLICK_ALWAYS_INLINE;
708 inline void release(flags_t) CLICK_ALWAYS_INLINE;
709
710#if CLICK_LINUXMODULE
711 private:
712 spinlock_t _lock;
713#elif CLICK_USERLEVEL && HAVE_MULTITHREAD
714 private:
715 Spinlock _lock;
716#endif
717
718};
719
721inline
723{
724#if CLICK_LINUXMODULE
725 spin_lock_init(&_lock);
726#endif
727}
728
732inline SpinlockIRQ::flags_t
734{
735#if CLICK_LINUXMODULE
736 flags_t flags;
737 spin_lock_irqsave(&_lock, flags);
738 return flags;
739#elif CLICK_USERLEVEL && HAVE_MULTITHREAD
740 _lock.acquire();
741 return 0;
742#else
743 return 0;
744#endif
745}
746
750inline void
752{
753#if CLICK_LINUXMODULE
754 spin_unlock_irqrestore(&_lock, flags);
755#elif CLICK_USERLEVEL && HAVE_MULTITHREAD
756 (void) flags;
757 _lock.release();
758#else
759 (void) flags;
760#endif
761}
762
763
764// read-write lock
765//
766// on read: acquire local read lock
767// on write: acquire every read lock
768//
769// alternatively, we could use a read counter and a write lock. we don't do
770// that because we'd like to avoid a cache miss for read acquires. this makes
771// reads very fast, and writes more expensive
772
800class ReadWriteLock { public:
801
802 inline ReadWriteLock();
803 inline ~ReadWriteLock();
804
805 inline void acquire_read();
806 inline bool attempt_read();
807 inline void release_read();
808 inline void acquire_write();
809 inline bool attempt_write();
810 inline void release_write();
811
812 private:
813 // allocate a cache line for every member
815
816};
817
819inline
823
824inline
825ReadWriteLock::~ReadWriteLock()
826{
827}
828
838inline void
840{
841#if HAVE_MULTITHREAD
842 _l->acquire();
843#endif
844}
845
852inline bool
854{
855#if HAVE_MULTITHREAD
856 bool result = _l->attempt();
857 if (!result)
858 click_put_processor();
859 return result;
860#else
861 return true;
862#endif
863}
864
871inline void
873{
874#if HAVE_MULTITHREAD
875 _l->release();
876 click_put_processor();
877#endif
878}
879
889inline void
891{
892#if HAVE_MULTITHREAD
893 for (unsigned i = 0; i < _l.weight(); i++)
894 _l.get_value(i).acquire();
895#endif
896}
897
908inline bool
910{
911#if HAVE_MULTITHREAD
912 bool all = true;
913 unsigned i;
914 for (i = 0; i < (unsigned) _l.weight(); i++) {
915 if (!(_l.get_value(i).attempt())) {
916 all = false;
917 break;
918 }
919 }
920 if (!all) {
921 for (unsigned j = 0; j < i; j++)
922 _l.get_value(j).release();
923 }
924 return all;
925#else
926 return true;
927#endif
928}
929
938inline void
940{
941#if HAVE_MULTITHREAD
942 for (unsigned i = 0; i < _l.weight(); i++)
943 _l.get_value(i).release();
944#endif
945}
946
952class nolock { public:
953 nolock() {}
954
955 inline void acquire() {};
956
957 inline void release() {};
958
959 inline bool attempt() { return true; };
960
961 inline void read_begin() {}
962
963 inline void read_end() {}
964
965 inline void read_get() {}
966
967 inline void write_begin() {}
968
969 inline void write_end() {}
970
971 inline void set_max_writers(int) {}
972};
973
974CLICK_ENDDECLS
975#undef SPINLOCK_ASSERTLEVEL
976#endif
An atomic 32-bit integer.
A read/write lock.
Definition sync.hh:800
void release_write()
Releases the ReadWriteLock for writing.
Definition sync.hh:939
ReadWriteLock()
Creates a ReadWriteLock.
Definition sync.hh:820
bool attempt_read()
Attempts to acquire the ReadWriteLock for reading.
Definition sync.hh:853
void release_read()
Releases the ReadWriteLock for reading.
Definition sync.hh:872
void acquire_write()
Acquires the ReadWriteLock for writing.
Definition sync.hh:890
bool attempt_write()
Attempts to acquire the ReadWriteLock for writing.
Definition sync.hh:909
void acquire_read()
Acquires the ReadWriteLock for reading.
Definition sync.hh:839
A non-recursive spinlock for SMP Click threads.
Definition sync.hh:587
bool attempt()
Attempts to acquire the SimpleSpinlock.
Definition sync.hh:648
void release()
Releases the SimpleSpinlock.
Definition sync.hh:665
SimpleSpinlock()
Create a SimpleSpinlock.
Definition sync.hh:608
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
bool attempt()
Attempts to acquire the Spinlock.
Definition sync.hh:510
void acquire()
Acquires the Spinlock.
Definition sync.hh:488
Spinlock()
Create a Spinlock.
Definition sync.hh:461
bool nested() const
Returns true iff the Spinlock has been acquired more than once by the current thread.
Definition sync.hh:554
A spinlock that disables interrupts.
Definition sync.hh:697
flags_t acquire() CLICK_ALWAYS_INLINE
Acquires the SpinlockIRQ.
Definition sync.hh:733
void release(flags_t) CLICK_ALWAYS_INLINE
Releases the SpinlockIRQ.
Definition sync.hh:751
SpinlockIRQ()
Creates a SpinlockIRQ.
Definition sync.hh:722
A 32-bit integer with support for atomic operations.
Definition atomic.hh:71
Definition sync.hh:952
Definition sync.hh:273
Definition sync.hh:57
unsigned weight() const
Definition sync.hh:203
void resize(unsigned int max_cpu_id, T v)
Definition sync.hh:97
T & get_value_for_thread(int thread_id) const
Definition sync.hh:176
T & get_value(int i) const
Definition sync.hh:190
Timestamp operator*(const Timestamp &a, double b)
Scale a by a factor of b and return the result.
Definition timestamp.hh:1447