// -*- c-basic-offset: 4; related-file-name: "../../lib/master.cc" -*- #ifndef CLICK_MASTER_HH #define CLICK_MASTER_HH #include #include #if CLICK_USERLEVEL # include #endif #if CLICK_NS # include #endif CLICK_DECLS #define CLICK_DEBUG_MASTER 0 class Master { public: Master(int nthreads); ~Master(); void use(); void unuse(); void block_all(); void unblock_all(); void pause(); inline void unpause(); bool paused() const { return _master_paused > 0; } inline int nthreads() const; inline RouterThread *thread(int id) const; void wake_somebody(); #if CLICK_USERLEVEL int add_signal_handler(int signo, Router *router, String handler); int remove_signal_handler(int signo, Router *router, String handler); void process_signals(RouterThread *thread); static void signal_handler(int signo); // not really public #endif void kill_router(Router*); #if CLICK_NS void initialize_ns(simclick_node_t *simnode); simclick_node_t *simnode() const { return _simnode; } #endif #if CLICK_DEBUG_MASTER || CLICK_DEBUG_SCHEDULING String info() const; #endif #if CLICK_USERLEVEL static volatile sig_atomic_t signals_pending; #endif private: // THREADS RouterThread **_threads; int _nthreads; // ROUTERS Router *_routers; int _refcount; void register_router(Router*); void prepare_router(Router*); void run_router(Router*, bool foreground); void unregister_router(Router*); #if CLICK_LINUXMODULE spinlock_t _master_lock; struct task_struct *_master_lock_task; int _master_lock_count; #elif HAVE_MULTITHREAD Spinlock _master_lock; #endif atomic_uint32_t _master_paused; inline void lock_master(); inline void unlock_master(); void request_stop(); bool verify_stop(RouterThread* t); #if CLICK_USERLEVEL // SIGNALS struct SignalInfo { int signo; Router *router; String handler; SignalInfo *next; SignalInfo(int signo_, Router *router_, const String &handler_) : signo(signo_), router(router_), handler(handler_), next() { } bool equals(int signo_, Router *router_, const String &handler_) const { return signo == signo_ && router == router_ && handler == handler_; } }; SignalInfo *_siginfo; sigset_t _sig_dispatching; Spinlock _signal_lock; #endif #if CLICK_NS simclick_node_t *_simnode; #endif Master(const Master&); Master& operator=(const Master&); friend class Task; friend class RouterThread; friend class Router; }; inline int Master::nthreads() const { return _nthreads - 1; } inline RouterThread* Master::thread(int id) const { // return the requested thread, or the quiescent thread if there's no such // thread if (unsigned(id + 1) < unsigned(_nthreads)) return _threads[id + 1]; else return _threads[0]; } inline void Master::wake_somebody() { _threads[1]->wake(); } #if CLICK_USERLEVEL inline void RouterThread::run_signals() { if (Master::signals_pending) _master->process_signals(this); } inline int TimerSet::next_timer_delay(bool more_tasks, Timestamp &t) const { # if CLICK_NS // The simulator should never block. (void) more_tasks, (void) t; return 0; # else if (more_tasks || Master::signals_pending) return 0; t = timer_expiry_steady_adjusted(); if (!t) return -1; // block forever else if (unlikely(Timestamp::warp_jumping())) { Timestamp::warp_jump_steady(t); return 0; } else if ((t -= Timestamp::now_steady(), !t.is_negative())) { t = t.warp_real_delay(); return 1; } else return 0; # endif } #endif inline void Master::request_stop() { for (RouterThread **t = _threads; t != _threads + _nthreads; ++t) (*t)->_stop_flag = true; // ensure that at least one thread is awake to handle the stop event wake_somebody(); } inline void Master::lock_master() { #if CLICK_LINUXMODULE if (current != _master_lock_task) { spin_lock(&_master_lock); _master_lock_task = current; } else _master_lock_count++; #elif HAVE_MULTITHREAD _master_lock.acquire(); #endif } inline void Master::unlock_master() { #if CLICK_LINUXMODULE assert(current == _master_lock_task); if (_master_lock_count == 0) { _master_lock_task = 0; spin_unlock(&_master_lock); } else _master_lock_count--; #elif HAVE_MULTITHREAD _master_lock.release(); #endif } inline void Master::unpause() { _master_paused--; } inline Master * Element::master() const { return _router->master(); } CLICK_ENDDECLS #endif