// -*- c-basic-offset: 4 -*-
#ifndef CLICK_STRIDESCHED_HH
#define CLICK_STRIDESCHED_HH
#include <click/element.hh>
#include <click/task.hh>
#include <click/notifier.hh>
CLICK_DECLS
/*
* =c
* StrideSched(TICKETS0, ..., TICKETSI<N-1>)
* =s scheduling
* pulls from stride-scheduled inputs
* =d
* Has one output and N inputs. Performs simple packet-based stride
* scheduling, assigning TICKETSI<i> to input I<i> for each input.
*
* Each time a pull comes in on the output, it pulls on its inputs in the order
* specified by the stride scheduling queue, until all inputs have been tried
* or one produces a packet. If an input does not produce a packet, it is not
* tried again in the current round (for the current pull on the output) even
* if it has a very short stride. This minimizes overhead and ensures that
* an input that produces a packet, if any, is found as soon as possible,
* consistently with the stride scheduler ordering.
*
* The inputs usually come from Queues or other pull schedulers.
* StrideSched uses notification to avoid pulling from empty inputs.
*
* =h tickets0...ticketsI<N-1> read/write
* Returns or sets the number of tickets for each input port.
*
* =a PrioSched, RoundRobinSched, DRRSched, StrideSwitch
*/
class StrideSched : public Element { public:
StrideSched();
~StrideSched();
const char *class_name() const { return "StrideSched"; }
const char *port_count() const { return "1-/1"; }
const char *processing() const { return PULL; }
int configure(Vector<String> &conf, ErrorHandler *);
int initialize(ErrorHandler *);
void cleanup(CleanupStage);
void add_handlers();
enum { STRIDE1 = 1U<<16, MAX_TICKETS = 1U<<15 };
int tickets(int) const;
int set_tickets(int, int, ErrorHandler *);
Packet *pull(int port);
protected:
struct Client {
Client *_prev;
Client *_next;
unsigned _pass;
unsigned _stride;
int _tickets;
NotifierSignal _signal;
int _port;
Client *_list;
Client() : _prev(0), _next(0), _pass(0), _stride(0), _tickets(-1), _port(-1) { }
inline Client(int port, int tickets);
void set_tickets(int);
void make_head();
void insert(Client *c);
void remove();
void stride();
};
Client *_list;
};
inline
StrideSched::Client::Client(int port, int tickets)
: _prev(0), _next(0), _pass(0), _stride(STRIDE1 / tickets),
_tickets(tickets), _port(port)
{
_pass = _stride;
}
inline void
StrideSched::Client::make_head()
{
_prev = _next = _list = this;
}
inline void
StrideSched::Client::insert(Client *c)
{
assert(this == _list);
Client *x = _next;
while (x != _list && PASS_GT(c->_pass, x->_pass))
x = x->_next;
// insert c before x
c->_next = x;
c->_prev = x->_prev;
c->_prev->_next = c;
x->_prev = c;
}
inline void
StrideSched::Client::remove()
{
_next->_prev = _prev;
_prev->_next = _next;
_next = _prev = 0;
}
inline void
StrideSched::Client::set_tickets(int tickets)
{
_tickets = tickets;
_stride = STRIDE1 / tickets;
}
inline void
StrideSched::Client::stride()
{
_pass += _stride;
}
CLICK_ENDDECLS
#endif
syntax highlighted by Code2HTML, v. 0.9.1