]> git.netwichtig.de Git - user/henk/code/inspircd.git/blob - src/timer.cpp
c041075025321e04fc5aa8cd8b2e20fb64a11fc3
[user/henk/code/inspircd.git] / src / timer.cpp
1 /*       +------------------------------------+
2  *       | Inspire Internet Relay Chat Daemon |
3  *       +------------------------------------+
4  *
5  *  InspIRCd: (C) 2002-2007 InspIRCd Development Team
6  * See: http://www.inspircd.org/wiki/index.php/Credits
7  *
8  * This program is free but copyrighted software; see
9  *            the file COPYING for details.
10  *
11  * ---------------------------------------------------
12  */
13
14 #include "inspircd.h"
15 #include "timer.h"
16
17 TimerManager::TimerManager(InspIRCd* Instance) : CantDeleteHere(false), ServerInstance(Instance)
18 {
19 }
20
21 void TimerManager::TickTimers(time_t TIME)
22 {
23         this->CantDeleteHere = true;
24         timerlist::iterator found = Timers.find(TIME);
25
26         if (found != Timers.end())
27         {
28                 timergroup* x = found->second;
29                 /* There are pending timers to trigger.
30                  * WARNING: Timers may delete themselves from within
31                  * their own Tick methods! see the comment below in
32                  * the DelTimer method.
33                  */
34                 for (timergroup::iterator y = x->begin(); y != x->end(); y++)
35                 {
36                         InspTimer* n = *y;
37                         n->Tick(TIME);
38                         if (n->GetRepeat())
39                         {
40                                 AddTimer(n, n->GetSecs());
41                         }
42                         else
43                         {
44                                 DELETE(n);
45                         }
46                 }
47
48                 Timers.erase(found);
49                 DELETE(x);
50         }
51
52         this->CantDeleteHere = false;
53 }
54
55 void TimerManager::DelTimer(InspTimer* T)
56 {
57         if (this->CantDeleteHere)
58         {
59                 /* If a developer tries to delete a timer from within its own Tick method,
60                  * then chances are this is just going to totally fuck over the timergroup
61                  * and timerlist iterators and cause a crash. Thanks to peavey and Bricker
62                  * for noticing this bug.
63                  * If we're within the tick loop when the DelTimer is called (signified
64                  * by the var 'CantDeleteHere') then we simply return for non-repeating
65                  * timers, and cancel the repeat on repeating timers. We can do this because
66                  * we know that the timer tick loop will safely delete the timer for us
67                  * anyway and therefore we avoid stack corruption.
68                  */
69                 if (T->GetRepeat())
70                         T->CancelRepeat();
71                 else
72                         return;
73         }
74
75         timerlist::iterator found = Timers.find(T->GetTimer());
76
77         if (found != Timers.end())
78         {
79                 timergroup* x = found->second;
80                 for (timergroup::iterator y = x->begin(); y != x->end(); y++)
81                 {
82                         InspTimer* n = *y;
83                         if (n == T)
84                         {
85                                 DELETE(n);
86                                 x->erase(y);
87                                 if (!x->size())
88                                 {
89                                         Timers.erase(found);
90                                         DELETE(x);
91                                 }
92                                 return;
93                         }
94                 }
95         }
96 }
97
98 /** Because some muppets may do odd things, and their ircd may lock up due
99  * to crappy 3rd party modules, or they may change their system time a bit,
100  * this accounts for shifts of up to 120 secs by looking behind for missed
101  * timers and executing them. This is only executed once every 5 secs.
102  * If you move your clock BACK, and your timers move further ahead as a result,
103  * then tough titty you'll just have to wait.
104  */
105 void TimerManager::TickMissedTimers(time_t TIME)
106 {
107         for (time_t n = TIME-1; n > TIME-120; n--)
108                 this->TickTimers(TIME);
109 }
110
111 void TimerManager::AddTimer(InspTimer* T, long secs_from_now)
112 {
113         timergroup* x = NULL;
114
115         int time_to_trigger = 0;
116         if (!secs_from_now)
117                 time_to_trigger = T->GetTimer();
118         else
119                 time_to_trigger = secs_from_now + ServerInstance->Time();
120
121         timerlist::iterator found = Timers.find(time_to_trigger);
122
123         if (found != Timers.end())
124         {
125                 x = found->second;
126         }
127         else
128         {
129                 x = new timergroup;
130                 Timers[time_to_trigger] = x;
131         }
132
133         x->push_back(T);
134 }
135