summaryrefslogtreecommitdiff
path: root/Libraries/LibCore
diff options
context:
space:
mode:
authorSergey Bugaev <bugaevc@serenityos.org>2020-05-15 18:21:40 +0300
committerAndreas Kling <kling@serenityos.org>2020-05-15 17:41:54 +0200
commit345fbd1fc1ecffbe6e0d9849373f7af3cbf44a23 (patch)
treef88834a60248398a754b5ffce1983c5f985185c6 /Libraries/LibCore
parentb8fef58c0c5db8f8a22667c846fa1a8ff8d5d5e1 (diff)
downloadserenity-345fbd1fc1ecffbe6e0d9849373f7af3cbf44a23.zip
LibCore: Fix timer expiration processing
The previous code did not account for the case when there are timers present, but none are enabled, and used a zero polling timeout. Fixes https://github.com/SerenityOS/serenity/issues/2222
Diffstat (limited to 'Libraries/LibCore')
-rw-r--r--Libraries/LibCore/EventLoop.cpp19
-rw-r--r--Libraries/LibCore/EventLoop.h2
2 files changed, 9 insertions, 12 deletions
diff --git a/Libraries/LibCore/EventLoop.cpp b/Libraries/LibCore/EventLoop.cpp
index 272ca0b1d4..ca745468e0 100644
--- a/Libraries/LibCore/EventLoop.cpp
+++ b/Libraries/LibCore/EventLoop.cpp
@@ -415,14 +415,14 @@ void EventLoop::wait_for_event(WaitMode mode)
timeval now;
struct timeval timeout = { 0, 0 };
bool should_wait_forever = false;
- if (mode == WaitMode::WaitForEvents) {
- if (!s_timers->is_empty() && queued_events_is_empty) {
+ if (mode == WaitMode::WaitForEvents && queued_events_is_empty) {
+ auto next_timer_expiration = get_next_timer_expiration();
+ if (next_timer_expiration.has_value()) {
timespec now_spec;
clock_gettime(CLOCK_MONOTONIC, &now_spec);
now.tv_sec = now_spec.tv_sec;
now.tv_usec = now_spec.tv_nsec / 1000;
- get_next_timer_expiration(timeout);
- timeval_sub(timeout, now, timeout);
+ timeval_sub(next_timer_expiration.value(), now, timeout);
if (timeout.tv_sec < 0) {
timeout.tv_sec = 0;
timeout.tv_usec = 0;
@@ -430,8 +430,6 @@ void EventLoop::wait_for_event(WaitMode mode)
} else {
should_wait_forever = true;
}
- } else {
- should_wait_forever = false;
}
int marked_fd_count = Core::safe_syscall(select, max_fd + 1, &rfds, &wfds, nullptr, should_wait_forever ? nullptr : &timeout);
@@ -500,10 +498,9 @@ void EventLoopTimer::reload(const timeval& now)
fire_time.tv_usec += (interval % 1000) * 1000;
}
-void EventLoop::get_next_timer_expiration(timeval& soonest)
+Optional<struct timeval> EventLoop::get_next_timer_expiration()
{
- ASSERT(!s_timers->is_empty());
- bool has_checked_any = false;
+ Optional<struct timeval> soonest {};
for (auto& it : *s_timers) {
auto& fire_time = it.value->fire_time;
if (it.value->fire_when_not_visible == TimerShouldFireWhenNotVisible::No
@@ -511,10 +508,10 @@ void EventLoop::get_next_timer_expiration(timeval& soonest)
&& !it.value->owner->is_visible_for_timer_purposes()) {
continue;
}
- if (!has_checked_any || fire_time.tv_sec < soonest.tv_sec || (fire_time.tv_sec == soonest.tv_sec && fire_time.tv_usec < soonest.tv_usec))
+ if (!soonest.has_value() || fire_time.tv_sec < soonest.value().tv_sec || (fire_time.tv_sec == soonest.value().tv_sec && fire_time.tv_usec < soonest.value().tv_usec))
soonest = fire_time;
- has_checked_any = true;
}
+ return soonest;
}
int EventLoop::register_timer(Object& object, int milliseconds, bool should_reload, TimerShouldFireWhenNotVisible fire_when_not_visible)
diff --git a/Libraries/LibCore/EventLoop.h b/Libraries/LibCore/EventLoop.h
index e1f4891ba6..b122bdf860 100644
--- a/Libraries/LibCore/EventLoop.h
+++ b/Libraries/LibCore/EventLoop.h
@@ -77,7 +77,7 @@ public:
private:
void wait_for_event(WaitMode);
- void get_next_timer_expiration(timeval&);
+ Optional<struct timeval> get_next_timer_expiration();
struct QueuedEvent {
AK_MAKE_NONCOPYABLE(QueuedEvent);