// -*- c-basic-offset: 4 -*-
#ifndef CLICK_SIMPLEQUEUE_HH
#define CLICK_SIMPLEQUEUE_HH
#include <click/element.hh>
#include <click/standard/storage.hh>
CLICK_DECLS
/*
=c
SimpleQueue
SimpleQueue(CAPACITY)
=s storage
stores packets in a FIFO queue
=d
Stores incoming packets in a first-in-first-out queue.
Drops incoming packets if the queue already holds CAPACITY packets.
The default for CAPACITY is 1000.
=n
The Queue and NotifierQueue elements act like SimpleQueue, but additionally
notify interested parties when they change state (from nonempty to empty or
vice versa, and/or from nonfull to full or vice versa).
=h length read-only
Returns the current number of packets in the queue.
=h highwater_length read-only
Returns the maximum number of packets that have ever been in the queue at once.
=h capacity read/write
Returns or sets the queue's capacity.
=h drops read-only
Returns the number of packets dropped by the queue so far.
=h reset_counts write-only
When written, resets the C<drops> and C<highwater_length> counters.
=h reset write-only
When written, drops all packets in the queue.
=a Queue, NotifierQueue, MixedQueue, RED, FrontDropQueue */
class SimpleQueue : public Element, public Storage { public:
SimpleQueue();
~SimpleQueue();
int drops() const { return _drops; }
int highwater_length() const { return _highwater_length; }
void enq(Packet*);
void lifo_enq(Packet*);
Packet* deq();
// to be used with care
Packet* packet(int i) const { return _q[i]; }
template <typename Filter> Packet* yank1(Filter);
template <typename Filter> Packet* yank1_peek(Filter);
template <typename Filter> int yank(Filter, Vector<Packet *> &);
const char* class_name() const { return "SimpleQueue"; }
const char *port_count() const { return PORTS_1_1; }
const char* processing() const { return PUSH_TO_PULL; }
void* cast(const char*);
int configure(Vector<String>&, ErrorHandler*);
int initialize(ErrorHandler*);
void cleanup(CleanupStage);
bool can_live_reconfigure() const { return true; }
int live_reconfigure(Vector<String>&, ErrorHandler*);
void take_state(Element*, ErrorHandler*);
void add_handlers();
void push(int port, Packet*);
Packet* pull(int port);
protected:
Packet** _q;
int _drops;
int _highwater_length;
friend class MixedQueue;
friend class TokenQueue;
friend class InOrderQueue;
friend class ECNQueue;
static String read_handler(Element*, void*);
static int write_handler(const String&, Element*, void*, ErrorHandler*);
};
inline void
SimpleQueue::enq(Packet *p)
{
assert(p);
int next = next_i(_tail);
if (next != _head) {
_q[_tail] = p;
_tail = next;
} else
p->kill();
}
inline void
SimpleQueue::lifo_enq(Packet *p)
{
// XXX NB: significantly more dangerous in a multithreaded environment
// than plain (FIFO) enq().
assert(p);
int prev = prev_i(_head);
if (prev == _tail) {
_tail = prev_i(_tail);
_q[_tail]->kill();
}
_q[prev] = p;
_head = prev;
}
inline Packet *
SimpleQueue::deq()
{
if (_head != _tail) {
Packet *p = _q[_head];
assert(p);
_head = next_i(_head);
return p;
} else
return 0;
}
template <typename Filter>
Packet *
SimpleQueue::yank1(Filter filter)
/* Remove from the queue and return the first packet that matches
'filter(Packet *)'. The returned packet must be deallocated by the
caller. */
{
for (int trav = _head; trav != _tail; trav = next_i(trav))
if (filter(_q[trav])) {
Packet *p = _q[trav];
int prev = prev_i(trav);
while (trav != _head) {
_q[trav] = _q[prev];
trav = prev;
prev = prev_i(prev);
}
_head = next_i(_head);
return p;
}
return 0;
}
template <typename Filter>
Packet *
SimpleQueue::yank1_peek(Filter filter)
/* return the first packet that matches
'filter(Packet *)'. The returned packet must *NOT* be deallocated by the
caller. */
{
for (int trav = _head; trav != _tail; trav = next_i(trav))
if (filter(_q[trav])) {
Packet *p = _q[trav];
return p;
}
return 0;
}
template <typename Filter>
int
SimpleQueue::yank(Filter filter, Vector<Packet *> &yank_vec)
/* Removes from the queue and adds to 'yank_vec' all packets in the queue
that match 'filter(Packet *)'. Packets are added to 'yank_vec' in LIFO
order, so 'yank_vec.back()' will equal the first packet in the queue
that matched 'filter()'. Caller should deallocate any packets returned
in 'yank_vec'. Returns the number of packets yanked. */
{
int write_ptr = _tail;
int nyanked = 0;
for (int trav = _tail; trav != _head; ) {
trav = prev_i(trav);
if (filter(_q[trav])) {
yank_vec.push_back(_q[trav]);
nyanked++;
} else {
write_ptr = prev_i(write_ptr);
_q[write_ptr] = _q[trav];
}
}
_head = write_ptr;
return nyanked;
}
CLICK_ENDDECLS
#endif
syntax highlighted by Code2HTML, v. 0.9.1