]> git.netwichtig.de Git - user/henk/code/inspircd.git/blob - src/timer.cpp
DELETE() on the timergroup in DelTimer (small memory leak)
[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                                         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         /** See comment above in TickTimers
108          */
109         this->CantDeleteHere = true;
110
111         for (time_t n = TIME-1; n > TIME-120; n--)
112         {
113                 timerlist::iterator found = Timers.find(n);
114                 if (found != Timers.end())
115                 {
116                         timergroup* x = found->second;
117                         for (timergroup::iterator y = x->begin(); y != x->end(); y++)
118                         {
119                                 InspTimer* z = *y;
120                                 z->Tick(TIME);
121                                 if (z->GetRepeat())
122                                 {
123                                         AddTimer(z, z->GetSecs());
124                                 }
125                                 else
126                                 {
127                                         DELETE(z);
128                                 }
129                         }
130
131                         Timers.erase(found);
132                         DELETE(x);
133                 }
134         }
135
136         this->CantDeleteHere = false;
137 }
138
139 void TimerManager::AddTimer(InspTimer* T, long secs_from_now)
140 {
141         timergroup* x = NULL;
142
143         int time_to_trigger = 0;
144         if (!secs_from_now)
145                 time_to_trigger = T->GetTimer();
146         else
147                 time_to_trigger = secs_from_now + time(NULL);
148
149         timerlist::iterator found = Timers.find(time_to_trigger);
150
151         if (found != Timers.end())
152         {
153                 x = found->second;
154         }
155         else
156         {
157                 x = new timergroup;
158                 Timers[time_to_trigger] = x;
159         }
160
161         x->push_back(T);
162 }
163