]> git.netwichtig.de Git - user/henk/code/inspircd.git/blob - src/timer.cpp
Add and properly test the ability for an InspTimer to DelTimer itself from within...
[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() : CantDeleteHere(false)
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                                 }
91                                 return;
92                         }
93                 }
94         }
95 }
96
97 /** Because some muppets may do odd things, and their ircd may lock up due
98  * to crappy 3rd party modules, or they may change their system time a bit,
99  * this accounts for shifts of up to 120 secs by looking behind for missed
100  * timers and executing them. This is only executed once every 5 secs.
101  * If you move your clock BACK, and your timers move further ahead as a result,
102  * then tough titty you'll just have to wait.
103  */
104 void TimerManager::TickMissedTimers(time_t TIME)
105 {
106         /** See comment above in TickTimers
107          */
108         this->CantDeleteHere = true;
109
110         for (time_t n = TIME-1; n > TIME-120; n--)
111         {
112                 timerlist::iterator found = Timers.find(n);
113                 if (found != Timers.end())
114                 {
115                         timergroup* x = found->second;
116                         for (timergroup::iterator y = x->begin(); y != x->end(); y++)
117                         {
118                                 InspTimer* z = *y;
119                                 z->Tick(TIME);
120                                 if (z->GetRepeat())
121                                 {
122                                         AddTimer(z, z->GetSecs());
123                                 }
124                                 else
125                                 {
126                                         DELETE(z);
127                                 }
128                         }
129
130                         Timers.erase(found);
131                         DELETE(x);
132                 }
133         }
134
135         this->CantDeleteHere = false;
136 }
137
138 void TimerManager::AddTimer(InspTimer* T, long secs_from_now)
139 {
140         timergroup* x = NULL;
141
142         int time_to_trigger = 0;
143         if (!secs_from_now)
144                 time_to_trigger = T->GetTimer();
145         else
146                 time_to_trigger = secs_from_now + time(NULL);
147
148         timerlist::iterator found = Timers.find(time_to_trigger);
149
150         if (found != Timers.end())
151         {
152                 x = found->second;
153         }
154         else
155         {
156                 x = new timergroup;
157                 Timers[time_to_trigger] = x;
158         }
159
160         x->push_back(T);
161 }
162