/* Web Polygraph http://www.web-polygraph.org/ * (C) 2003-2006 The Measurement Factory * Licensed under the Apache License, Version 2.0 */ #include "xstd/xstd.h" #include "xstd/Assert.h" #include "xstd/AlarmClock.h" #include "xstd/gadgets.h" AlarmClock TheAlarmClock; /* Alarm */ void Alarm::ring() { Assert(theSleeper); theSleeper->wakeUp(*this); clear(); } void Alarm::snooze() { Assert(theSleeper); theSleeper->snooze(*this); clear(); } void Alarm::set(Time aTime, AlarmUser *aSleeper) { Assert(aSleeper); theSleeper = aSleeper; theTime = aTime; } /* AlarmUser */ AlarmUser::AlarmUser(): thePendAlarmCnt(0) { } AlarmUser::~AlarmUser() { cancelAlarms(); } void AlarmUser::wakeUp(const Alarm &) { thePendAlarmCnt--; Assert(thePendAlarmCnt >= 0); } // ignore this alarm void AlarmUser::snooze(const Alarm &) { thePendAlarmCnt--; Assert(thePendAlarmCnt >= 0); } void AlarmUser::sleepTill(Time time) { TheAlarmClock.setAlarm(Alarm(time, this)); thePendAlarmCnt++; } void AlarmUser::sleepFor(Time delay) { sleepTill(TheClock + delay); } void AlarmUser::cancelAlarms() { if (thePendAlarmCnt) TheAlarmClock.cancelAll(this); Assert(!thePendAlarmCnt); } /* AlarmClock */ AlarmClock::AlarmClock() { } void AlarmClock::setAlarm(const Alarm &alarm) { if (alarm) theQueue.add(alarm); } void AlarmClock::cancelAll(const AlarmUser *sleeper) { for (int i = theQueue.count()-1; i >= 0 && sleeper->alarmWaiting(); --i) { if (theQueue.at(i).sleeper() == sleeper) theQueue.at(i).snooze(); } } // rings all ready alarms void AlarmClock::ring() { // process alarms that were current at the call time only for (int c = theQueue.count(); c && !theQueue.empty(); --c) { if (const Alarm &alarm = theQueue.top()) { if (alarm.time() <= theCurTime) { static Time lastRing; Assert(lastRing <= alarm.time()); lastRing = alarm.time(); theQueue.shift().ring(); } else break; // not ready yet } else { theQueue.skip(); } } } void AlarmClock::update(Time curTime) { Clock::update(curTime); ring(); } // must be called only for an alarm clock that is on Time AlarmClock::timeLeft() const { Assert(!theQueue.empty()); if (const Alarm &alarm = theQueue.top()) return alarm.time() - theCurTime; Assert(false); // timeLeft() must be called only for set alarm clock return Time(); } bool AlarmClock::on() { while (!theQueue.empty() && !theQueue.top()) theQueue.skip(); return !theQueue.empty(); }