mirror of
https://github.com/LadybirdBrowser/ladybird.git
synced 2025-06-11 10:18:15 +09:00
Kernel: Use TimerQueue for SIGALRM
This commit is contained in:
parent
601a688b6f
commit
4c1e27ec65
Notes:
sideshowbarker
2024-07-19 01:05:49 +09:00
Author: https://github.com/tomuta
Commit: 4c1e27ec65
Pull-request: https://github.com/SerenityOS/serenity/pull/4298
6 changed files with 43 additions and 27 deletions
|
@ -367,6 +367,7 @@ Process::Process(RefPtr<Thread>& first_thread, const String& name, uid_t uid, gi
|
||||||
Process::~Process()
|
Process::~Process()
|
||||||
{
|
{
|
||||||
ASSERT(thread_count() == 0); // all threads should have been finalized
|
ASSERT(thread_count() == 0); // all threads should have been finalized
|
||||||
|
ASSERT(!m_alarm_timer);
|
||||||
|
|
||||||
{
|
{
|
||||||
ScopedSpinLock processses_lock(g_processes_lock);
|
ScopedSpinLock processses_lock(g_processes_lock);
|
||||||
|
@ -596,6 +597,8 @@ void Process::finalize(Thread& last_thread)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (m_alarm_timer)
|
||||||
|
TimerQueue::the().cancel_timer(m_alarm_timer.release_nonnull());
|
||||||
m_fds.clear();
|
m_fds.clear();
|
||||||
m_tty = nullptr;
|
m_tty = nullptr;
|
||||||
m_executable = nullptr;
|
m_executable = nullptr;
|
||||||
|
|
|
@ -611,7 +611,7 @@ private:
|
||||||
Lock m_big_lock { "Process" };
|
Lock m_big_lock { "Process" };
|
||||||
mutable SpinLock<u32> m_lock;
|
mutable SpinLock<u32> m_lock;
|
||||||
|
|
||||||
u64 m_alarm_deadline { 0 };
|
RefPtr<Timer> m_alarm_timer;
|
||||||
|
|
||||||
int m_icon_id { -1 };
|
int m_icon_id { -1 };
|
||||||
|
|
||||||
|
|
|
@ -137,15 +137,6 @@ bool Scheduler::pick_next()
|
||||||
current_thread->set_state(Thread::Dying);
|
current_thread->set_state(Thread::Dying);
|
||||||
}
|
}
|
||||||
|
|
||||||
Process::for_each([&](Process& process) {
|
|
||||||
if (process.m_alarm_deadline && TimeManagement::the().uptime_ms() > process.m_alarm_deadline) {
|
|
||||||
process.m_alarm_deadline = 0;
|
|
||||||
// FIXME: Should we observe this signal somehow?
|
|
||||||
(void)process.send_signal(SIGALRM, nullptr);
|
|
||||||
}
|
|
||||||
return IterationDecision::Continue;
|
|
||||||
});
|
|
||||||
|
|
||||||
#ifdef SCHEDULER_RUNNABLE_DEBUG
|
#ifdef SCHEDULER_RUNNABLE_DEBUG
|
||||||
dbg() << "Scheduler[" << Processor::current().id() << "]: Non-runnables:";
|
dbg() << "Scheduler[" << Processor::current().id() << "]: Non-runnables:";
|
||||||
Scheduler::for_each_nonrunnable([&](Thread& thread) -> IterationDecision {
|
Scheduler::for_each_nonrunnable([&](Thread& thread) -> IterationDecision {
|
||||||
|
|
|
@ -33,15 +33,25 @@ unsigned Process::sys$alarm(unsigned seconds)
|
||||||
{
|
{
|
||||||
REQUIRE_PROMISE(stdio);
|
REQUIRE_PROMISE(stdio);
|
||||||
unsigned previous_alarm_remaining = 0;
|
unsigned previous_alarm_remaining = 0;
|
||||||
auto uptime = TimeManagement::the().uptime_ms();
|
if (auto alarm_timer = move(m_alarm_timer)) {
|
||||||
if (m_alarm_deadline && m_alarm_deadline > uptime) {
|
if (TimerQueue::the().cancel_timer(*alarm_timer)) {
|
||||||
previous_alarm_remaining = m_alarm_deadline - uptime;
|
// The timer hasn't fired. Round up the remaining time (if any)
|
||||||
|
timespec remaining;
|
||||||
|
timespec_add(alarm_timer->remaining(), { 0, 1000000000 - 1 }, remaining);
|
||||||
|
previous_alarm_remaining = remaining.tv_sec;
|
||||||
|
}
|
||||||
|
// We had an existing alarm, must return a non-zero value here!
|
||||||
|
if (previous_alarm_remaining == 0)
|
||||||
|
previous_alarm_remaining = 1;
|
||||||
}
|
}
|
||||||
if (!seconds) {
|
|
||||||
m_alarm_deadline = 0;
|
if (seconds > 0) {
|
||||||
return previous_alarm_remaining;
|
auto deadline = TimeManagement::the().monotonic_time(); // TODO: should be using CLOCK_REALTIME
|
||||||
|
timespec_add(deadline, { seconds, 0 }, deadline);
|
||||||
|
m_alarm_timer = TimerQueue::the().add_timer_without_id(deadline, [this]() {
|
||||||
|
(void)send_signal(SIGALRM, nullptr);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
m_alarm_deadline = uptime + seconds * 1000;
|
|
||||||
return previous_alarm_remaining;
|
return previous_alarm_remaining;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -38,6 +38,13 @@ namespace Kernel {
|
||||||
static AK::Singleton<TimerQueue> s_the;
|
static AK::Singleton<TimerQueue> s_the;
|
||||||
static SpinLock<u8> g_timerqueue_lock;
|
static SpinLock<u8> g_timerqueue_lock;
|
||||||
|
|
||||||
|
timespec Timer::remaining() const
|
||||||
|
{
|
||||||
|
if (m_remaining == 0)
|
||||||
|
return {};
|
||||||
|
return TimerQueue::the().ticks_to_time(m_remaining);
|
||||||
|
}
|
||||||
|
|
||||||
TimerQueue& TimerQueue::the()
|
TimerQueue& TimerQueue::the()
|
||||||
{
|
{
|
||||||
return *s_the;
|
return *s_the;
|
||||||
|
@ -164,14 +171,7 @@ bool TimerQueue::cancel_timer(TimerId id)
|
||||||
}
|
}
|
||||||
|
|
||||||
ASSERT(found_timer);
|
ASSERT(found_timer);
|
||||||
bool was_next_timer = (m_timer_queue.head() == found_timer);
|
remove_timer_locked(*found_timer);
|
||||||
|
|
||||||
m_timer_queue.remove(found_timer);
|
|
||||||
found_timer->set_queued(false);
|
|
||||||
|
|
||||||
if (was_next_timer)
|
|
||||||
update_next_timer_due();
|
|
||||||
|
|
||||||
lock.unlock();
|
lock.unlock();
|
||||||
found_timer->unref();
|
found_timer->unref();
|
||||||
return true;
|
return true;
|
||||||
|
@ -199,13 +199,21 @@ bool TimerQueue::cancel_timer(Timer& timer)
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
remove_timer_locked(timer);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void TimerQueue::remove_timer_locked(Timer& timer)
|
||||||
|
{
|
||||||
bool was_next_timer = (m_timer_queue.head() == &timer);
|
bool was_next_timer = (m_timer_queue.head() == &timer);
|
||||||
m_timer_queue.remove(&timer);
|
m_timer_queue.remove(&timer);
|
||||||
timer.set_queued(false);
|
timer.set_queued(false);
|
||||||
|
auto now = TimeManagement::the().monotonic_ticks();
|
||||||
|
if (timer.m_expires > now)
|
||||||
|
timer.m_remaining = timer.m_expires - now;
|
||||||
|
|
||||||
if (was_next_timer)
|
if (was_next_timer)
|
||||||
update_next_timer_due();
|
update_next_timer_due();
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void TimerQueue::fire()
|
void TimerQueue::fire()
|
||||||
|
|
|
@ -53,9 +53,12 @@ public:
|
||||||
ASSERT(!is_queued());
|
ASSERT(!is_queued());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
timespec remaining() const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
TimerId m_id;
|
TimerId m_id;
|
||||||
u64 m_expires;
|
u64 m_expires;
|
||||||
|
u64 m_remaining { 0 };
|
||||||
Function<void()> m_callback;
|
Function<void()> m_callback;
|
||||||
Timer* m_next { nullptr };
|
Timer* m_next { nullptr };
|
||||||
Timer* m_prev { nullptr };
|
Timer* m_prev { nullptr };
|
||||||
|
@ -88,6 +91,7 @@ public:
|
||||||
RefPtr<Timer> add_timer_without_id(const timespec& timeout, Function<void()>&& callback);
|
RefPtr<Timer> add_timer_without_id(const timespec& timeout, Function<void()>&& callback);
|
||||||
TimerId add_timer(timeval& timeout, Function<void()>&& callback);
|
TimerId add_timer(timeval& timeout, Function<void()>&& callback);
|
||||||
bool cancel_timer(TimerId id);
|
bool cancel_timer(TimerId id);
|
||||||
|
bool cancel_timer(Timer&);
|
||||||
bool cancel_timer(NonnullRefPtr<Timer>&& timer)
|
bool cancel_timer(NonnullRefPtr<Timer>&& timer)
|
||||||
{
|
{
|
||||||
return cancel_timer(timer.leak_ref());
|
return cancel_timer(timer.leak_ref());
|
||||||
|
@ -95,7 +99,7 @@ public:
|
||||||
void fire();
|
void fire();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
bool cancel_timer(Timer&);
|
void remove_timer_locked(Timer&);
|
||||||
void update_next_timer_due();
|
void update_next_timer_due();
|
||||||
void add_timer_locked(NonnullRefPtr<Timer>);
|
void add_timer_locked(NonnullRefPtr<Timer>);
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue