genode/repos/os/include/os/alarm.h
Norman Feske 26524edbf4 alarm: reposition reprogrammed alarms in queue
The alarm library failed to handle the case properly where an already
scheduled alarm gets rescheduled before it triggered. Even though the
attempt to reschedule the alarm (twice insertion into alarm queue) was
detected, this condition resulted in the mere modification of the
alarm's parameters while keeping the alarm's queue position unchanged.
This, in turn, may violate the invariant that all enqueued alarm objects
are strictly ordered by their deadlines. The patch handles the case by
dequeuing the alarm object before reinserting it into the queue at the
right position.

Fixes #1646
2015-08-21 11:00:57 +02:00

152 lines
3.4 KiB
C++

/*
* \brief Timed event scheduler interface
* \date 2005-10-24
* \author Norman Feske
*/
/*
* Copyright (C) 2005-2013 Genode Labs GmbH
*
* This file is part of the Genode OS framework, which is distributed
* under the terms of the GNU General Public License version 2.
*/
#ifndef _INCLUDE__OS__ALARM_H_
#define _INCLUDE__OS__ALARM_H_
#include <base/lock.h>
namespace Genode {
class Alarm_scheduler;
class Alarm;
}
class Genode::Alarm
{
public:
typedef unsigned long Time;
private:
friend class Alarm_scheduler;
Lock _dispatch_lock; /* taken during handle method */
Time _deadline; /* next deadline */
Time _period; /* duration between alarms */
int _active; /* set to one when active */
Alarm *_next; /* next alarm in alarm list */
Alarm_scheduler *_scheduler; /* currently assigned scheduler */
void _assign(Time period, Time deadline, Alarm_scheduler *scheduler) {
_period = period, _deadline = deadline, _scheduler = scheduler; }
void _reset() {
_assign(0, 0, 0), _active = 0, _next = 0; }
protected:
/**
* Method to be called on when deadline is reached
*
* This method must be implemented by a derived class. If the
* return value is 'true' and the alarm is periodically scheduled,
* the alarm is scheduled again.
*/
virtual bool on_alarm(unsigned) { return false; }
public:
Alarm() { _reset(); }
virtual ~Alarm();
};
class Genode::Alarm_scheduler
{
private:
Lock _lock; /* protect alarm list */
Alarm *_head; /* head of alarm list */
Alarm::Time _now; /* recent time (updated by handle method) */
/**
* Enqueue alarm into alarm queue
*
* This is a helper for 'schedule' and 'handle'.
*/
void _unsynchronized_enqueue(Alarm *alarm);
/**
* Dequeue alarm from alarm queue
*/
void _unsynchronized_dequeue(Alarm *alarm);
/**
* Dequeue next pending alarm from alarm list
*
* \return dequeued pending alarm
* \retval 0 no alarm pending
*/
Alarm *_get_pending_alarm();
/**
* Assign timeout values to alarm object and add it to the schedule
*/
void _setup_alarm(Alarm &alarm, Alarm::Time period, Alarm::Time deadline);
public:
Alarm_scheduler() : _head(0), _now(0) { }
~Alarm_scheduler();
/**
* Schedule absolute timeout
*
* \param timeout absolute point in time for execution
*/
void schedule_absolute(Alarm *alarm, Alarm::Time timeout);
/**
* Schedule alarm (periodic timeout)
*
* \param period alarm period
*
* The first deadline is overdue after this call, i.e. on_alarm() is
* called immediately.
*/
void schedule(Alarm *alarm, Alarm::Time period);
/**
* Remove alarm from schedule
*/
void discard(Alarm *alarm);
/**
* Handle alarms
*
* \param now current time
*/
void handle(Alarm::Time now);
/**
* Determine next deadline (absolute)
*
* \param deadline out parameter for storing the next deadline
* \return true if an alarm is scheduled
*/
bool next_deadline(Alarm::Time *deadline);
/**
* Determine if given alarm object is current head element
*
* \param alarm alarm object
* \return true if alarm is head element of timeout queue
*/
bool head_timeout(const Alarm * alarm) { return _head == alarm; }
};
#endif /* _INCLUDE__OS__ALARM_H_ */