// -*- c-basic-offset: 4; tab-width: 8; indent-tabs-mode: t -*- // vim:set sts=4 ts=8: // Copyright (c) 2001-2005 International Computer Science Institute // // Permission is hereby granted, free of charge, to any person obtaining a // copy of this software and associated documentation files (the "Software") // to deal in the Software without restriction, subject to the conditions // listed in the XORP LICENSE file. These conditions include: you must // preserve this copyright notice, and you cannot mention the copyright // holders in advertising related to the Software without their permission. // The Software is provided WITHOUT ANY WARRANTY, EXPRESS OR IMPLIED. This // notice is a summary of the XORP LICENSE file; the license in that file is // legally binding. // $XORP: xorp/ospf/delay_queue.hh,v 1.5 2005/09/05 01:04:25 atanu Exp $ #ifndef __OSPF_DELAY_QUEUE_HH__ #define __OSPF_DELAY_QUEUE_HH__ /** * Entries can be added to the queue at any rate. The callback is * invoked at the specified period to remove an entry from the queue. */ template <typename _Entry> class DelayQueue { public: typedef typename XorpCallback1<void, _Entry>::RefPtr DelayCallback; DelayQueue(EventLoop& eventloop, uint32_t delay, DelayCallback forward) : _eventloop(eventloop), _delay(delay), _forward(forward) {} /** * Add an entry to the queue. If the entry is already on the queue * it is not added again. */ void add(_Entry entry); /** * Start the timer running but don't add anything to the queue. */ void fire(); private: EventLoop& _eventloop; deque<_Entry> _queue; const uint32_t _delay; // Delay in seconds. DelayCallback _forward; // Invoked to forward an entry from the queue. XorpTimer _timer; // Timer that services the queue. /** * Invoked from the timer to take the next entry from the queue. */ void next(); }; template <typename _Entry> void DelayQueue<_Entry>::add(_Entry entry) { // If this entry is already on the queue just return. if (_queue.end() != find(_queue.begin(), _queue.end(), entry)) return; // If the timer is running push this entry to the back of the // queue and return. if (_timer.scheduled()) { _queue.push_back(entry); return; } // If the timer isn't running then we have been idle for more than // delay seconds. Forward this entry immediately and start the // timer. Start the timer first in case this code is re-entered. _timer = _eventloop.new_oneoff_after(TimeVal(_delay, 0), callback(this, &DelayQueue::next)); _forward->dispatch(entry); } template <typename _Entry> void DelayQueue<_Entry>::fire() { if (_timer.scheduled()) return; _timer = _eventloop.new_oneoff_after(TimeVal(_delay, 0), callback(this, &DelayQueue::next)); } template <typename _Entry> void DelayQueue<_Entry>::next() { if (_queue.empty()) return; _timer = _eventloop.new_oneoff_after(TimeVal(_delay, 0), callback(this, &DelayQueue::next)); _Entry entry = _queue.front(); _queue.pop_front(); _forward->dispatch(entry); } #endif // __OSPF_DELAY_QUEUE_HH__