Skip to content

Commit

Permalink
Kernel: Use TimerQueue for SIGALRM
Browse files Browse the repository at this point in the history
  • Loading branch information
tomuta authored and awesomekling committed Dec 2, 2020
1 parent 601a688 commit 4c1e27e
Show file tree
Hide file tree
Showing 6 changed files with 43 additions and 27 deletions.
3 changes: 3 additions & 0 deletions Kernel/Process.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down Expand Up @@ -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;
Expand Down
2 changes: 1 addition & 1 deletion Kernel/Process.h
Original file line number Diff line number Diff line change
Expand Up @@ -611,7 +611,7 @@ class Process
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 };

Expand Down
9 changes: 0 additions & 9 deletions Kernel/Scheduler.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down
24 changes: 17 additions & 7 deletions Kernel/Syscalls/alarm.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}

Expand Down
26 changes: 17 additions & 9 deletions Kernel/TimerQueue.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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()
Expand Down
6 changes: 5 additions & 1 deletion Kernel/TimerQueue.h
Original file line number Diff line number Diff line change
Expand Up @@ -53,9 +53,12 @@ class Timer : public RefCounted<Timer>
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 };
Expand Down Expand Up @@ -88,14 +91,15 @@ class TimerQueue {
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());
}
void fire();

private:
bool cancel_timer(Timer&);
void remove_timer_locked(Timer&);
void update_next_timer_due();
void add_timer_locked(NonnullRefPtr<Timer>);

Expand Down

0 comments on commit 4c1e27e

Please sign in to comment.