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.
This commit is contained in:
parent
06655f6d7f
commit
4d307dcd10
1 changed files with 19 additions and 15 deletions
|
@ -52,6 +52,7 @@
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include <cstdio>
|
#include <cstdio>
|
||||||
|
#include <vector>
|
||||||
#include <set>
|
#include <set>
|
||||||
|
|
||||||
|
|
||||||
|
@ -195,32 +196,35 @@ void Timer::updateTimers(int fd) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
now = FbTime::now();
|
// stoping / restarting the timers modifies the list in an upredictable
|
||||||
for (it = s_timerlist.begin(); it != s_timerlist.end(); ) {
|
// way. to avoid problems such as infinite loops we save the current
|
||||||
|
// (ordered) list of timers into a list and work on it.
|
||||||
|
|
||||||
|
ssize_t i;
|
||||||
|
const ssize_t ts = s_timerlist.size();
|
||||||
|
std::vector<FbTk::Timer*> timers;
|
||||||
|
|
||||||
|
timers.reserve(ts);
|
||||||
|
for (it = s_timerlist.begin(); it != s_timerlist.end(); ++it ) {
|
||||||
|
timers.push_back(*it);
|
||||||
|
}
|
||||||
|
|
||||||
|
now = FbTime::now();
|
||||||
|
for (i = 0; i < ts; ++i) {
|
||||||
|
|
||||||
|
FbTk::Timer* t = timers[i];
|
||||||
|
|
||||||
// t->fireTimeout() might add timers to the list
|
|
||||||
// this invalidates 'it'. thus we store the current timer
|
|
||||||
Timer* t = *it;
|
|
||||||
if (now < t->getEndTime()) {
|
if (now < t->getEndTime()) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
t->fireTimeout();
|
t->fireTimeout();
|
||||||
|
t->stop();
|
||||||
// find the iterator to the timer again
|
|
||||||
// and continue working on the list
|
|
||||||
it = s_timerlist.find(t);
|
|
||||||
it++;
|
|
||||||
s_timerlist.erase(t);
|
|
||||||
|
|
||||||
if (! t->doOnce()) { // restart the current timer
|
if (! t->doOnce()) { // restart the current timer
|
||||||
t->m_timing = false;
|
|
||||||
t->start();
|
t->start();
|
||||||
} else {
|
|
||||||
t->stop();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue