diff options
author | Mathias Gumz <akira at fluxbox dot org> | 2013-01-12 08:24:11 (GMT) |
---|---|---|
committer | Mathias Gumz <akira at fluxbox dot org> | 2013-01-12 08:24:11 (GMT) |
commit | 4d307dcd10af9d817ff5c05fc40ae7487564cb31 (patch) | |
tree | 97d4e32d99c90ee5fe1e5036ad15dedd280a09b4 | |
parent | 06655f6d7ff2af0626d37f083b927af2af1be529 (diff) | |
download | fluxbox-4d307dcd10af9d817ff5c05fc40ae7487564cb31.zip fluxbox-4d307dcd10af9d817ff5c05fc40ae7487564cb31.tar.bz2 |
Fix bug: handle the list of Timers not in-place
With commit 541c8c4 we switched from an (manually) ordered list to a
std::set<> to handle the active timers. The code which checks for overdue
timers now traverses and modifies the std::set<> in place. This might
lead to an infinite loop. Examples of such bad behavior are "flickering of
the tooltip" (bug #3590078) or crashes (bug #3600143) or just insanely high
cpu load when autoraising windows or submenus.
We now make a copy of the std::set<> traverse this instead of the original.
-rw-r--r-- | src/FbTk/Timer.cc | 32 |
1 files changed, 18 insertions, 14 deletions
diff --git a/src/FbTk/Timer.cc b/src/FbTk/Timer.cc index f63ea38..dd736dd 100644 --- a/src/FbTk/Timer.cc +++ b/src/FbTk/Timer.cc | |||
@@ -52,6 +52,7 @@ | |||
52 | #endif | 52 | #endif |
53 | 53 | ||
54 | #include <cstdio> | 54 | #include <cstdio> |
55 | #include <vector> | ||
55 | #include <set> | 56 | #include <set> |
56 | 57 | ||
57 | 58 | ||
@@ -195,32 +196,35 @@ void Timer::updateTimers(int fd) { | |||
195 | return; | 196 | return; |
196 | } | 197 | } |
197 | 198 | ||
199 | // stoping / restarting the timers modifies the list in an upredictable | ||
200 | // way. to avoid problems such as infinite loops we save the current | ||
201 | // (ordered) list of timers into a list and work on it. | ||
202 | |||
203 | ssize_t i; | ||
204 | const ssize_t ts = s_timerlist.size(); | ||
205 | std::vector<FbTk::Timer*> timers; | ||
206 | |||
207 | timers.reserve(ts); | ||
208 | for (it = s_timerlist.begin(); it != s_timerlist.end(); ++it ) { | ||
209 | timers.push_back(*it); | ||
210 | } | ||
211 | |||
198 | now = FbTime::now(); | 212 | now = FbTime::now(); |
199 | for (it = s_timerlist.begin(); it != s_timerlist.end(); ) { | 213 | for (i = 0; i < ts; ++i) { |
214 | |||
215 | FbTk::Timer* t = timers[i]; | ||
200 | 216 | ||
201 | // t->fireTimeout() might add timers to the list | ||
202 | // this invalidates 'it'. thus we store the current timer | ||
203 | Timer* t = *it; | ||
204 | if (now < t->getEndTime()) { | 217 | if (now < t->getEndTime()) { |
205 | break; | 218 | break; |
206 | } | 219 | } |
207 | 220 | ||
208 | t->fireTimeout(); | 221 | t->fireTimeout(); |
209 | 222 | t->stop(); | |
210 | // find the iterator to the timer again | ||
211 | // and continue working on the list | ||
212 | it = s_timerlist.find(t); | ||
213 | it++; | ||
214 | s_timerlist.erase(t); | ||
215 | 223 | ||
216 | if (! t->doOnce()) { // restart the current timer | 224 | if (! t->doOnce()) { // restart the current timer |
217 | t->m_timing = false; | ||
218 | t->start(); | 225 | t->start(); |
219 | } else { | ||
220 | t->stop(); | ||
221 | } | 226 | } |
222 | } | 227 | } |
223 | |||
224 | } | 228 | } |
225 | 229 | ||
226 | 230 | ||