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/Thread.cpp
|
||||||
src/thread/ThreadImage.cpp
|
src/thread/ThreadImage.cpp
|
||||||
src/thread/Scheduler.cpp
|
src/thread/Scheduler.cpp
|
||||||
|
src/thread/Timer.cpp
|
||||||
src/sys/Syscall.cpp
|
src/sys/Syscall.cpp
|
||||||
src/sys/exit.cpp
|
src/sys/exit.cpp
|
||||||
src/sys/clock_gettime.cpp
|
src/sys/clock_gettime.cpp
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
#include "Pledge.h"
|
#include "Pledge.h"
|
||||||
#include "sys/Syscall.h"
|
#include "sys/Syscall.h"
|
||||||
#include "thread/Scheduler.h"
|
#include "thread/Scheduler.h"
|
||||||
|
#include "thread/Timer.h"
|
||||||
|
|
||||||
Result<u64> sys_alarm(Registers*, SyscallArgs args)
|
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));
|
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 "binfmt/ELF.h"
|
||||||
#include "memory/MemoryManager.h"
|
#include "memory/MemoryManager.h"
|
||||||
#include "thread/ThreadImage.h"
|
#include "thread/ThreadImage.h"
|
||||||
|
#include "thread/Timer.h"
|
||||||
#include <luna/Alignment.h>
|
#include <luna/Alignment.h>
|
||||||
#include <luna/ScopeGuard.h>
|
#include <luna/ScopeGuard.h>
|
||||||
#include <luna/Stack.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();
|
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;
|
delete thread;
|
||||||
|
|
||||||
CPU::enable_interrupts();
|
CPU::enable_interrupts();
|
||||||
@ -293,6 +300,8 @@ namespace Scheduler
|
|||||||
{
|
{
|
||||||
CPU::disable_interrupts();
|
CPU::disable_interrupts();
|
||||||
|
|
||||||
|
tick_queue();
|
||||||
|
|
||||||
if (is_in_kernel(regs)) g_current->kernel_ticks_self++;
|
if (is_in_kernel(regs)) g_current->kernel_ticks_self++;
|
||||||
else
|
else
|
||||||
g_current->user_ticks_self++;
|
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->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);
|
if (!g_current->ticks_left) switch_task(regs);
|
||||||
|
@ -19,6 +19,11 @@
|
|||||||
#error "Unknown architecture."
|
#error "Unknown architecture."
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
namespace Scheduler
|
||||||
|
{
|
||||||
|
class Timer;
|
||||||
|
}
|
||||||
|
|
||||||
enum class ThreadState
|
enum class ThreadState
|
||||||
{
|
{
|
||||||
None,
|
None,
|
||||||
@ -60,7 +65,6 @@ struct Thread : public LinkedListNode<Thread>
|
|||||||
|
|
||||||
u64 ticks_left;
|
u64 ticks_left;
|
||||||
u64 sleep_ticks_left;
|
u64 sleep_ticks_left;
|
||||||
u64 alarm_ticks_left { 0 };
|
|
||||||
|
|
||||||
int promises { -1 };
|
int promises { -1 };
|
||||||
int execpromises { -1 };
|
int execpromises { -1 };
|
||||||
@ -97,6 +101,8 @@ struct Thread : public LinkedListNode<Thread>
|
|||||||
|
|
||||||
mode_t umask { 0 };
|
mode_t umask { 0 };
|
||||||
|
|
||||||
|
Scheduler::Timer* timer { nullptr };
|
||||||
|
|
||||||
StaticString<128> cmdline;
|
StaticString<128> cmdline;
|
||||||
|
|
||||||
String current_directory_path = {};
|
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