Kernel: Use TimerQueue for SIGALRM

This commit is contained in:
Tom 2020-12-01 15:44:52 -07:00 committed by Andreas Kling
parent 601a688b6f
commit 4c1e27ec65
Notes: sideshowbarker 2024-07-19 01:05:49 +09:00
6 changed files with 43 additions and 27 deletions

View File

@ -367,6 +367,7 @@ Process::Process(RefPtr<Thread>& first_thread, const String& name, uid_t uid, gi
Process::~Process()
{
ASSERT(thread_count() == 0); // all threads should have been finalized
ASSERT(!m_alarm_timer);
{
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_tty = nullptr;
m_executable = nullptr;

View File

@ -611,7 +611,7 @@ private:
Lock m_big_lock { "Process" };
mutable SpinLock<u32> m_lock;
u64 m_alarm_deadline { 0 };
RefPtr<Timer> m_alarm_timer;
int m_icon_id { -1 };

View File

@ -137,15 +137,6 @@ bool Scheduler::pick_next()
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
dbg() << "Scheduler[" << Processor::current().id() << "]: Non-runnables:";
Scheduler::for_each_nonrunnable([&](Thread& thread) -> IterationDecision {

View File

@ -33,15 +33,25 @@ unsigned Process::sys$alarm(unsigned seconds)
{
REQUIRE_PROMISE(stdio);
unsigned previous_alarm_remaining = 0;
auto uptime = TimeManagement::the().uptime_ms();
if (m_alarm_deadline && m_alarm_deadline > uptime) {
previous_alarm_remaining = m_alarm_deadline - uptime;
if (auto alarm_timer = move(m_alarm_timer)) {
if (TimerQueue::the().cancel_timer(*alarm_timer)) {
// 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;
return previous_alarm_remaining;
if (seconds > 0) {
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;
}

View File

@ -38,6 +38,13 @@ namespace Kernel {
static AK::Singleton<TimerQueue> s_the;
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()
{
return *s_the;
@ -164,14 +171,7 @@ bool TimerQueue::cancel_timer(TimerId id)
}
ASSERT(found_timer);
bool was_next_timer = (m_timer_queue.head() == found_timer);
m_timer_queue.remove(found_timer);
found_timer->set_queued(false);
if (was_next_timer)
update_next_timer_due();
remove_timer_locked(*found_timer);
lock.unlock();
found_timer->unref();
return true;
@ -199,13 +199,21 @@ bool TimerQueue::cancel_timer(Timer& timer)
return false;
}
remove_timer_locked(timer);
return true;
}
void TimerQueue::remove_timer_locked(Timer& timer)
{
bool was_next_timer = (m_timer_queue.head() == &timer);
m_timer_queue.remove(&timer);
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)
update_next_timer_due();
return true;
}
void TimerQueue::fire()

View File

@ -53,9 +53,12 @@ public:
ASSERT(!is_queued());
}
timespec remaining() const;
private:
TimerId m_id;
u64 m_expires;
u64 m_remaining { 0 };
Function<void()> m_callback;
Timer* m_next { nullptr };
Timer* m_prev { nullptr };
@ -88,6 +91,7 @@ public:
RefPtr<Timer> add_timer_without_id(const timespec& timeout, Function<void()>&& callback);
TimerId add_timer(timeval& timeout, Function<void()>&& callback);
bool cancel_timer(TimerId id);
bool cancel_timer(Timer&);
bool cancel_timer(NonnullRefPtr<Timer>&& timer)
{
return cancel_timer(timer.leak_ref());
@ -95,7 +99,7 @@ public:
void fire();
private:
bool cancel_timer(Timer&);
void remove_timer_locked(Timer&);
void update_next_timer_due();
void add_timer_locked(NonnullRefPtr<Timer>);