kernel: Add a timer queue with more versatility than simple alarm()
All checks were successful
continuous-integration/drone/push Build is passing
All checks were successful
continuous-integration/drone/push Build is passing
This commit is contained in:
parent
54ec441000
commit
dfebdce689
@ -25,6 +25,7 @@ set(SOURCES
|
||||
src/thread/Thread.cpp
|
||||
src/thread/ThreadImage.cpp
|
||||
src/thread/Scheduler.cpp
|
||||
src/thread/Timer.cpp
|
||||
src/sys/Syscall.cpp
|
||||
src/sys/exit.cpp
|
||||
src/sys/clock_gettime.cpp
|
||||
|
@ -1,6 +1,7 @@
|
||||
#include "Pledge.h"
|
||||
#include "sys/Syscall.h"
|
||||
#include "thread/Scheduler.h"
|
||||
#include "thread/Timer.h"
|
||||
|
||||
Result<u64> sys_alarm(Registers*, SyscallArgs args)
|
||||
{
|
||||
@ -10,9 +11,16 @@ Result<u64> sys_alarm(Registers*, SyscallArgs args)
|
||||
|
||||
TRY(check_pledge(current, Promise::p_stdio));
|
||||
|
||||
u64 time_left = current->alarm_ticks_left;
|
||||
u64 ticks_left = current->timer ? current->timer->ticks_left() : 0;
|
||||
|
||||
current->alarm_ticks_left = seconds * 1000;
|
||||
if (current->timer) Scheduler::remove_from_timer_queue(current->timer);
|
||||
else
|
||||
current->timer = TRY(make<Scheduler::Timer>());
|
||||
|
||||
return time_left * 1000;
|
||||
current->timer->total_ticks = seconds * 1000;
|
||||
current->timer->thread = current;
|
||||
|
||||
Scheduler::add_to_timer_queue(current->timer);
|
||||
|
||||
return ticks_left * 1000;
|
||||
}
|
||||
|
@ -5,6 +5,7 @@
|
||||
#include "binfmt/ELF.h"
|
||||
#include "memory/MemoryManager.h"
|
||||
#include "thread/ThreadImage.h"
|
||||
#include "thread/Timer.h"
|
||||
#include <luna/Alignment.h>
|
||||
#include <luna/ScopeGuard.h>
|
||||
#include <luna/Stack.h>
|
||||
@ -216,6 +217,12 @@ namespace Scheduler
|
||||
MemoryManager::unmap_owned_and_free_vm(stack.bottom(), stack.bytes() / ARCH_PAGE_SIZE).release_value();
|
||||
}
|
||||
|
||||
if (thread->timer)
|
||||
{
|
||||
Scheduler::remove_from_timer_queue(thread->timer);
|
||||
delete thread->timer;
|
||||
}
|
||||
|
||||
delete thread;
|
||||
|
||||
CPU::enable_interrupts();
|
||||
@ -293,6 +300,8 @@ namespace Scheduler
|
||||
{
|
||||
CPU::disable_interrupts();
|
||||
|
||||
tick_queue();
|
||||
|
||||
if (is_in_kernel(regs)) g_current->kernel_ticks_self++;
|
||||
else
|
||||
g_current->user_ticks_self++;
|
||||
@ -305,8 +314,6 @@ namespace Scheduler
|
||||
{
|
||||
if (thread->sleep_ticks_left == 0 || --thread->sleep_ticks_left == 0) thread->wake_up();
|
||||
}
|
||||
|
||||
if (thread->alarm_ticks_left && --thread->alarm_ticks_left == 0) thread->send_signal(SIGALRM);
|
||||
}
|
||||
|
||||
if (!g_current->ticks_left) switch_task(regs);
|
||||
|
@ -19,6 +19,11 @@
|
||||
#error "Unknown architecture."
|
||||
#endif
|
||||
|
||||
namespace Scheduler
|
||||
{
|
||||
class Timer;
|
||||
}
|
||||
|
||||
enum class ThreadState
|
||||
{
|
||||
None,
|
||||
@ -60,7 +65,6 @@ struct Thread : public LinkedListNode<Thread>
|
||||
|
||||
u64 ticks_left;
|
||||
u64 sleep_ticks_left;
|
||||
u64 alarm_ticks_left { 0 };
|
||||
|
||||
int promises { -1 };
|
||||
int execpromises { -1 };
|
||||
@ -97,6 +101,8 @@ struct Thread : public LinkedListNode<Thread>
|
||||
|
||||
mode_t umask { 0 };
|
||||
|
||||
Scheduler::Timer* timer { nullptr };
|
||||
|
||||
StaticString<128> cmdline;
|
||||
|
||||
String current_directory_path = {};
|
||||
|
72
kernel/src/thread/Timer.cpp
Normal file
72
kernel/src/thread/Timer.cpp
Normal file
@ -0,0 +1,72 @@
|
||||
#include "thread/Timer.h"
|
||||
#include "Log.h"
|
||||
|
||||
static LinkedList<Scheduler::Timer> g_timer_queue;
|
||||
|
||||
namespace Scheduler
|
||||
{
|
||||
void add_to_timer_queue(Timer* timer)
|
||||
{
|
||||
timer->delta_ticks = timer->total_ticks;
|
||||
|
||||
for (auto* t : g_timer_queue)
|
||||
{
|
||||
if (timer->delta_ticks <= t->delta_ticks)
|
||||
{
|
||||
t->delta_ticks -= timer->delta_ticks;
|
||||
g_timer_queue.add_before(t, timer);
|
||||
return;
|
||||
}
|
||||
timer->delta_ticks -= t->delta_ticks;
|
||||
}
|
||||
|
||||
g_timer_queue.append(timer);
|
||||
}
|
||||
|
||||
void remove_from_timer_queue(Timer* timer)
|
||||
{
|
||||
auto maybe_next = g_timer_queue.next(timer);
|
||||
if (maybe_next.has_value())
|
||||
{
|
||||
auto next = maybe_next.value();
|
||||
next->delta_ticks += timer->delta_ticks;
|
||||
}
|
||||
g_timer_queue.remove(timer);
|
||||
}
|
||||
|
||||
void tick_queue()
|
||||
{
|
||||
auto maybe_first = g_timer_queue.first();
|
||||
if (!maybe_first.has_value()) return;
|
||||
|
||||
auto first = *maybe_first;
|
||||
first->delta_ticks--;
|
||||
|
||||
LinkedList<Scheduler::Timer> timers_to_be_restarted;
|
||||
|
||||
g_timer_queue.delayed_for_each([&](Timer* t) {
|
||||
if (t->delta_ticks == 0)
|
||||
{
|
||||
g_timer_queue.remove(t);
|
||||
t->thread->send_signal(t->signo);
|
||||
if (t->restart) timers_to_be_restarted.append(t);
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
});
|
||||
|
||||
timers_to_be_restarted.consume([](Timer* t) { add_to_timer_queue(t); });
|
||||
}
|
||||
|
||||
u64 Timer::ticks_left()
|
||||
{
|
||||
u64 total = 0;
|
||||
for (auto* t : g_timer_queue)
|
||||
{
|
||||
total += t->delta_ticks;
|
||||
if (t == this) break;
|
||||
}
|
||||
return total;
|
||||
}
|
||||
}
|
23
kernel/src/thread/Timer.h
Normal file
23
kernel/src/thread/Timer.h
Normal file
@ -0,0 +1,23 @@
|
||||
#pragma once
|
||||
#include "thread/Thread.h"
|
||||
#include <luna/LinkedList.h>
|
||||
|
||||
namespace Scheduler
|
||||
{
|
||||
class Timer : public LinkedListNode<Timer>
|
||||
{
|
||||
public:
|
||||
u64 delta_ticks;
|
||||
u64 total_ticks;
|
||||
Thread* thread;
|
||||
int signo { SIGALRM };
|
||||
bool restart { false };
|
||||
|
||||
u64 ticks_left();
|
||||
};
|
||||
|
||||
void add_to_timer_queue(Timer* timer);
|
||||
void remove_from_timer_queue(Timer* timer);
|
||||
|
||||
void tick_queue();
|
||||
}
|
Loading…
Reference in New Issue
Block a user