00001
00002 #ifndef CLICK_NOTIFIER_HH
00003 #define CLICK_NOTIFIER_HH
00004 #include <click/task.hh>
00005 #include <click/atomic.hh>
00006 #if HAVE_CXX_PRAGMA_INTERFACE
00007 # pragma interface "click/notifier.hh"
00008 #endif
00009 CLICK_DECLS
00010
00011 class NotifierSignal { public:
00012
00016 inline NotifierSignal();
00017
00022 inline NotifierSignal(atomic_uint32_t* value, uint32_t mask);
00023
00025 inline NotifierSignal(const NotifierSignal &x);
00026
00028 inline ~NotifierSignal();
00029
00033 static inline NotifierSignal idle_signal();
00034
00038 static inline NotifierSignal busy_signal();
00039
00045 static inline NotifierSignal overderived_signal();
00046
00051 static inline NotifierSignal uninitialized_signal();
00052
00053 typedef bool (NotifierSignal::*unspecified_bool_type)() const;
00054
00057 inline operator unspecified_bool_type() const;
00058
00061 inline bool active() const;
00062
00065 inline bool idle() const;
00066
00072 inline bool busy() const;
00073
00079 inline bool overderived() const;
00080
00083 inline bool initialized() const;
00084
00094 inline bool set_active(bool active);
00095
00097 NotifierSignal &operator=(const NotifierSignal &x);
00098
00106 NotifierSignal &operator+=(const NotifierSignal& x);
00107
00112 String unparse(Router *router) const;
00113
00114 static void static_initialize();
00115
00124 friend bool operator==(const NotifierSignal &a, const NotifierSignal &b);
00125
00130 friend bool operator!=(const NotifierSignal &a, const NotifierSignal &b);
00131
00150 friend NotifierSignal operator+(NotifierSignal a, const NotifierSignal &b);
00151
00152 private:
00153
00154 struct vmpair {
00155 atomic_uint32_t *value;
00156 uint32_t mask;
00157 };
00158
00159 union {
00160 atomic_uint32_t *v1;
00161 vmpair *vm;
00162 } _v;
00163 uint32_t _mask;
00164
00165 enum {
00166 true_mask = 1, false_mask = 2, overderived_mask = 4,
00167 uninitialized_mask = 8
00168 };
00169 static atomic_uint32_t static_value;
00170
00171 void hard_assign_vm(const NotifierSignal &x);
00172 void hard_derive_one(atomic_uint32_t *value, uint32_t mask);
00173 static bool hard_equals(const vmpair *a, const vmpair *b);
00174
00175 };
00176
00177 class Notifier { public:
00178
00179 enum SearchOp { SEARCH_STOP = 0, SEARCH_CONTINUE, SEARCH_CONTINUE_WAKE };
00180
00181 inline Notifier(SearchOp op = SEARCH_STOP);
00182 inline Notifier(const NotifierSignal &signal, SearchOp op = SEARCH_STOP);
00183 virtual ~Notifier();
00184
00186 inline bool initialized() const {
00187 return _signal.initialized();
00188 }
00189
00190 int initialize(const char *name, Router *router);
00191
00192 inline const NotifierSignal &signal() const;
00193 inline SearchOp search_op() const;
00194
00195 inline bool active() const;
00196
00197 inline bool set_active(bool active);
00198 inline void wake();
00199 inline void sleep();
00200
00201 virtual int add_listener(Task *task);
00202 virtual void remove_listener(Task *task);
00203 virtual int add_dependent_signal(NotifierSignal *signal);
00204
00205 static const char EMPTY_NOTIFIER[];
00206 static const char FULL_NOTIFIER[];
00207
00208 static NotifierSignal upstream_empty_signal(Element* e, int port, Task* task, Notifier* dependent_notifier = 0);
00209 static NotifierSignal downstream_full_signal(Element* e, int port, Task* task, Notifier* dependent_notifier = 0);
00210
00211 private:
00212
00213 NotifierSignal _signal;
00214 SearchOp _search_op;
00215
00216 };
00217
00218 class ActiveNotifier : public Notifier { public:
00219
00220 ActiveNotifier(SearchOp op = SEARCH_STOP);
00221 ~ActiveNotifier();
00222
00223 int add_listener(Task *task);
00224 void remove_listener(Task *task);
00225 int add_dependent_signal(NotifierSignal *signal);
00226 void listeners(Vector<Task*> &v) const;
00227
00228 inline void set_active(bool active, bool schedule = true);
00229 inline void wake();
00230 inline void sleep();
00231
00232 private:
00233
00234 typedef union {
00235 Task *t;
00236 NotifierSignal *s;
00237 void *v;
00238 } task_or_signal_t;
00239
00240 Task* _listener1;
00241 task_or_signal_t* _listeners;
00242
00243 int listener_change(void *what, int where, bool rem);
00244
00245 ActiveNotifier(const ActiveNotifier&);
00246 ActiveNotifier& operator=(const ActiveNotifier&);
00247
00248 };
00249
00250
00251 inline
00252 NotifierSignal::NotifierSignal()
00253 : _mask(true_mask)
00254 {
00255 _v.v1 = &static_value;
00256 }
00257
00258 inline
00259 NotifierSignal::NotifierSignal(atomic_uint32_t* value, uint32_t mask)
00260 : _mask(mask)
00261 {
00262 _v.v1 = value;
00263 }
00264
00265 inline
00266 NotifierSignal::NotifierSignal(const NotifierSignal &x)
00267 : _mask(x._mask)
00268 {
00269 if (likely(_mask))
00270 _v.v1 = x._v.v1;
00271 else
00272 hard_assign_vm(x);
00273 }
00274
00275 inline
00276 NotifierSignal::~NotifierSignal()
00277 {
00278 if (unlikely(_mask == 0))
00279 delete[] _v.vm;
00280 }
00281
00282 inline NotifierSignal
00283 NotifierSignal::idle_signal()
00284 {
00285 return NotifierSignal(&static_value, false_mask);
00286 }
00287
00288 inline NotifierSignal
00289 NotifierSignal::busy_signal()
00290 {
00291 return NotifierSignal(&static_value, true_mask);
00292 }
00293
00294 inline NotifierSignal
00295 NotifierSignal::overderived_signal()
00296 {
00297 return NotifierSignal(&static_value, overderived_mask | true_mask);
00298 }
00299
00300 inline NotifierSignal
00301 NotifierSignal::uninitialized_signal()
00302 {
00303 return NotifierSignal(&static_value, uninitialized_mask);
00304 }
00305
00306 inline bool
00307 NotifierSignal::active() const
00308 {
00309
00310
00311
00312 if (likely(_mask))
00313 return (*_v.v1 & _mask) != 0;
00314 else {
00315 for (vmpair *vm = _v.vm; vm->mask; ++vm)
00316 if ((*vm->value & vm->mask) != 0)
00317 return true;
00318 return false;
00319 }
00320 }
00321
00322 inline
00323 NotifierSignal::operator unspecified_bool_type() const
00324 {
00325 return active() ? &NotifierSignal::active : 0;
00326 }
00327
00328 inline bool
00329 NotifierSignal::idle() const
00330 {
00331 return (_mask == false_mask && _v.v1 == &static_value);
00332 }
00333
00334 inline bool
00335 NotifierSignal::busy() const
00336 {
00337 return ((_mask & true_mask) && _v.v1 == &static_value);
00338 }
00339
00340 inline bool
00341 NotifierSignal::overderived() const
00342 {
00343 return ((_mask & overderived_mask) && _v.v1 == &static_value);
00344 }
00345
00346 inline bool
00347 NotifierSignal::initialized() const
00348 {
00349 return (!(_mask & uninitialized_mask) || _v.v1 != &static_value);
00350 }
00351
00352 inline bool
00353 NotifierSignal::set_active(bool active)
00354 {
00355 assert(_mask && _v.v1 != &static_value && !(_mask & (_mask - 1)));
00356 uint32_t expected = *_v.v1;
00357 #if !CLICK_USERLEVEL || HAVE_MULTITHREAD
00358 while (1) {
00359 uint32_t desired = (active ? expected | _mask : expected & ~_mask);
00360 uint32_t actual = _v.v1->compare_swap(expected, desired);
00361 if (expected == actual)
00362 break;
00363 expected = actual;
00364 }
00365 #else
00366 *_v.v1 = (active ? expected | _mask : expected & ~_mask);
00367 #endif
00368 return expected & _mask;
00369 }
00370
00371 inline NotifierSignal &
00372 NotifierSignal::operator=(const NotifierSignal &x)
00373 {
00374 if (likely(this != &x)) {
00375 if (unlikely(_mask == 0))
00376 delete[] _v.vm;
00377 _mask = x._mask;
00378 if (likely(_mask))
00379 _v.v1 = x._v.v1;
00380 else
00381 hard_assign_vm(x);
00382 }
00383 return *this;
00384 }
00385
00386 inline bool
00387 operator==(const NotifierSignal& a, const NotifierSignal& b)
00388 {
00389 if (a._mask == b._mask) {
00390 if (likely(a._mask))
00391 return a._v.v1 == b._v.v1;
00392 else
00393 return NotifierSignal::hard_equals(a._v.vm, b._v.vm);
00394 } else
00395 return false;
00396 }
00397
00398 inline bool
00399 operator!=(const NotifierSignal& a, const NotifierSignal& b)
00400 {
00401 return !(a == b);
00402 }
00403
00404 inline NotifierSignal
00405 operator+(NotifierSignal a, const NotifierSignal& b)
00406 {
00407 return a += b;
00408 }
00409
00449 inline
00450 Notifier::Notifier(SearchOp op)
00451 : _signal(NotifierSignal::uninitialized_signal()), _search_op(op)
00452 {
00453 }
00454
00465 inline
00466 Notifier::Notifier(const NotifierSignal &signal, SearchOp op)
00467 : _signal(signal), _search_op(op)
00468 {
00469 }
00470
00477 inline const NotifierSignal &
00478 Notifier::signal() const
00479 {
00480 return _signal;
00481 }
00482
00487 inline Notifier::SearchOp
00488 Notifier::search_op() const
00489 {
00490 return _search_op;
00491 }
00492
00497 inline bool
00498 Notifier::active() const
00499 {
00500 return _signal.active();
00501 }
00502
00507 inline bool
00508 Notifier::set_active(bool active)
00509 {
00510 return _signal.set_active(active);
00511 }
00512
00516 inline void
00517 Notifier::wake()
00518 {
00519 set_active(true);
00520 }
00521
00525 inline void
00526 Notifier::sleep()
00527 {
00528 set_active(false);
00529 }
00530
00541 inline void
00542 ActiveNotifier::set_active(bool active, bool schedule)
00543 {
00544 bool was_active = Notifier::set_active(active);
00545 if (active && schedule && !was_active) {
00546
00547
00548
00549
00550
00551 if (_listener1)
00552 _listener1->reschedule();
00553 else if (task_or_signal_t *tos = _listeners) {
00554 for (; tos->t; tos++)
00555 tos->t->reschedule();
00556 for (tos++; tos->s; tos++)
00557 tos->s->set_active(true);
00558 }
00559 }
00560 }
00561
00570 inline void
00571 ActiveNotifier::wake()
00572 {
00573 set_active(true, true);
00574 }
00575
00579 inline void
00580 ActiveNotifier::sleep()
00581 {
00582 set_active(false, true);
00583 }
00584
00585 CLICK_ENDDECLS
00586 #endif