mirror of
https://github.com/LadybirdBrowser/ladybird.git
synced 2024-11-10 13:00:29 +03:00
fc91eb365d
The sys$alarm() syscall has logic to cache a m_alarm_timer to avoid allocating a new timer for every call to alarm. Unfortunately that logic was broken, and there were conditions in which we could have a timer allocated, but it was no longer on the timer queue, and we would attempt to cancel that timer again resulting in an infinite loop waiting for the timers callback to fire. To fix this, we need to track if a timer is currently in use or not, allowing us to avoid attempting to cancel inactive timers. Luke and Tom did the initial investigation, I just happened to have time to write a repro and attempt a fix, so I'm adding them as the as co-authors of this commit. Co-authored-by: Luke <luke.wilde@live.co.uk> Co-authored-by: Tom <tomut@yahoo.com>
47 lines
1.6 KiB
C++
47 lines
1.6 KiB
C++
/*
|
|
* Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org>
|
|
*
|
|
* SPDX-License-Identifier: BSD-2-Clause
|
|
*/
|
|
|
|
#include <Kernel/Process.h>
|
|
#include <Kernel/Time/TimeManagement.h>
|
|
|
|
namespace Kernel {
|
|
|
|
KResultOr<FlatPtr> Process::sys$alarm(unsigned seconds)
|
|
{
|
|
VERIFY_PROCESS_BIG_LOCK_ACQUIRED(this);
|
|
REQUIRE_PROMISE(stdio);
|
|
unsigned previous_alarm_remaining = 0;
|
|
if (m_alarm_timer) {
|
|
bool was_in_use = false;
|
|
if (TimerQueue::the().cancel_timer(*m_alarm_timer, &was_in_use)) {
|
|
// The timer hasn't fired. Round up the remaining time (if any)
|
|
Time remaining = m_alarm_timer->remaining() + Time::from_nanoseconds(999'999'999);
|
|
previous_alarm_remaining = remaining.to_truncated_seconds();
|
|
}
|
|
// We had an existing alarm, must return a non-zero value here!
|
|
if (was_in_use && previous_alarm_remaining == 0)
|
|
previous_alarm_remaining = 1;
|
|
}
|
|
|
|
if (seconds > 0) {
|
|
auto deadline = TimeManagement::the().current_time(CLOCK_REALTIME_COARSE);
|
|
deadline = deadline + Time::from_seconds(seconds);
|
|
if (!m_alarm_timer) {
|
|
m_alarm_timer = adopt_ref_if_nonnull(new (nothrow) Timer());
|
|
if (!m_alarm_timer)
|
|
return ENOMEM;
|
|
}
|
|
auto timer_was_added = TimerQueue::the().add_timer_without_id(*m_alarm_timer, CLOCK_REALTIME_COARSE, deadline, [this]() {
|
|
[[maybe_unused]] auto rc = send_signal(SIGALRM, nullptr);
|
|
});
|
|
if (!timer_was_added)
|
|
return ENOMEM;
|
|
}
|
|
return previous_alarm_remaining;
|
|
}
|
|
|
|
}
|