2#ifndef CLICK_MULTITHREAD_HH
3#define CLICK_MULTITHREAD_HH
5#include <click/config.h>
6#include <click/glue.hh>
9#include <click/machine.hh>
13# error This file is not meant for Kernel mode
26class per_thread_oread :
public per_thread<T> {
public:
30 for (
int i = 0; i < usable.
size(); i++) {
39 inline bool initialized() {
40 return mapping.size() > 0;
47 inline void set_value(
int i, T v) {
51 inline int get_mapping(
int index) {
52 return mapping[index];
68class per_thread_omem {
private:
71 } CLICK_CACHE_ALIGN AT;
78 per_thread_omem() : storage(0),mapping(),_size(0) {
87 void initialize(
Bitvector usable, T v=T()) {
89 storage =
new AT[_size];
90 mapping.
resize(click_max_cpu_ids(), 0);
92 for (
unsigned i = 0; i < click_max_cpu_ids(); i++) {
100 inline T* operator->()
const {
101 return &(storage[mapping[click_current_cpu_id()]].v);
104 return storage[mapping[click_current_cpu_id()]].v;
107 inline T& operator+=(
const T& add)
const {
108 storage[mapping[click_current_cpu_id()]].v += add;
109 return storage[mapping[click_current_cpu_id()]].v;
112 inline T& operator++()
const {
113 return ++(storage[mapping[click_current_cpu_id()]].v);
116 inline T operator++(
int)
const {
117 return storage[mapping[click_current_cpu_id()]].v++;
120 inline T& operator--()
const {
121 return --(storage[mapping[click_current_cpu_id()]].v);
124 inline T operator--(
int)
const {
125 return storage[mapping[click_current_cpu_id()]].v--;
128 inline T& operator=(T value)
const {
130 return storage[mapping[click_current_cpu_id()]].v;
133 inline void set(T v) {
134 storage[mapping[click_current_cpu_id()]].v = v;
137 inline void setAll(T v) {
138 for (
int i = 0; i < weight(); i++)
142 inline T& get()
const{
143 return storage[mapping[click_current_cpu_id()]].v;
146 inline T& get_value_for_thread(
int thread_id)
const{
147 return storage[mapping[thread_id]].v;
150 inline void set_value_for_thread(
int thread_id, T v) {
151 storage[mapping[thread_id]].v = v;
154 inline T& get_value(
int i)
const {
158 inline void set_value(
int i, T v) {
162 inline unsigned weight()
const {
174 static int sum(
int i) {
178 static unsigned usum(
unsigned i) {
183 PER_THREAD_SUM(
unsigned, s, v);
188 PER_THREAD_SUM(
unsigned, s, v);
192 static void set(
int &i,
int v) {
196 static void uset(
unsigned &i,
unsigned v) {
201 PER_THREAD_SET(pt , v);
205 PER_THREAD_SET(pt , v);
209 static int64_t sum_long(int64_t i) {
213 static uint64_t usum_long(uint64_t i) {
217 static void set_long(int64_t &i, int64_t v) {
221 static void uset_long(uint64_t &i, uint64_t v) {
226 PER_THREAD_SUM(int64_t, s, v);
231 PER_THREAD_SUM(uint64_t, s, v);
236 PER_THREAD_SET(pt, v);
240 PER_THREAD_SET(pt, v);
283template <
typename T,
int N>
290 storage[rcu_current] = v;
296 inline void initialize(T v) {
297 storage[rcu_current] = v;
300 inline const T& read_begin() {
301 return storage[rcu_current];
304 inline void read_end() {
308 inline const T& read()
const {
309 return storage[rcu_current];
312 inline const T operator*()
const {
316 inline const T* operator->()
const {
320 inline T& write_begin() {
321 int rcu_next = (rcu_current + 1) & (N - 1);
322 storage[rcu_next] = storage[rcu_current];
323 return storage[rcu_next];
326 inline void write_commit() {
328 rcu_current = (rcu_current + 1) & (N - 1);
331 inline void write_abort() {
334 inline const T& read_begin(
int) {
338 inline void read_end(
int) {
344 volatile int rcu_current;
359template <
typename T,
int N>
366 inline T& write_begin() {
371 inline void write_commit() {
376 inline void write_abort() {
401 inline ptr() : _v(0) {};
402 inline ptr(
shared<T>* v) : _v(v) {_v->get();}
407 inline T* operator->() {
419 inline ptr(
const ptr &o) {
424 inline uint32_t refcnt() {
434 inline void assign_release(ptr &o) {
440 inline void operator=(
const ptr &o) {
447 inline void release() {
453 inline operator bool()
const {
462 typedef ptr write_ptr;
464 inline ptr operator->() {
473 return write_ptr(
this);
477 inline void get(ptr &o) {
485 inline bool unshared() {
489 inline bool write_held() {
493 inline bool hasref() {
497 T* unprotected_ptr() {
528 inline ptr() : _v(0) {};
534 inline T* operator->() {
546 inline ptr(
const ptr &o) {
558 inline void assign_release(ptr &o) {
564 inline void operator=(
const ptr &o) {
571 inline void release() {
577 inline operator bool()
const {
586 typedef ptr write_ptr;
588 inline ptr operator->() {
597 return write_ptr(
this);
601 inline void get(ptr &o) {
605 T* unprotected_ptr() {
609 inline bool unshared() {
613 inline bool write_held() {
617 inline bool hasref() {
657 uint32_t current_refcnt;
659 current_refcnt = _refcnt;
660#if ! CLICK_ATOMIC_COMPARE_SWAP
661 }
while ((int32_t)current_refcnt < 0 || (!_refcnt.
compare_and_swap(current_refcnt,current_refcnt+1)));
663 }
while ((int32_t)current_refcnt < 0 || (_refcnt.compare_swap(current_refcnt,current_refcnt+1) != current_refcnt));
691#if ! CLICK_ATOMIC_COMPARE_SWAP
692 while (!_refcnt.compare_and_swap(0,-1)) click_relax_fence();
694 while (_refcnt.compare_swap(0,-1) != 0) click_relax_fence();
702#if ! CLICK_ATOMIC_COMPARE_SWAP
703 return (_refcnt.compare_and_swap(0,-1));
705 return (_refcnt.compare_swap(0,-1) == 0);
731 assert(_refcnt == (uint32_t)-1);
762 inline bool read_to_write() CLICK_WARN_UNUSED_RESULT;
764 inline uint32_t refcnt() {
815 set_max_writers(max_writers);
818 void set_max_writers(int32_t max_writers) {
819 assert(max_writers < 65535);
821 max_write = - max_writers;
825 inline void read_begin() {
826 uint32_t current_refcnt;
828 current_refcnt = _refcnt;
829 if (unlikely((int32_t)current_refcnt < 0)) {
830 if ((int32_t)current_refcnt <= -65536) {
833#if ! CLICK_ATOMIC_COMPARE_SWAP
836 if (_refcnt.compare_swap(current_refcnt,current_refcnt - 65536) == current_refcnt) {
841 }
while((int32_t)_refcnt != -65536);
848#if ! CLICK_ATOMIC_COMPARE_SWAP
851 if (likely(_refcnt.compare_swap(current_refcnt,current_refcnt+1) == current_refcnt))
859 inline void read_end() {
864 inline void read_get() {
868 inline void write_begin() {
869 uint32_t current_refcnt;
871 current_refcnt = _refcnt;
872 if (likely((int32_t)current_refcnt <= 0 && (int32_t)current_refcnt > max_write)) {
873#if ! CLICK_ATOMIC_COMPARE_SWAP
876 if (_refcnt.compare_swap(current_refcnt,current_refcnt - 1) == current_refcnt)
884 inline void write_end() {
913 set_max_writers(max_writers);
916 void set_max_writers(int32_t max_writers) {
917 assert(max_writers < 65535);
919 max_write = - max_writers;
923 inline void write_begin() {
924 uint32_t current_refcnt;
926 current_refcnt = _refcnt;
927 if (unlikely((int32_t)current_refcnt < 0)) {
928 if ((int32_t)current_refcnt <= -65536) {
931#if ! CLICK_ATOMIC_COMPARE_SWAP
932 if (_refcnt.compare_and_swap(current_refcnt,current_refcnt - 65536)) {
934 if (_refcnt.compare_swap(current_refcnt,current_refcnt - 65536) == current_refcnt) {
939 }
while((int32_t)_refcnt != -65536);
946#if ! CLICK_ATOMIC_COMPARE_SWAP
947 if (likely(_refcnt.compare_and_swap(current_refcnt,current_refcnt+1)))
949 if (likely(_refcnt.compare_swap(current_refcnt,current_refcnt+1) == current_refcnt))
957 inline void write_end() {
962 inline void write_get() {
966 inline void read_begin() {
967 uint32_t current_refcnt;
969 current_refcnt = _refcnt;
970 if (likely((int32_t)current_refcnt <= 0 && (int32_t)current_refcnt > max_write)) {
971#if ! CLICK_ATOMIC_COMPARE_SWAP
972 if (_refcnt.compare_and_swap(current_refcnt,current_refcnt - 1))
974 if (_refcnt.compare_swap(current_refcnt,current_refcnt - 1) == current_refcnt)
982 inline void read_end() {
995class rXwlock {
public:
1000 inline void read_begin() {
1001 uint32_t current_refcnt;
1002 current_refcnt = _refcnt;
1003#if ! CLICK_ATOMIC_COMPARE_SWAP
1004 while ((int32_t)current_refcnt < 0 || !_refcnt.compare_and_swap(current_refcnt,current_refcnt+1)) {
1006 while ((int32_t)current_refcnt < 0 || _refcnt.compare_swap(current_refcnt,current_refcnt+1) != current_refcnt) {
1008 click_relax_fence();
1009 current_refcnt = _refcnt;
1013 void set_max_writers(int32_t max_writers) {
1019 inline void read_end() {
1024 inline void read_get() {
1028 inline void write_begin() {
1029 uint32_t current_refcnt;
1030 current_refcnt = _refcnt;
1031#if ! CLICK_ATOMIC_COMPARE_SWAP
1032 while ((int32_t)current_refcnt > 0 || !_refcnt.compare_and_swap(current_refcnt,current_refcnt-1)) {
1034 while ((int32_t)current_refcnt > 0 || _refcnt.compare_swap(current_refcnt,current_refcnt-1) != current_refcnt) {
1036 click_relax_fence();
1037 current_refcnt = _refcnt;
1041 inline void write_end() {
1042 click_write_fence();
1054template <
typename V>
1063 class ptr { public :
1080 const V* operator->()
const {
1088 void operator=(
const ptr &o) {
1095 inline uint32_t refcnt() {
1096 return _p->refcnt();
1109 inline operator bool()
const {
1122 class write_ptr { public :
1123 write_ptr(
const write_ptr &o) {
1148 void operator=(
const write_ptr &o) {
1158 return _p->refcnt();
1175 inline void assign_release(write_ptr& o) {
1181 inline operator bool()
const {
1185 write_ptr() : _p(0) {};
1201 return write_ptr(&_v);
1214 if (_v.read_to_write()) {
1215 return write_ptr(_v);
1228 return const_ptr(_v);
1231 V* unprotected_ptr() {
1255 click_write_fence();
1258#if ! CLICK_ATOMIC_COMPARE_SWAP
1259 if (_refcnt.compare_and_swap(1,-1))
1261 if (_refcnt.compare_swap(1,-1) == 1)
1265 uint32_t current_refcnt;
1266 uint32_t new_refcnt;
1268 current_refcnt = _refcnt;
1269 new_refcnt = current_refcnt+1000000;
1270 if (current_refcnt > 1000000) {
1272 click_relax_fence();
1275#if ! CLICK_ATOMIC_COMPARE_SWAP
1276 }
while (!_refcnt.compare_and_swap(current_refcnt,new_refcnt));
1277 while (!_refcnt.compare_and_swap(1000001,-1)) click_relax_fence();
1279 }
while (_refcnt.compare_swap(current_refcnt,new_refcnt) != current_refcnt);
1280 while (_refcnt.compare_swap(1000001,-1) != 1000001) click_relax_fence();
1311template <
typename T>
1326 inline void initialize(T v) {
1327 storage[rcu_current] = v;
1349 uint32_t current_refcnt;
1351 rcu_current_local = rcu_current;
1353 current_refcnt = refcnt[rcu_current_local].value();
1354#if ! CLICK_ATOMIC_COMPARE_SWAP
1355 if (current_refcnt == (uint32_t)-1 || !(refcnt[rcu_current_local].compare_and_swap(current_refcnt,current_refcnt+1))) {
1357 if (current_refcnt == (uint32_t)-1 || (refcnt[rcu_current_local].compare_swap(current_refcnt,current_refcnt+1) != current_refcnt)) {
1359 click_relax_fence();
1364 click_write_fence();
1366 return storage[rcu_current_local];
1369 inline void read_end(
const int &rcu_current_local) {
1370 click_compiler_fence();
1371 refcnt[rcu_current_local]--;
1376 T v = read_begin(flags);
1391 rcu_next = (rcu_current + 1) & 1;
1392#if ! CLICK_ATOMIC_COMPARE_SWAP
1393 }
while (!refcnt[rcu_next].compare_and_swap(0,-1));
1395 }
while (refcnt[rcu_next].compare_swap(0,-1) != 0);
1400 if (rcu_next == rcu_current) {
1401 refcnt[rcu_next] = 0;
1406 storage[rcu_next] = storage[rcu_current];
1407 return storage[rcu_next];
1410 inline void write_commit() {
1411 int rcu_next = (rcu_current + 1) & 1;
1412 rcu_current = rcu_next;
1413 click_write_fence();
1414 refcnt[rcu_next] = 0;
1417 inline void write_abort() {
1420 click_write_fence();
1421 refcnt[(rcu_current + 1) & 1] = 0;
1424 inline void write(
const T &v) {
1432 volatile int rcu_current;
1439template <
typename T>
1442 fast_rcu() : _rcu_current(0), _epochs(0), _write_epoch(1) {
1445 fast_rcu(T v) : _rcu_current(0), _epochs(0), _write_epoch(1){
1451 inline void initialize(T v) {
1452 _storage[_rcu_current].v = v;
1455 inline const T& read_begin(
int &) {
1456 int w_epoch = _write_epoch;
1458 click_write_fence();
1459 int rcu_current_local = _rcu_current;
1462 return _storage[rcu_current_local].v;
1465 inline void read_end(
const int &) {
1466 click_compiler_fence();
1472 T v = read_begin(flags);
1477 inline T& write_begin(
int& rcu_current_local) {
1479 _write_lock.acquire();
1480 rcu_current_local = _rcu_current;
1482 int rcu_next = (rcu_current_local + 1) & (RCU_N - 1);
1483 int bad_epoch = (_write_epoch - RCU_N) + 1;
1487 for (; i < _epochs.weight(); i ++) {
1488 int te = _epochs.get_value(i);
1489 if (unlikely(te != 0 && te == bad_epoch)) {
1490 click_relax_fence();
1497 _storage[rcu_next].v = _storage[rcu_current_local].v;
1499 return _storage[rcu_next].v;
1502 inline void write_commit(
int rcu_current_local) {
1503 click_write_fence();
1504 _rcu_current = (rcu_current_local + 1) & 1;
1505 click_compiler_fence();
1507 _write_lock.release();
1514 } CLICK_CACHE_ALIGN AT;
1516 volatile int _rcu_current;
1519 volatile int _write_epoch;
Definition multithread.hh:778
Vector of bits.
Definition bitvector.hh:21
int weight() const
Return the number of true bits.
Definition bitvector.hh:394
int size() const
Return the number of bits in the bitvector.
Definition bitvector.hh:192
Definition multithread.hh:643
void write_end()
Definition multithread.hh:721
void write_begin()
Definition multithread.hh:690
void write_get()
Definition multithread.hh:714
void write_to_read()
Definition multithread.hh:729
bool read_to_write()
Definition multithread.hh:1243
void read_begin()
Definition multithread.hh:656
void read_get()
Definition multithread.hh:681
void read_end()
Definition multithread.hh:670
bool write_attempt()
Definition multithread.hh:701
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
Vector template.
Definition vector.hh:111
void resize(size_type n, value_argument_type v=T())
Resize the vector to contain n elements.
Definition vector.hh:390
A 32-bit integer with support for atomic operations.
Definition atomic.hh:71
bool compare_and_swap(uint32_t expected, uint32_t desired) CLICK_BUILTINS_NONDEPRECATED
Perform a compare-and-swap operation.
Definition atomic.hh:734
Definition multithread.hh:1312
const T & read_begin(int &rcu_current_local)
Definition multithread.hh:1348
T & write_begin()
Definition multithread.hh:1387
Definition multithread.hh:1440
Definition multithread.hh:519
Definition multithread.hh:172
void resize(unsigned int max_cpu_id, T v)
Definition sync.hh:97
T & get_value(int i) const
Definition sync.hh:190
Definition multithread.hh:808
Definition multithread.hh:906
Definition multithread.hh:1055
write_ptr read_to_write(const ptr &o)
Definition multithread.hh:1212
ptr write_to_read(const write_ptr &o)
Definition multithread.hh:1225
Definition multithread.hh:390
Definition multithread.hh:284
Definition multithread.hh:360
Classes for synchronizing among multiple CPUs, particularly in the Linux kernel.
Timestamp operator*(const Timestamp &a, double b)
Scale a by a factor of b and return the result.
Definition timestamp.hh:1447
Click's vector container template.