Click
Loading...
Searching...
No Matches
notifier.hh
Go to the documentation of this file.
1// -*- c-basic-offset: 4; related-file-name: "../../lib/notifier.cc" -*-
2#ifndef CLICK_NOTIFIER_HH
3#define CLICK_NOTIFIER_HH
4#include <click/task.hh>
5#include <click/atomic.hh>
6#include <click/algorithm.hh>
7#if HAVE_CXX_PRAGMA_INTERFACE
8# pragma interface "click/notifier.hh"
9#endif
10CLICK_DECLS
11
13 public:
14 typedef bool (NotifierSignal::*unspecified_bool_type)() const;
15
16 inline NotifierSignal();
17 inline NotifierSignal(atomic_uint32_t* value, uint32_t mask);
18 inline NotifierSignal(const NotifierSignal& x);
19 inline ~NotifierSignal();
20
21 static inline NotifierSignal idle_signal();
22 static inline NotifierSignal busy_signal();
23 static inline NotifierSignal overderived_signal();
25
26 inline bool active() const;
27 inline bool safe_active() const;
28 inline operator unspecified_bool_type() const;
29
30 inline bool set_active(bool active);
31
32 inline bool idle() const;
33 inline bool busy() const;
34 inline bool overderived() const;
35 inline bool initialized() const;
36
37 friend bool operator==(const NotifierSignal &a, const NotifierSignal &b);
38 friend bool operator!=(const NotifierSignal &a, const NotifierSignal &b);
39
43
44 inline void swap(NotifierSignal& x);
45
46 String unparse(Router *router) const;
47
48 static void static_initialize();
49
50 private:
51 struct vmpair {
52 atomic_uint32_t *value;
53 uint32_t mask;
54 };
55 union vmvalue {
57 vmpair *vm;
58 };
59
60 vmvalue _v;
61 uint32_t _mask;
62
63 enum {
64 true_mask = 1, false_mask = 2, overderived_mask = 4,
65 uninitialized_mask = 8
66 };
67 static atomic_uint32_t static_value;
68
69 void hard_assign_vm(const NotifierSignal &x);
70 void hard_derive_one(atomic_uint32_t *value, uint32_t mask);
71 static bool hard_equals(const vmpair *a, const vmpair *b);
72};
73
74class Notifier { public:
75
76 enum SearchOp { SEARCH_STOP = 0, SEARCH_CONTINUE, SEARCH_CONTINUE_WAKE };
77 typedef void (*callback_type)(void *, Notifier *);
78
79 inline Notifier(SearchOp op = SEARCH_STOP);
80 inline Notifier(const NotifierSignal &signal, SearchOp op = SEARCH_STOP);
81 virtual ~Notifier();
82
84 inline bool initialized() const {
85 return _signal.initialized();
86 }
87
88 int initialize(const char *name, Router *router);
89
90 inline const NotifierSignal &signal() const;
91 inline SearchOp search_op() const;
92
93 inline bool active() const;
94 inline bool safe_active() const;
95
96 inline bool set_active(bool active);
97 inline void wake();
98 inline void sleep();
99
100 virtual int add_activate_callback(callback_type f, void *user_data);
101 virtual void remove_activate_callback(callback_type f, void *user_data);
102 inline int add_listener(Task *task);
103 inline void remove_listener(Task *task);
106
107 static const char EMPTY_NOTIFIER[];
108 static const char FULL_NOTIFIER[];
109
110 static inline NotifierSignal upstream_empty_signal(Element *e, int port);
111 static inline NotifierSignal upstream_empty_signal(Element *e, int port, Task *task);
112 static inline NotifierSignal upstream_empty_signal(Element *e, int port, Notifier *dependent_notifier);
113 static inline NotifierSignal upstream_signal(Element *e, int port, Task *task, const char* signal);
114 static inline NotifierSignal upstream_empty_signal(Element *e, int port, callback_type f, void *user_data);
115 static NotifierSignal upstream_signal(Element *e, int port, callback_type f, void *user_data, const char* signal);
116
117 static inline NotifierSignal downstream_full_signal(Element *e, int port);
118 static inline NotifierSignal downstream_full_signal(Element *e, int port, Task *task);
119 static inline NotifierSignal downstream_full_signal(Element *e, int port, Notifier *dependent_notifier);
120 static NotifierSignal downstream_full_signal(Element *e, int port, callback_type f, void *user_data);
121
122 static inline NotifierSignal upstream_empty_signal(Element *e, int port, int) CLICK_DEPRECATED;
123 static inline NotifierSignal upstream_empty_signal(Element *e, int port, int, Notifier *) CLICK_DEPRECATED;
124 static inline NotifierSignal downstream_full_signal(Element *e, int port, int) CLICK_DEPRECATED;
125 static inline NotifierSignal downstream_full_signal(Element *e, int port, int, Notifier *) CLICK_DEPRECATED;
126
127 private:
128
129 NotifierSignal _signal;
130 SearchOp _search_op;
131
132 static void dependent_signal_callback(void *, Notifier *);
133
134};
135
136class ActiveNotifier : public Notifier { public:
137
138 ActiveNotifier(SearchOp op = SEARCH_STOP);
140
141 int add_activate_callback(callback_type f, void *v);
142 void remove_activate_callback(callback_type f, void *v);
143 void listeners(Vector<Task*> &v) const CLICK_DEPRECATED;
144
145 inline void set_active(bool active, bool schedule = true);
146 inline void wake();
147 inline void sleep();
148
149#if CLICK_DEBUG_SCHEDULING
150 String unparse(Router *router) const;
151#endif
152
153 private:
154
155 typedef union {
156 Task *t;
157 callback_type f;
158 void *v;
159 uintptr_t p;
160 } task_or_signal_t;
161
162 Task* _listener1;
163 task_or_signal_t* _listeners;
164
165 int listener_add(callback_type f, void *v);
166 int listener_remove(callback_type f, void *v);
167
168 ActiveNotifier(const ActiveNotifier&); // does not exist
169 ActiveNotifier& operator=(const ActiveNotifier&); // does not exist
170
171};
172
173
178 : _mask(true_mask) {
179 _v.v1 = &static_value;
180}
181
187 : _mask(mask) {
188 _v.v1 = value;
189}
190
193 : _mask(x._mask) {
194 if (likely(_mask))
195 _v.v1 = x._v.v1;
196 else
197 hard_assign_vm(x);
198}
199
202 if (unlikely(_mask == 0))
203 delete[] _v.vm;
204}
205
210 return NotifierSignal(&static_value, false_mask);
211}
212
217 return NotifierSignal(&static_value, true_mask);
218}
219
226 return NotifierSignal(&static_value, overderived_mask | true_mask);
227}
228
234 return NotifierSignal(&static_value, uninitialized_mask);
235}
236
238inline bool NotifierSignal::active() const {
239 // 2012.May.16 This fence is necessary; consider, for example,
240 // InfiniteSource's checking of nonfull notifiers.
241 click_fence();
242 return safe_active();
243}
244
246inline bool NotifierSignal::safe_active() const {
247 if (likely(_mask))
248 return (*_v.v1 & _mask) != 0;
249 else {
250 for (vmpair *vm = _v.vm; vm->mask; ++vm)
251 if ((*vm->value & vm->mask) != 0)
252 return true;
253 return false;
254 }
255}
256
258inline NotifierSignal::operator unspecified_bool_type() const {
259 return active() ? &NotifierSignal::active : 0;
260}
261
264inline bool NotifierSignal::idle() const {
265 return (_mask == false_mask && _v.v1 == &static_value);
266}
267
273inline bool NotifierSignal::busy() const {
274 return ((_mask & true_mask) && _v.v1 == &static_value);
275}
276
282inline bool NotifierSignal::overderived() const {
283 return ((_mask & overderived_mask) && _v.v1 == &static_value);
284}
285
288inline bool NotifierSignal::initialized() const {
289 return (!(_mask & uninitialized_mask) || _v.v1 != &static_value);
290}
291
301inline bool NotifierSignal::set_active(bool active) {
302 assert(_v.v1 != &static_value && !(_mask & (_mask - 1)));
303 uint32_t expected = *_v.v1;
304#if !CLICK_USERLEVEL || HAVE_MULTITHREAD
305 while (_mask) {
306#if ! CLICK_ATOMIC_COMPARE_SWAP
307 // TODO: is it equivalent to compare_swap branch?
308 uint32_t desired = (active ? expected | _mask : expected & ~_mask);
309 if(_v.v1->compare_and_swap(expected, desired))
310 break;
311 expected = *(_v.v1);
312
313#else
314 uint32_t desired = (active ? expected | _mask : expected & ~_mask);
315 uint32_t actual = _v.v1->compare_swap(expected, desired);
316 if (expected == actual)
317 break;
318 expected = actual;
319#endif
320 }
321#else
322 *_v.v1 = (active ? expected | _mask : expected & ~_mask);
323#endif
324 return expected & _mask;
325}
326
329 if (likely(this != &x)) {
330 if (unlikely(_mask == 0))
331 delete[] _v.vm;
332 _mask = x._mask;
333 if (likely(_mask))
334 _v.v1 = x._v.v1;
335 else
336 hard_assign_vm(x);
337 }
338 return *this;
339}
340
343 click_swap(_v, x._v);
344 click_swap(_mask, x._mask);
345}
346
355inline bool operator==(const NotifierSignal& a, const NotifierSignal& b) {
356 if (a._mask == b._mask) {
357 if (likely(a._mask))
358 return a._v.v1 == b._v.v1;
359 else
360 return NotifierSignal::hard_equals(a._v.vm, b._v.vm);
361 } else
362 return false;
363}
364
369inline bool operator!=(const NotifierSignal& a, const NotifierSignal& b) {
370 return !(a == b);
371}
372
391inline NotifierSignal operator+(NotifierSignal a, const NotifierSignal& b) {
392 return a += b;
393}
394
434inline Notifier::Notifier(SearchOp op)
435 : _signal(NotifierSignal::uninitialized_signal()), _search_op(op) {
436}
437
448inline Notifier::Notifier(const NotifierSignal &signal, SearchOp op)
449 : _signal(signal), _search_op(op) {
450}
451
458inline const NotifierSignal& Notifier::signal() const {
459 return _signal;
460}
461
466inline Notifier::SearchOp Notifier::search_op() const {
467 return _search_op;
468}
469
474inline bool Notifier::active() const {
475 return _signal.active();
476}
477
482inline bool Notifier::safe_active() const {
483 return _signal.safe_active();
484}
485
490inline bool Notifier::set_active(bool active) {
491 return _signal.set_active(active);
492}
493
497inline void Notifier::wake() {
498 set_active(true);
499}
500
504inline void Notifier::sleep() {
505 set_active(false);
506}
507
517inline int Notifier::add_listener(Task* task) {
518 return add_activate_callback(0, task);
519}
520
529inline void Notifier::remove_listener(Task* task) {
531}
532
543 return add_activate_callback(dependent_signal_callback, signal);
544}
545
556 remove_activate_callback(dependent_signal_callback, signal);
557}
558
592 return upstream_signal(e, port, (callback_type) 0, 0, Notifier::EMPTY_NOTIFIER);
593}
594
602 Task* task) {
603 return upstream_signal(e, port, (callback_type) 0, task, Notifier::EMPTY_NOTIFIER);
604}
605
614 Task* task, const char * signal) {
615 return upstream_signal(e, port, (callback_type) 0, task, signal);
616}
617
625 Notifier* dependent_notifier) {
626 return upstream_signal(e, port, dependent_signal_callback, &dependent_notifier->_signal, Notifier::EMPTY_NOTIFIER);
627}
628
629
637inline NotifierSignal Notifier::upstream_empty_signal(Element* e, int port, callback_type f, void *user_data)
638{
639 return upstream_signal(e,port,f,user_data,Notifier::EMPTY_NOTIFIER);
640}
641
674 return downstream_full_signal(e, port, (callback_type) 0, 0);
675}
676
684 Task* task) {
685 return downstream_full_signal(e, port, (callback_type) 0, task);
686}
687
695 Notifier* dependent_notifier) {
696 return downstream_full_signal(e, port, dependent_signal_callback, &dependent_notifier->_signal);
697}
698
700inline NotifierSignal Notifier::upstream_empty_signal(Element* e, int port, int x) {
701 (void) x;
702 assert(x == 0);
703 return upstream_empty_signal(e, port);
704}
705
707 Notifier* notifier) {
708 (void) x;
709 assert(x == 0);
710 return upstream_empty_signal(e, port, notifier);
711}
712
713inline NotifierSignal Notifier::downstream_full_signal(Element* e, int port, int x) {
714 (void) x;
715 assert(x == 0);
716 return downstream_full_signal(e, port);
717}
718
720 Notifier* notifier) {
721 (void) x;
722 assert(x == 0);
723 return downstream_full_signal(e, port, notifier);
724}
737inline void ActiveNotifier::set_active(bool active, bool schedule) {
738 bool was_active = Notifier::set_active(active);
739 if (active && schedule && !was_active) {
740 // 2007.Sep.6: Perhaps there was a race condition here. Make sure
741 // that we set the notifier to active BEFORE rescheduling downstream
742 // tasks. This is because, in a multithreaded environment, a task we
743 // reschedule might run BEFORE we set the notifier; after which it
744 // would go to sleep forever.
745 if (_listener1)
746 _listener1->reschedule();
747 else if (task_or_signal_t *tos = _listeners) {
748 for (; tos->p > 1; tos++)
749 tos->t->reschedule();
750 if (tos->p == 1)
751 for (tos++; tos->p; tos += 2)
752 tos->f(tos[1].v, this);
753 }
754 }
755}
756
765inline void ActiveNotifier::wake() {
766 set_active(true, true);
767}
768
773 set_active(false, true);
774}
775
776inline void click_swap(NotifierSignal& x, NotifierSignal& y) {
777 x.swap(y);
778}
779
780CLICK_ENDDECLS
781#endif
An atomic 32-bit integer.
A basic activity signal and notification provider that can reschedule any dependent Task objects.
Definition notifier.hh:136
void set_active(bool active, bool schedule=true)
Set the associated signal's activity, possibly scheduling any listener tasks.
Definition notifier.hh:737
int add_activate_callback(callback_type f, void *v)
Register an activate callback with this Notifier.
Definition notifier.cc:336
~ActiveNotifier()
Destroy an ActiveNotifier.
Definition notifier.cc:330
void remove_activate_callback(callback_type f, void *v)
Unregister an activate callback with this Notifier.
Definition notifier.cc:398
void listeners(Vector< Task * > &v) const
Return the listener list.
Definition notifier.cc:432
void wake()
Set the associated signal to active and schedule any listener tasks.
Definition notifier.hh:765
void sleep()
Set the associated signal to inactive.
Definition notifier.hh:772
Base class for Click elements.
Definition element.hh:42
A basic activity signal and notification provider.
Definition notifier.hh:74
bool active() const
Returns whether the associated signal is active.
Definition notifier.hh:474
Notifier(SearchOp op=SEARCH_STOP)
Constructs a Notifier.
Definition notifier.hh:434
int add_dependent_signal(NotifierSignal *signal)
Register a dependent signal with this Notifier.
Definition notifier.hh:542
int add_listener(Task *task)
Register a listener with this Notifier.
Definition notifier.hh:517
bool set_active(bool active)
Set the associated signal's activity.
Definition notifier.hh:490
const NotifierSignal & signal() const
Return this Notifier's associated NotifierSignal.
Definition notifier.hh:458
static NotifierSignal downstream_full_signal(Element *e, int port)
Calculate and return the NotifierSignal derived from all full notifiers downstream of element e's out...
Definition notifier.hh:673
SearchOp search_op() const
Return this Notifier's search operation.
Definition notifier.hh:466
bool safe_active() const
Returns whether the associated signal is active.
Definition notifier.hh:482
void sleep()
Set the associated signal to inactive.
Definition notifier.hh:504
void remove_listener(Task *task)
Unregister a listener with this Notifier.
Definition notifier.hh:529
virtual int add_activate_callback(callback_type f, void *user_data)
Register an activate callback with this Notifier.
Definition notifier.cc:274
void remove_dependent_signal(NotifierSignal *signal)
Unregister a dependent signal with this Notifier.
Definition notifier.hh:555
static NotifierSignal upstream_signal(Element *e, int port, Task *task, const char *signal)
Calculate and return the NotifierSignal derived from all empty notifiers upstream of element e's inpu...
Definition notifier.hh:613
int initialize(const char *name, Router *router)
Initialize the associated NotifierSignal, if necessary.
Definition notifier.cc:308
bool initialized() const
Return whether the Notifier is initialized.
Definition notifier.hh:84
static NotifierSignal upstream_empty_signal(Element *e, int port)
Calculate and return the NotifierSignal derived from all empty notifiers upstream of element e's inpu...
Definition notifier.hh:591
virtual ~Notifier()
Destruct a Notifier.
Definition notifier.cc:248
virtual void remove_activate_callback(callback_type f, void *user_data)
Unregister an activate callback with this Notifier.
Definition notifier.cc:294
void wake()
Set the associated signal to active.
Definition notifier.hh:497
An activity signal.
Definition notifier.hh:12
void swap(NotifierSignal &x)
Exchange the values of this signal and x.
Definition notifier.hh:342
bool idle() const
Test if the signal is idle.
Definition notifier.hh:264
bool overderived() const
Test if the signal is overderived.
Definition notifier.hh:282
friend NotifierSignal operator+(NotifierSignal a, const NotifierSignal &b)
Return a derived signal.
Definition notifier.hh:391
bool safe_active() const
Test if the signal is active.
Definition notifier.hh:246
bool busy() const
Test if the signal is busy.
Definition notifier.hh:273
friend bool operator!=(const NotifierSignal &a, const NotifierSignal &b)
Test if two NotifierSignals are unequal.
Definition notifier.hh:369
bool set_active(bool active)
Set whether the basic signal is active.
Definition notifier.hh:301
~NotifierSignal()
Destroy a signal.
Definition notifier.hh:201
bool active() const
Test if the signal is active.
Definition notifier.hh:238
static NotifierSignal overderived_signal()
Return an overderived busy signal.
Definition notifier.hh:225
NotifierSignal & operator+=(const NotifierSignal &x)
Make this signal derived by adding information from x.
Definition notifier.cc:125
String unparse(Router *router) const
Return a human-readable representation of the signal.
Definition notifier.cc:215
friend bool operator==(const NotifierSignal &a, const NotifierSignal &b)
Test if two NotifierSignals are equal.
Definition notifier.hh:355
static NotifierSignal uninitialized_signal()
Return an uninitialized signal.
Definition notifier.hh:233
static void static_initialize()
Initialize the NotifierSignal implementation.
Definition notifier.cc:113
NotifierSignal()
Construct a busy signal.
Definition notifier.hh:177
static NotifierSignal busy_signal()
Return a busy signal.
Definition notifier.hh:216
NotifierSignal & operator=(const NotifierSignal &x)
Assign a signal.
Definition notifier.hh:328
static NotifierSignal idle_signal()
Return an idle signal.
Definition notifier.hh:209
bool initialized() const
Test if the signal is initialized.
Definition notifier.hh:288
A router configuration.
Definition router.hh:28
A string of characters.
Definition string.hh:22
Represents a frequently-scheduled computational task.
Definition task.hh:49
void reschedule()
Reschedule the task.
Definition task.hh:206
Vector template.
Definition vector.hh:111
A 32-bit integer with support for atomic operations.
Definition atomic.hh:71
Support for Task, which triggers execution frequently.