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