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
10 CLICK_DECLS
11
12 class NotifierSignal {
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();
24 static inline NotifierSignal uninitialized_signal();
25
26 inline bool active() const;
27 inline operator unspecified_bool_type() const;
28
29 inline bool set_active(bool active);
30
31 inline bool idle() const;
32 inline bool busy() const;
33 inline bool overderived() const;
34 inline bool initialized() const;
35
36 friend bool operator==(const NotifierSignal &a, const NotifierSignal &b);
37 friend bool operator!=(const NotifierSignal &a, const NotifierSignal &b);
38
39 NotifierSignal& operator=(const NotifierSignal& x);
40 NotifierSignal& operator+=(const NotifierSignal& x);
41 friend NotifierSignal operator+(NotifierSignal a, const NotifierSignal &b);
42
43 inline void swap(NotifierSignal& x);
44
45 String unparse(Router *router) const;
46
47 static void static_initialize();
48
49 private:
50 struct vmpair {
51 atomic_uint32_t *value;
52 uint32_t mask;
53 };
54 union vmvalue {
55 atomic_uint32_t *v1;
56 vmpair *vm;
57 };
58
59 vmvalue _v;
60 uint32_t _mask;
61
62 enum {
63 true_mask = 1, false_mask = 2, overderived_mask = 4,
64 uninitialized_mask = 8
65 };
66 static atomic_uint32_t static_value;
67
68 void hard_assign_vm(const NotifierSignal &x);
69 void hard_derive_one(atomic_uint32_t *value, uint32_t mask);
70 static bool hard_equals(const vmpair *a, const vmpair *b);
71 };
72
73 class Notifier { public:
74
75 enum SearchOp { SEARCH_STOP = 0, SEARCH_CONTINUE, SEARCH_CONTINUE_WAKE };
76 typedef void (*callback_type)(void *, Notifier *);
77
78 inline Notifier(SearchOp op = SEARCH_STOP);
79 inline Notifier(const NotifierSignal &signal, SearchOp op = SEARCH_STOP);
80 virtual ~Notifier();
81
82 /** @brief Return whether the Notifier is initialized. */
initialized() const83 inline bool initialized() const {
84 return _signal.initialized();
85 }
86
87 int initialize(const char *name, Router *router);
88
89 inline const NotifierSignal &signal() const;
90 inline SearchOp search_op() const;
91
92 inline bool active() const;
93
94 inline bool set_active(bool active);
95 inline void wake();
96 inline void sleep();
97
98 virtual int add_activate_callback(callback_type f, void *user_data);
99 virtual void remove_activate_callback(callback_type f, void *user_data);
100 inline int add_listener(Task *task);
101 inline void remove_listener(Task *task);
102 inline int add_dependent_signal(NotifierSignal *signal);
103 inline void remove_dependent_signal(NotifierSignal *signal);
104
105 static const char EMPTY_NOTIFIER[];
106 static const char FULL_NOTIFIER[];
107
108 static inline NotifierSignal upstream_empty_signal(Element *e, int port);
109 static inline NotifierSignal upstream_empty_signal(Element *e, int port, Task *task);
110 static inline NotifierSignal upstream_empty_signal(Element *e, int port, Notifier *dependent_notifier);
111 static NotifierSignal upstream_empty_signal(Element *e, int port, callback_type f, void *user_data);
112
113 static inline NotifierSignal downstream_full_signal(Element *e, int port);
114 static inline NotifierSignal downstream_full_signal(Element *e, int port, Task *task);
115 static inline NotifierSignal downstream_full_signal(Element *e, int port, Notifier *dependent_notifier);
116 static NotifierSignal downstream_full_signal(Element *e, int port, callback_type f, void *user_data);
117
118 static inline NotifierSignal upstream_empty_signal(Element *e, int port, int) CLICK_DEPRECATED;
119 static inline NotifierSignal upstream_empty_signal(Element *e, int port, int, Notifier *) CLICK_DEPRECATED;
120 static inline NotifierSignal downstream_full_signal(Element *e, int port, int) CLICK_DEPRECATED;
121 static inline NotifierSignal downstream_full_signal(Element *e, int port, int, Notifier *) CLICK_DEPRECATED;
122
123 private:
124
125 NotifierSignal _signal;
126 SearchOp _search_op;
127
128 static void dependent_signal_callback(void *, Notifier *);
129
130 };
131
132 class ActiveNotifier : public Notifier { public:
133
134 ActiveNotifier(SearchOp op = SEARCH_STOP);
135 ~ActiveNotifier();
136
137 int add_activate_callback(callback_type f, void *v);
138 void remove_activate_callback(callback_type f, void *v);
139 void listeners(Vector<Task*> &v) const CLICK_DEPRECATED;
140
141 inline void set_active(bool active, bool schedule = true);
142 inline void wake();
143 inline void sleep();
144
145 #if CLICK_DEBUG_SCHEDULING
146 String unparse(Router *router) const;
147 #endif
148
149 private:
150
151 typedef union {
152 Task *t;
153 callback_type f;
154 void *v;
155 uintptr_t p;
156 } task_or_signal_t;
157
158 Task* _listener1;
159 task_or_signal_t* _listeners;
160
161 int listener_add(callback_type f, void *v);
162 int listener_remove(callback_type f, void *v);
163
164 ActiveNotifier(const ActiveNotifier&); // does not exist
165 ActiveNotifier& operator=(const ActiveNotifier&); // does not exist
166
167 };
168
169
170 /** @brief Construct a busy signal.
171 *
172 * The returned signal is always active. */
NotifierSignal()173 inline NotifierSignal::NotifierSignal()
174 : _mask(true_mask) {
175 _v.v1 = &static_value;
176 }
177
178 /** @brief Construct an activity signal.
179 *
180 * Elements should not use this constructor directly.
181 * @sa Router::new_notifier_signal */
NotifierSignal(atomic_uint32_t * value,uint32_t mask)182 inline NotifierSignal::NotifierSignal(atomic_uint32_t* value, uint32_t mask)
183 : _mask(mask) {
184 _v.v1 = value;
185 }
186
187 /** @brief Copy construct a signal. */
NotifierSignal(const NotifierSignal & x)188 inline NotifierSignal::NotifierSignal(const NotifierSignal& x)
189 : _mask(x._mask) {
190 if (likely(_mask))
191 _v.v1 = x._v.v1;
192 else
193 hard_assign_vm(x);
194 }
195
196 /** @brief Destroy a signal. */
~NotifierSignal()197 inline NotifierSignal::~NotifierSignal() {
198 if (unlikely(_mask == 0))
199 delete[] _v.vm;
200 }
201
202 /** @brief Return an idle signal.
203 *
204 * The returned signal is never active. */
idle_signal()205 inline NotifierSignal NotifierSignal::idle_signal() {
206 return NotifierSignal(&static_value, false_mask);
207 }
208
209 /** @brief Return a busy signal.
210 *
211 * The returned signal is always active. */
busy_signal()212 inline NotifierSignal NotifierSignal::busy_signal() {
213 return NotifierSignal(&static_value, true_mask);
214 }
215
216 /** @brief Return an overderived busy signal.
217 *
218 * Overderived signals replace derived signals that are too complex to
219 * represent. An overderived signal, like a busy signal, is always
220 * active. */
overderived_signal()221 inline NotifierSignal NotifierSignal::overderived_signal() {
222 return NotifierSignal(&static_value, overderived_mask | true_mask);
223 }
224
225 /** @brief Return an uninitialized signal.
226 *
227 * Uninitialized signals may be used occasionally as placeholders for true
228 * signals to be added later. Uninitialized signals are never active. */
uninitialized_signal()229 inline NotifierSignal NotifierSignal::uninitialized_signal() {
230 return NotifierSignal(&static_value, uninitialized_mask);
231 }
232
233 /** @brief Test if the signal is active. */
active() const234 inline bool NotifierSignal::active() const {
235 // 2012.May.16 This fence is necessary; consider, for example,
236 // InfiniteSource's checking of nonfull notifiers.
237 click_fence();
238 if (likely(_mask))
239 return (*_v.v1 & _mask) != 0;
240 else {
241 for (vmpair *vm = _v.vm; vm->mask; ++vm)
242 if ((*vm->value & vm->mask) != 0)
243 return true;
244 return false;
245 }
246 }
247
248 /** @brief Test if the signal is active. */
operator unspecified_bool_type() const249 inline NotifierSignal::operator unspecified_bool_type() const {
250 return active() ? &NotifierSignal::active : 0;
251 }
252
253 /** @brief Test if the signal is idle.
254 * @return true iff the signal is idle, i.e. it will never be active. */
idle() const255 inline bool NotifierSignal::idle() const {
256 return (_mask == false_mask && _v.v1 == &static_value);
257 }
258
259 /** @brief Test if the signal is busy.
260 * @return true iff the signal is busy, i.e. it will always be active.
261 *
262 * @note An overderived_signal() is busy(), but a busy_signal() is not
263 * overderived(). */
busy() const264 inline bool NotifierSignal::busy() const {
265 return ((_mask & true_mask) && _v.v1 == &static_value);
266 }
267
268 /** @brief Test if the signal is overderived.
269 * @return true iff the signal equals overderived_signal().
270 *
271 * @note An overderived_signal() is busy(), but a busy_signal() is not
272 * overderived(). */
overderived() const273 inline bool NotifierSignal::overderived() const {
274 return ((_mask & overderived_mask) && _v.v1 == &static_value);
275 }
276
277 /** @brief Test if the signal is initialized.
278 * @return true iff the signal doesn't equal uninitialized_signal(). */
initialized() const279 inline bool NotifierSignal::initialized() const {
280 return (!(_mask & uninitialized_mask) || _v.v1 != &static_value);
281 }
282
283 /** @brief Set whether the basic signal is active.
284 * @param active true iff the basic signal is active
285 * @return previous active state
286 *
287 * Use this function to set whether a basic signal is active.
288 *
289 * It is illegal to call set_active() on derived, idle, busy, or
290 * overderived signals. Some of these actions may cause an assertion
291 * failure. */
set_active(bool active)292 inline bool NotifierSignal::set_active(bool active) {
293 assert(_v.v1 != &static_value && !(_mask & (_mask - 1)));
294 uint32_t expected = *_v.v1;
295 #if !CLICK_USERLEVEL || HAVE_MULTITHREAD
296 while (_mask) {
297 uint32_t desired = (active ? expected | _mask : expected & ~_mask);
298 uint32_t actual = _v.v1->compare_swap(expected, desired);
299 if (expected == actual)
300 break;
301 expected = actual;
302 }
303 #else
304 *_v.v1 = (active ? expected | _mask : expected & ~_mask);
305 #endif
306 return expected & _mask;
307 }
308
309 /** @brief Assign a signal. */
operator =(const NotifierSignal & x)310 inline NotifierSignal& NotifierSignal::operator=(const NotifierSignal& x) {
311 if (likely(this != &x)) {
312 if (unlikely(_mask == 0))
313 delete[] _v.vm;
314 _mask = x._mask;
315 if (likely(_mask))
316 _v.v1 = x._v.v1;
317 else
318 hard_assign_vm(x);
319 }
320 return *this;
321 }
322
323 /** @brief Exchange the values of this signal and @a x. */
swap(NotifierSignal & x)324 inline void NotifierSignal::swap(NotifierSignal& x) {
325 click_swap(_v, x._v);
326 click_swap(_mask, x._mask);
327 }
328
329 /** @relates NotifierSignal
330 * @brief Test if two NotifierSignals are equal.
331 *
332 * Returns true iff the two NotifierSignals are the same -- i.e., they
333 * combine information about exactly the same sets of basic signals.
334 *
335 * All idle() signals compare equal. busy_signal() and
336 * overderived_signal() do not compare equal, however. */
operator ==(const NotifierSignal & a,const NotifierSignal & b)337 inline bool operator==(const NotifierSignal& a, const NotifierSignal& b) {
338 if (a._mask == b._mask) {
339 if (likely(a._mask))
340 return a._v.v1 == b._v.v1;
341 else
342 return NotifierSignal::hard_equals(a._v.vm, b._v.vm);
343 } else
344 return false;
345 }
346
347 /** @relates NotifierSignal
348 * @brief Test if two NotifierSignals are unequal.
349 *
350 * Returns true iff !(@a a == @a b). */
operator !=(const NotifierSignal & a,const NotifierSignal & b)351 inline bool operator!=(const NotifierSignal& a, const NotifierSignal& b) {
352 return !(a == b);
353 }
354
355 /** @relates NotifierSignal
356 * @brief Return a derived signal.
357 *
358 * Returns a derived signal that combines information from its arguments.
359 * The result will be active whenever @a a and/or @a b is active. If the
360 * combination of @a a and @a b is too complex to represent, returns an
361 * overderived signal; this trivially follows the invariant since it is
362 * always active.
363 *
364 * Signal derivation is commutative and associative. The following
365 * special combinations are worth remembering:
366 *
367 * - An uninitialized signal plus any other signal is uninitialized.
368 * - An idle signal plus any signal @a a equals @a a.
369 * - A busy signal plus any other initialized signal is busy.
370 * - overderived_signal() plus busy_signal() equals busy_signal().
371 *
372 * @sa NotifierSignal::operator+= */
operator +(NotifierSignal a,const NotifierSignal & b)373 inline NotifierSignal operator+(NotifierSignal a, const NotifierSignal& b) {
374 return a += b;
375 }
376
377 /** @brief Constructs a Notifier.
378 * @param op controls notifier path search
379 *
380 * This function constructs a Notifier object. The Notifier's associated
381 * NotifierSignal is initially idle; it becomes associated with a signal after
382 * initialize() is called.
383 *
384 * The @a op argument controls path search. The rest of this entry
385 * describes it further.
386 *
387 * Elements interested in notification generally search for Notifier objects
388 * along all possible packet paths upstream (or downstream) of one of their
389 * ports. When a Notifier is found along a path, further searching along that
390 * path is cut off, so only the closest Notifiers are found. Sometimes,
391 * however, it makes more sense to continue searching for more Notifiers. The
392 * correct behavior is Notifier-specific, and is controlled by this method.
393 * When the search encounters a Notifier, it consults the Notifier's @a
394 * op variable supplied to the constructor. It should equal one of
395 * three SearchOp constants, which correspond to the following behavior:
396 *
397 * <dl>
398 * <dt>SEARCH_STOP</dt>
399 * <dd>Stop searching along this path. This is the default.</dd>
400 * <dt>SEARCH_CONTINUE</dt>
401 * <dd>Continue searching along this path.</dd>
402 * <dt>SEARCH_CONTINUE_WAKE</dt>
403 * <dd>Continue searching along this path, but any further Notifiers should
404 * only be used for adding and removing listeners; ignore their NotifierSignal
405 * objects. This operation is useful, for example, for schedulers that store
406 * packets temporarily. Such schedulers provide their own NotifierSignal,
407 * since the scheduler may still hold a packet even when all upstream sources
408 * are empty, but since they aren't packet sources, they don't know when
409 * new packets arrive and can't wake up sleeping listeners. During
410 * initialization, such schedulers should call Notifier::upstream_empty_signal,
411 * passing their own Notifier as the fourth argument. This will ensure that
412 * their signal is turned on appropriately whenever an upstream queue becomes
413 * nonempty.</dd>
414 * </dl>
415 */
Notifier(SearchOp op)416 inline Notifier::Notifier(SearchOp op)
417 : _signal(NotifierSignal::uninitialized_signal()), _search_op(op) {
418 }
419
420 /** @brief Constructs a Notifier associated with a given signal.
421 * @param signal the associated NotifierSignal
422 * @param op controls notifier path search
423 *
424 * This function constructs a Notifier object associated with a specific
425 * NotifierSignal, such as NotifierSignal::idle_signal(). Calling
426 * initialize() on this Notifier will not change the associated
427 * NotifierSignal. The @a op argument is as in
428 * Notifier::Notifier(SearchOp), above.
429 */
Notifier(const NotifierSignal & signal,SearchOp op)430 inline Notifier::Notifier(const NotifierSignal &signal, SearchOp op)
431 : _signal(signal), _search_op(op) {
432 }
433
434 /** @brief Return this Notifier's associated NotifierSignal.
435 *
436 * Every Notifier object corresponds to one NotifierSignal; this method
437 * returns it. The signal is @link NotifierSignal::idle idle() @endlink
438 * before initialize() is called.
439 */
signal() const440 inline const NotifierSignal& Notifier::signal() const {
441 return _signal;
442 }
443
444 /** @brief Return this Notifier's search operation.
445 *
446 * @sa Notifier() for a detailed explanation of search operations.
447 */
search_op() const448 inline Notifier::SearchOp Notifier::search_op() const {
449 return _search_op;
450 }
451
452 /** @brief Returns whether the associated signal is active.
453 *
454 * Same as signal().active().
455 */
active() const456 inline bool Notifier::active() const {
457 return _signal.active();
458 }
459
460 /** @brief Set the associated signal's activity.
461 * @param active true iff the signal should be active
462 * @return previous active state
463 */
set_active(bool active)464 inline bool Notifier::set_active(bool active) {
465 return _signal.set_active(active);
466 }
467
468 /** @brief Set the associated signal to active.
469 * @sa set_active
470 */
wake()471 inline void Notifier::wake() {
472 set_active(true);
473 }
474
475 /** @brief Set the associated signal to inactive.
476 * @sa set_active
477 */
sleep()478 inline void Notifier::sleep() {
479 set_active(false);
480 }
481
482 /** @brief Register a listener with this Notifier.
483 * @param task Task to reschedule when this Notifier becomes active
484 *
485 * When this Notifier's associated signal is activated, the Notifier should
486 * schedule @a task. Not all types of Notifier provide this functionality. The
487 * default implementation does nothing.
488 *
489 * @sa remove_listener, add_activate_callback, add_dependent_signal
490 */
add_listener(Task * task)491 inline int Notifier::add_listener(Task* task) {
492 return add_activate_callback(0, task);
493 }
494
495 /** @brief Unregister a listener with this Notifier.
496 * @param task listener Task
497 *
498 * Undoes the effect of all prior add_listener(@a task) calls. Does nothing if
499 * @a task was never added. The default implementation does nothing.
500 *
501 * @sa add_listener
502 */
remove_listener(Task * task)503 inline void Notifier::remove_listener(Task* task) {
504 remove_activate_callback(0, task);
505 }
506
507 /** @brief Register a dependent signal with this Notifier.
508 * @param signal dependent signal
509 *
510 * When this Notifier's associated signal is activated, the Notifier should
511 * also activate @a signal. Not all types of Notifier provide this
512 * functionality. The default implementation does nothing.
513 *
514 * @sa add_listener, add_activate_callback, remove_dependent_signal
515 */
add_dependent_signal(NotifierSignal * signal)516 inline int Notifier::add_dependent_signal(NotifierSignal* signal) {
517 return add_activate_callback(dependent_signal_callback, signal);
518 }
519
520 /** @brief Unregister a dependent signal with this Notifier.
521 * @param signal dependent signal
522 *
523 * Undoes the effect of all prior add_dependent_signal(@a signal) calls. Does
524 * nothing if @a signal was never added. The default implementation does
525 * nothing.
526 *
527 * @sa add_dependent_signal
528 */
remove_dependent_signal(NotifierSignal * signal)529 inline void Notifier::remove_dependent_signal(NotifierSignal* signal) {
530 remove_activate_callback(dependent_signal_callback, signal);
531 }
532
533 /** @brief Calculate and return the NotifierSignal derived from all empty
534 * notifiers upstream of element @a e's input @a port.
535 * @param e an element
536 * @param port the input port of @a e at which to start the upstream search
537 *
538 * Searches the configuration upstream of element @a e's input @a port for @e
539 * empty @e notifiers. These notifiers are associated with packet storage,
540 * and should be true when packets are available (or likely to be available
541 * quite soon), and false when they are not. All notifiers found are combined
542 * into a single derived signal. Thus, if any of the base notifiers are
543 * active, indicating that at least one packet is available upstream, the
544 * derived signal will also be active. Element @a e's code generally uses the
545 * resulting signal to decide whether or not to reschedule itself.
546 *
547 * The returned signal is generally conservative, meaning that the signal
548 * is true whenever a packet exists upstream, but the elements that provide
549 * notification are responsible for ensuring this.
550 *
551 * Overloaded versions of this function can also register a task (as in
552 * add_listener()), a signal (as in add_dependent_notifier()), or a callback
553 * function (as in add_active_callback()) for each located notifier. When
554 * packets become available, the task will be scheduled, the signal will be
555 * activated, or the callback will be called.
556 *
557 * <h3>Supporting upstream_empty_signal()</h3>
558 *
559 * Elements that have an empty notifier must override the Element::cast()
560 * method. When passed the @a name Notifier::EMPTY_NOTIFIER, this method
561 * should return a pointer to the corresponding Notifier object.
562 *
563 * @sa downstream_full_signal
564 */
upstream_empty_signal(Element * e,int port)565 inline NotifierSignal Notifier::upstream_empty_signal(Element* e, int port) {
566 return upstream_empty_signal(e, port, (callback_type) 0, 0);
567 }
568
569 /** @brief Calculate and return the NotifierSignal derived from all empty
570 * notifiers upstream of element @a e's input @a port.
571 * @param e an element
572 * @param port the input port of @a e at which to start the upstream search
573 * @param task task to schedule when packets become available
574 * @sa add_listener */
upstream_empty_signal(Element * e,int port,Task * task)575 inline NotifierSignal Notifier::upstream_empty_signal(Element* e, int port,
576 Task* task) {
577 return upstream_empty_signal(e, port, (callback_type) 0, task);
578 }
579
580 /** @brief Calculate and return the NotifierSignal derived from all empty
581 * notifiers upstream of element @a e's input @a port.
582 * @param e an element
583 * @param port the input port of @a e at which to start the upstream search
584 * @param notifier notifier to activate when packets become available
585 * @sa add_dependent_signal */
upstream_empty_signal(Element * e,int port,Notifier * dependent_notifier)586 inline NotifierSignal Notifier::upstream_empty_signal(Element* e, int port,
587 Notifier* dependent_notifier) {
588 return upstream_empty_signal(e, port, dependent_signal_callback, &dependent_notifier->_signal);
589 }
590
591 /** @brief Calculate and return the NotifierSignal derived from all full
592 * notifiers downstream of element @a e's output @a port.
593 * @param e an element
594 * @param port the output port of @a e at which to start the downstream search
595 *
596 * Searches the configuration downstream of element @a e's output @a port for
597 * @e full @e notifiers. These notifiers are associated with packet storage,
598 * and should be true when there is space for at least one packet, and false
599 * when there is not. All notifiers found are combined into a single derived
600 * signal. Thus, if any of the base notifiers are active, indicating that at
601 * least one path has available space, the derived signal will also be active.
602 * Element @a e's code generally uses the resulting signal to decide whether
603 * or not to reschedule itself.
604 *
605 * Overloaded versions of this function can also register a task (as in
606 * add_listener()), a signal (as in add_dependent_notifier()), or a callback
607 * function (as in add_active_callback()) for each located notifier. When
608 * space becomes available, the task will be scheduled, the signal will be
609 * activated, or the callback will be called.
610 *
611 * In current Click, the returned signal is conservative: if it's inactive,
612 * then there is no space for packets downstream.
613 *
614 * <h3>Supporting downstream_full_signal()</h3>
615 *
616 * Elements that have a full notifier must override the Element::cast()
617 * method. When passed the @a name Notifier::FULL_NOTIFIER, this method
618 * should return a pointer to the corresponding Notifier object.
619 *
620 * @sa upstream_empty_signal
621 */
downstream_full_signal(Element * e,int port)622 inline NotifierSignal Notifier::downstream_full_signal(Element* e, int port) {
623 return downstream_full_signal(e, port, (callback_type) 0, 0);
624 }
625
626 /** @brief Calculate and return the NotifierSignal derived from all full
627 * notifiers downstream of element @a e's output @a port.
628 * @param e an element
629 * @param port the output port of @a e at which to start the downstream search
630 * @param task task to schedule when packets become available
631 * @sa add_listener */
downstream_full_signal(Element * e,int port,Task * task)632 inline NotifierSignal Notifier::downstream_full_signal(Element* e, int port,
633 Task* task) {
634 return downstream_full_signal(e, port, (callback_type) 0, task);
635 }
636
637 /** @brief Calculate and return the NotifierSignal derived from all full
638 * notifiers downstream of element @a e's output @a port.
639 * @param e an element
640 * @param port the output port of @a e at which to start the downstream search
641 * @param notifier notifier to activate when packets become available
642 * @sa add_dependent_signal */
downstream_full_signal(Element * e,int port,Notifier * dependent_notifier)643 inline NotifierSignal Notifier::downstream_full_signal(Element* e, int port,
644 Notifier* dependent_notifier) {
645 return downstream_full_signal(e, port, dependent_signal_callback, &dependent_notifier->_signal);
646 }
647
648 /** @cond never */
upstream_empty_signal(Element * e,int port,int x)649 inline NotifierSignal Notifier::upstream_empty_signal(Element* e, int port, int x) {
650 (void) x;
651 assert(x == 0);
652 return upstream_empty_signal(e, port);
653 }
654
upstream_empty_signal(Element * e,int port,int x,Notifier * notifier)655 inline NotifierSignal Notifier::upstream_empty_signal(Element* e, int port, int x,
656 Notifier* notifier) {
657 (void) x;
658 assert(x == 0);
659 return upstream_empty_signal(e, port, notifier);
660 }
661
downstream_full_signal(Element * e,int port,int x)662 inline NotifierSignal Notifier::downstream_full_signal(Element* e, int port, int x) {
663 (void) x;
664 assert(x == 0);
665 return downstream_full_signal(e, port);
666 }
667
downstream_full_signal(Element * e,int port,int x,Notifier * notifier)668 inline NotifierSignal Notifier::downstream_full_signal(Element* e, int port, int x,
669 Notifier* notifier) {
670 (void) x;
671 assert(x == 0);
672 return downstream_full_signal(e, port, notifier);
673 }
674 /** @endcond never */
675
676 /** @brief Set the associated signal's activity, possibly scheduling any
677 * listener tasks.
678 * @param active true iff the signal should be active
679 * @param schedule if true, wake up listener tasks
680 *
681 * If @a active and @a schedule are both true, and the signal was previously
682 * inactive, then any listener Tasks are scheduled with Task::reschedule().
683 *
684 * @sa wake, sleep, add_listener
685 */
set_active(bool active,bool schedule)686 inline void ActiveNotifier::set_active(bool active, bool schedule) {
687 bool was_active = Notifier::set_active(active);
688 if (active && schedule && !was_active) {
689 // 2007.Sep.6: Perhaps there was a race condition here. Make sure
690 // that we set the notifier to active BEFORE rescheduling downstream
691 // tasks. This is because, in a multithreaded environment, a task we
692 // reschedule might run BEFORE we set the notifier; after which it
693 // would go to sleep forever.
694 if (_listener1)
695 _listener1->reschedule();
696 else if (task_or_signal_t *tos = _listeners) {
697 for (; tos->p > 1; tos++)
698 tos->t->reschedule();
699 if (tos->p == 1)
700 for (tos++; tos->p; tos += 2)
701 tos->f(tos[1].v, this);
702 }
703 }
704 }
705
706 /** @brief Set the associated signal to active and schedule any listener
707 * tasks.
708 *
709 * If the signal was previously inactive, then any listener Tasks are
710 * scheduled with Task::reschedule().
711 *
712 * @sa set_active, add_listener
713 */
wake()714 inline void ActiveNotifier::wake() {
715 set_active(true, true);
716 }
717
718 /** @brief Set the associated signal to inactive.
719 * @sa set_active
720 */
sleep()721 inline void ActiveNotifier::sleep() {
722 set_active(false, true);
723 }
724
click_swap(NotifierSignal & x,NotifierSignal & y)725 inline void click_swap(NotifierSignal& x, NotifierSignal& y) {
726 x.swap(y);
727 }
728
729 CLICK_ENDDECLS
730 #endif
731