224 lines
4.7 KiB
C++
224 lines
4.7 KiB
C++
// -*- c-basic-offset: 4; related-file-name: "../../lib/master.cc" -*-
|
|
#ifndef CLICK_MASTER_HH
|
|
#define CLICK_MASTER_HH
|
|
#include <click/router.hh>
|
|
#include <click/atomic.hh>
|
|
#if CLICK_USERLEVEL
|
|
# include <signal.h>
|
|
#endif
|
|
#if CLICK_NS
|
|
# include <click/simclick.h>
|
|
#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
|