1 /* +------------------------------------+
\r * | Inspire Internet Relay Chat Daemon |
\r * +------------------------------------+
\r *
\r * InspIRCd: (C) 2002-2007 InspIRCd Development Team
\r * See: http://www.inspircd.org/wiki/index.php/Credits
\r *
\r * This program is free but copyrighted software; see
\r * the file COPYING for details.
\r *
\r * ---------------------------------------------------
\r */
\r\r#include "inspircd.h"
\r#include "timer.h"
\r\rTimerManager::TimerManager(InspIRCd* Instance) : CantDeleteHere(false), ServerInstance(Instance)
\r{
\r}
\r\rvoid TimerManager::TickTimers(time_t TIME)
\r{
\r this->CantDeleteHere = true;
\r timerlist::iterator found = Timers.find(TIME);
\r\r if (found != Timers.end())
\r {
\r timergroup* x = found->second;
\r /* There are pending timers to trigger.
\r * WARNING: Timers may delete themselves from within
\r * their own Tick methods! see the comment below in
\r * the DelTimer method.
\r */
\r for (timergroup::iterator y = x->begin(); y != x->end(); y++)
\r {
\r InspTimer* n = *y;
\r n->Tick(TIME);
\r if (n->GetRepeat())
\r {
\r AddTimer(n, n->GetSecs());
\r }
\r else
\r {
\r DELETE(n);
\r }
\r }
\r\r Timers.erase(found);
\r DELETE(x);
\r }
\r\r this->CantDeleteHere = false;
\r}
\r\rvoid TimerManager::DelTimer(InspTimer* T)
\r{
\r if (this->CantDeleteHere)
\r {
\r /* If a developer tries to delete a timer from within its own Tick method,
\r * then chances are this is just going to totally fuck over the timergroup
\r * and timerlist iterators and cause a crash. Thanks to peavey and Bricker
\r * for noticing this bug.
\r * If we're within the tick loop when the DelTimer is called (signified
\r * by the var 'CantDeleteHere') then we simply return for non-repeating
\r * timers, and cancel the repeat on repeating timers. We can do this because
\r * we know that the timer tick loop will safely delete the timer for us
\r * anyway and therefore we avoid stack corruption.
\r */
\r if (T->GetRepeat())
\r T->CancelRepeat();
\r else
\r return;
\r }
\r\r timerlist::iterator found = Timers.find(T->GetTimer());
\r\r if (found != Timers.end())
\r {
\r timergroup* x = found->second;
\r for (timergroup::iterator y = x->begin(); y != x->end(); y++)
\r {
\r InspTimer* n = *y;
\r if (n == T)
\r {
\r DELETE(n);
\r x->erase(y);
\r if (!x->size())
\r {
\r Timers.erase(found);
\r DELETE(x);
\r }
\r return;
\r }
\r }
\r }
\r}
\r\r/** Because some muppets may do odd things, and their ircd may lock up due
\r * to crappy 3rd party modules, or they may change their system time a bit,
\r * this accounts for shifts of up to 120 secs by looking behind for missed
\r * timers and executing them. This is only executed once every 5 secs.
\r * If you move your clock BACK, and your timers move further ahead as a result,
\r * then tough titty you'll just have to wait.
\r */
\rvoid TimerManager::TickMissedTimers(time_t TIME)
\r{
\r for (time_t n = TIME-1; n > TIME-120; n--)
\r this->TickTimers(TIME);
\r}
\r\rvoid TimerManager::AddTimer(InspTimer* T, long secs_from_now)
\r{
\r timergroup* x = NULL;
\r\r int time_to_trigger = 0;
\r if (!secs_from_now)
\r time_to_trigger = T->GetTimer();
\r else
\r time_to_trigger = secs_from_now + ServerInstance->Time();
\r\r timerlist::iterator found = Timers.find(time_to_trigger);
\r\r if (found != Timers.end())
\r {
\r x = found->second;
\r }
\r else
\r {
\r x = new timergroup;
\r Timers[time_to_trigger] = x;
\r }
\r\r x->push_back(T);
\r}
\r\r