kernel: Rework the entire time system to use modular clocks
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
e28e1c682c
commit
c4d2847da1
@ -19,13 +19,12 @@ set(SOURCES
|
|||||||
src/memory/SharedMemory.cpp
|
src/memory/SharedMemory.cpp
|
||||||
src/boot/Init.cpp
|
src/boot/Init.cpp
|
||||||
src/arch/Serial.cpp
|
src/arch/Serial.cpp
|
||||||
src/arch/Timer.cpp
|
|
||||||
src/arch/PCI.cpp
|
src/arch/PCI.cpp
|
||||||
src/lib/Mutex.cpp
|
src/lib/Mutex.cpp
|
||||||
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/thread/Clock.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
|
||||||
@ -93,7 +92,7 @@ if("${LUNA_ARCH}" MATCHES "x86_64")
|
|||||||
src/arch/x86_64/Serial.cpp
|
src/arch/x86_64/Serial.cpp
|
||||||
src/arch/x86_64/MMU.cpp
|
src/arch/x86_64/MMU.cpp
|
||||||
src/arch/x86_64/CPU.cpp
|
src/arch/x86_64/CPU.cpp
|
||||||
src/arch/x86_64/Timer.cpp
|
src/arch/x86_64/Clock.cpp
|
||||||
src/arch/x86_64/Thread.cpp
|
src/arch/x86_64/Thread.cpp
|
||||||
src/arch/x86_64/PCI.cpp
|
src/arch/x86_64/PCI.cpp
|
||||||
src/arch/x86_64/Keyboard.cpp
|
src/arch/x86_64/Keyboard.cpp
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
#include "Log.h"
|
#include "Log.h"
|
||||||
#include "arch/CPU.h"
|
#include "arch/CPU.h"
|
||||||
#include "arch/Serial.h"
|
#include "arch/Serial.h"
|
||||||
#include "arch/Timer.h"
|
#include "thread/Clock.h"
|
||||||
#include "video/TextConsole.h"
|
#include "video/TextConsole.h"
|
||||||
#include <luna/Format.h>
|
#include <luna/Format.h>
|
||||||
#include <luna/SourceLocation.h>
|
#include <luna/SourceLocation.h>
|
||||||
@ -35,9 +35,10 @@ static void log_serial(LogLevel level, const char* format, va_list origin)
|
|||||||
"\x1b[0m ",
|
"\x1b[0m ",
|
||||||
ansi_color_codes_per_log_level[(int)level], log_level_letters[(int)level]);
|
ansi_color_codes_per_log_level[(int)level], log_level_letters[(int)level]);
|
||||||
|
|
||||||
auto* time = Timer::monotonic_clock();
|
struct timespec time;
|
||||||
|
g_monotonic_clock.get_time(time);
|
||||||
|
|
||||||
Serial::printf("%4zu.%.3zu ", time->tv_sec, time->tv_nsec / 1'000'000);
|
Serial::printf("%4zu.%.3zu ", time.tv_sec, time.tv_nsec / 1'000'000);
|
||||||
|
|
||||||
// NOTE: We do this manually because of a lack of vprintf() in both Serial and TextConsole.
|
// NOTE: We do this manually because of a lack of vprintf() in both Serial and TextConsole.
|
||||||
cstyle_format(
|
cstyle_format(
|
||||||
|
@ -1,91 +0,0 @@
|
|||||||
#include "arch/Timer.h"
|
|
||||||
#include "Log.h"
|
|
||||||
#include "arch/Serial.h"
|
|
||||||
#include "boot/bootboot.h"
|
|
||||||
#include <luna/TypeTraits.h>
|
|
||||||
|
|
||||||
static struct timespec s_monotonic_clock = { 0, 0 };
|
|
||||||
static struct timespec s_realtime_clock;
|
|
||||||
|
|
||||||
static inline constexpr bool isleap(u32 year)
|
|
||||||
{
|
|
||||||
return year % 4 == 0 && (year % 100 != 0 || year % 400 == 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
static constexpr u32 make_yday(u32 year, u32 month)
|
|
||||||
{
|
|
||||||
constexpr u16 upto[12] = { 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334 };
|
|
||||||
|
|
||||||
u32 yd = upto[month - 1];
|
|
||||||
if (month > 2 && isleap(year)) yd++;
|
|
||||||
return yd;
|
|
||||||
}
|
|
||||||
|
|
||||||
// https://pubs.opengroup.org/onlinepubs/9699919799/basedefs/V1_chap04.html#tag_04_16
|
|
||||||
static constexpr u64 broken_down_to_unix(u64 year, u64 yday, u64 hour, u64 min, u64 sec)
|
|
||||||
{
|
|
||||||
return sec + min * 60 + hour * 3600 + yday * 86400 + (year - 70) * 31536000 + ((year - 69) / 4) * 86400 -
|
|
||||||
((year - 1) / 100) * 86400 + ((year + 299) / 400) * 86400;
|
|
||||||
}
|
|
||||||
|
|
||||||
// The bootloader encodes the date and time in Binary-Coded Decimal (BCD), which represents decimal digits using
|
|
||||||
// hexadecimal digits. For example, BCD 0x22 is 22 in decimal.
|
|
||||||
// https://gitlab.com/bztsrc/bootboot/-/blob/master/bootboot_spec_1st_ed.pdf, page 15.
|
|
||||||
static inline constexpr u32 bcd_number_to_decimal(u32 num)
|
|
||||||
{
|
|
||||||
return ((num >> 4) * 10) + (num & 0xf);
|
|
||||||
}
|
|
||||||
|
|
||||||
static u64 bootloader_time_to_unix(const u8 boottime[8])
|
|
||||||
{
|
|
||||||
const u32 year = bcd_number_to_decimal(boottime[0]) * 100 + bcd_number_to_decimal(boottime[1]);
|
|
||||||
const u32 month = bcd_number_to_decimal(boottime[2]);
|
|
||||||
const u32 day = bcd_number_to_decimal(boottime[3]);
|
|
||||||
const u32 hour = bcd_number_to_decimal(boottime[4]);
|
|
||||||
const u32 minute = bcd_number_to_decimal(boottime[5]);
|
|
||||||
const u32 second = bcd_number_to_decimal(boottime[6]);
|
|
||||||
// "The last byte can store 1/100th second precision, but in lack of support on most platforms, it is 0x00".
|
|
||||||
// Therefore, let's not rely on it.
|
|
||||||
kinfoln("Current time: %.2d/%.2d/%d %.2d:%.2d:%.2d UTC", day, month, year, hour, minute, second);
|
|
||||||
return broken_down_to_unix(year - 1900, make_yday(year, month) + (day - 1), hour, minute, second);
|
|
||||||
}
|
|
||||||
|
|
||||||
extern const BOOTBOOT bootboot;
|
|
||||||
|
|
||||||
namespace Timer
|
|
||||||
{
|
|
||||||
static struct timespec s_interval = { .tv_sec = 0, .tv_nsec = ARCH_TIMER_RESOLUTION * 1000 };
|
|
||||||
|
|
||||||
void tick()
|
|
||||||
{
|
|
||||||
timespecadd(&s_monotonic_clock, &s_interval, &s_monotonic_clock);
|
|
||||||
timespecadd(&s_realtime_clock, &s_interval, &s_realtime_clock);
|
|
||||||
}
|
|
||||||
|
|
||||||
usize ticks_ms()
|
|
||||||
{
|
|
||||||
return (s_monotonic_clock.tv_sec * 1000) + (s_monotonic_clock.tv_nsec / 1'000'000);
|
|
||||||
}
|
|
||||||
|
|
||||||
struct timespec* monotonic_clock()
|
|
||||||
{
|
|
||||||
return &s_monotonic_clock;
|
|
||||||
}
|
|
||||||
|
|
||||||
struct timespec* realtime_clock()
|
|
||||||
{
|
|
||||||
return &s_realtime_clock;
|
|
||||||
}
|
|
||||||
|
|
||||||
void init()
|
|
||||||
{
|
|
||||||
s_realtime_clock.tv_sec = bootloader_time_to_unix(bootboot.datetime);
|
|
||||||
s_realtime_clock.tv_nsec = 0;
|
|
||||||
arch_init();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
bool should_invoke_scheduler()
|
|
||||||
{
|
|
||||||
return (s_realtime_clock.tv_nsec % 1'000'000) == 0;
|
|
||||||
}
|
|
@ -1,29 +0,0 @@
|
|||||||
#pragma once
|
|
||||||
#include <bits/timespec.h>
|
|
||||||
#include <luna/Types.h>
|
|
||||||
|
|
||||||
#ifdef ARCH_X86_64
|
|
||||||
#include "arch/x86_64/Timer.h"
|
|
||||||
#else
|
|
||||||
#error "Unknown architecture."
|
|
||||||
#endif
|
|
||||||
|
|
||||||
static const usize MS_PER_SECOND = 1000;
|
|
||||||
static const usize US_PER_SECOND = MS_PER_SECOND * 1000;
|
|
||||||
static const usize NS_PER_SECOND = US_PER_SECOND * 1000;
|
|
||||||
|
|
||||||
namespace Timer
|
|
||||||
{
|
|
||||||
void tick();
|
|
||||||
|
|
||||||
usize ticks_ms();
|
|
||||||
|
|
||||||
struct timespec* monotonic_clock();
|
|
||||||
|
|
||||||
struct timespec* realtime_clock();
|
|
||||||
|
|
||||||
void arch_init();
|
|
||||||
void init();
|
|
||||||
}
|
|
||||||
|
|
||||||
bool should_invoke_scheduler();
|
|
@ -3,13 +3,13 @@
|
|||||||
#include "Symbols.h"
|
#include "Symbols.h"
|
||||||
#include "api/Mouse.h"
|
#include "api/Mouse.h"
|
||||||
#include "arch/Keyboard.h"
|
#include "arch/Keyboard.h"
|
||||||
#include "arch/Timer.h"
|
|
||||||
#include "arch/x86_64/CPU.h"
|
#include "arch/x86_64/CPU.h"
|
||||||
#include "arch/x86_64/IO.h"
|
#include "arch/x86_64/IO.h"
|
||||||
#include "fs/devices/KeyboardDevice.h"
|
#include "fs/devices/KeyboardDevice.h"
|
||||||
#include "fs/devices/MouseDevice.h"
|
#include "fs/devices/MouseDevice.h"
|
||||||
#include "memory/MemoryManager.h"
|
#include "memory/MemoryManager.h"
|
||||||
#include "sys/Syscall.h"
|
#include "sys/Syscall.h"
|
||||||
|
#include "thread/Clock.h"
|
||||||
#include "thread/Scheduler.h"
|
#include "thread/Scheduler.h"
|
||||||
#include "video/TextConsole.h"
|
#include "video/TextConsole.h"
|
||||||
#include <bits/signal.h>
|
#include <bits/signal.h>
|
||||||
@ -164,9 +164,17 @@ void io_thread()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static bool should_invoke_scheduler()
|
||||||
|
{
|
||||||
|
struct timespec time;
|
||||||
|
g_realtime_clock.get_time(time);
|
||||||
|
return (time.tv_nsec % 1'000'000) == 0;
|
||||||
|
}
|
||||||
|
|
||||||
static void timer_interrupt(Registers* regs, void*)
|
static void timer_interrupt(Registers* regs, void*)
|
||||||
{
|
{
|
||||||
Timer::tick();
|
g_realtime_clock.tick();
|
||||||
|
g_monotonic_clock.tick();
|
||||||
if (should_invoke_scheduler()) Scheduler::invoke(regs);
|
if (should_invoke_scheduler()) Scheduler::invoke(regs);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,15 +1,24 @@
|
|||||||
#include "arch/Timer.h"
|
#include "thread/Clock.h"
|
||||||
#include "arch/x86_64/IO.h"
|
#include "arch/x86_64/IO.h"
|
||||||
|
|
||||||
|
// Every timer tick is equivalent to 250 microseconds.
|
||||||
|
// FIXME: Change ARCH_TIMER_RESOLUTION to use nanoseconds.
|
||||||
|
const usize ARCH_TIMER_RESOLUTION = 250;
|
||||||
|
|
||||||
#define PIT_CHANNEL_0 0x40
|
#define PIT_CHANNEL_0 0x40
|
||||||
|
|
||||||
const u64 base_frequency = 1193182;
|
const u64 base_frequency = 1193182;
|
||||||
|
|
||||||
void Timer::arch_init()
|
void Clock::arch_init()
|
||||||
{
|
{
|
||||||
constexpr u16 divisor = (u16)(base_frequency / ((1000 / ARCH_TIMER_RESOLUTION) * 1000));
|
constexpr u16 divisor = (u16)(base_frequency / ((1000 / ARCH_TIMER_RESOLUTION) * 1000));
|
||||||
static_assert(divisor >= 100, "ARCH_TIMER_RESOLUTION is too low");
|
static_assert(divisor >= 100, "ARCH_TIMER_RESOLUTION is too low");
|
||||||
IO::outb(PIT_CHANNEL_0, (u8)(divisor & 0xFF));
|
IO::outb(PIT_CHANNEL_0, (u8)(divisor & 0xFF));
|
||||||
IO::outb(0x80, 0); // short delay
|
IO::outb(0x80, 0); // short delay
|
||||||
IO::outb(PIT_CHANNEL_0, (u8)((divisor & 0xFF00) >> 8));
|
IO::outb(PIT_CHANNEL_0, (u8)((divisor & 0xFF00) >> 8));
|
||||||
|
|
||||||
|
long resolution = ARCH_TIMER_RESOLUTION * 1000;
|
||||||
|
|
||||||
|
g_realtime_clock.set_resolution(resolution);
|
||||||
|
g_monotonic_clock.set_resolution(resolution);
|
||||||
}
|
}
|
@ -1,6 +0,0 @@
|
|||||||
#pragma once
|
|
||||||
#include <luna/Types.h>
|
|
||||||
|
|
||||||
// Every timer tick is equivalent to 250 microseconds.
|
|
||||||
// FIXME: Change ARCH_TIMER_RESOLUTION to use nanoseconds.
|
|
||||||
const usize ARCH_TIMER_RESOLUTION = 250;
|
|
@ -2,10 +2,10 @@
|
|||||||
#include "Log.h"
|
#include "Log.h"
|
||||||
#include "arch/CPU.h"
|
#include "arch/CPU.h"
|
||||||
#include "arch/Serial.h"
|
#include "arch/Serial.h"
|
||||||
#include "arch/Timer.h"
|
|
||||||
#include "arch/x86_64/IO.h"
|
#include "arch/x86_64/IO.h"
|
||||||
#include "fs/MBR.h"
|
#include "fs/MBR.h"
|
||||||
#include "memory/MemoryManager.h"
|
#include "memory/MemoryManager.h"
|
||||||
|
#include "thread/Clock.h"
|
||||||
#include "thread/Scheduler.h"
|
#include "thread/Scheduler.h"
|
||||||
#include <luna/Alignment.h>
|
#include <luna/Alignment.h>
|
||||||
#include <luna/Buffer.h>
|
#include <luna/Buffer.h>
|
||||||
@ -34,6 +34,13 @@ static usize copy_ata_string(char* out, u16* in, usize size)
|
|||||||
return size;
|
return size;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static u64 ticks_ms()
|
||||||
|
{
|
||||||
|
struct timespec time;
|
||||||
|
g_monotonic_clock.get_time(time);
|
||||||
|
return time.tv_sec * 1000 + time.tv_nsec / 1'000'000;
|
||||||
|
}
|
||||||
|
|
||||||
namespace ATA
|
namespace ATA
|
||||||
{
|
{
|
||||||
Result<void> Controller::scan()
|
Result<void> Controller::scan()
|
||||||
@ -199,24 +206,24 @@ namespace ATA
|
|||||||
|
|
||||||
bool Channel::wait_for_reg_set(Register reg, u8 value, u64 timeout)
|
bool Channel::wait_for_reg_set(Register reg, u8 value, u64 timeout)
|
||||||
{
|
{
|
||||||
u64 begin = Timer::ticks_ms();
|
u64 begin = ticks_ms();
|
||||||
while (true)
|
while (true)
|
||||||
{
|
{
|
||||||
u8 reg_value = reg == Register::Status ? read_control(ControlRegister::AltStatus) : read_register(reg);
|
u8 reg_value = reg == Register::Status ? read_control(ControlRegister::AltStatus) : read_register(reg);
|
||||||
if (reg_value & value) return true;
|
if (reg_value & value) return true;
|
||||||
if ((Timer::ticks_ms() - begin) >= timeout) return false;
|
if ((ticks_ms() - begin) >= timeout) return false;
|
||||||
kernel_sleep(1);
|
kernel_sleep(1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Channel::wait_for_reg_clear(Register reg, u8 value, u64 timeout)
|
bool Channel::wait_for_reg_clear(Register reg, u8 value, u64 timeout)
|
||||||
{
|
{
|
||||||
u64 begin = Timer::ticks_ms();
|
u64 begin = ticks_ms();
|
||||||
while (true)
|
while (true)
|
||||||
{
|
{
|
||||||
u8 reg_value = reg == Register::Status ? read_control(ControlRegister::AltStatus) : read_register(reg);
|
u8 reg_value = reg == Register::Status ? read_control(ControlRegister::AltStatus) : read_register(reg);
|
||||||
if ((reg_value & value) == 0) return true;
|
if ((reg_value & value) == 0) return true;
|
||||||
if ((Timer::ticks_ms() - begin) >= timeout) return false;
|
if ((ticks_ms() - begin) >= timeout) return false;
|
||||||
kernel_sleep(1);
|
kernel_sleep(1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
#include "arch/Timer.h"
|
#include "thread/Clock.h"
|
||||||
#include <bits/makedev.h>
|
#include <bits/makedev.h>
|
||||||
#include <bits/timespec.h>
|
#include <bits/timespec.h>
|
||||||
#include <luna/SharedPtr.h>
|
#include <luna/SharedPtr.h>
|
||||||
@ -163,7 +163,7 @@ namespace VFS
|
|||||||
virtual Result<void> set_metadata(const InodeMetadata& metadata)
|
virtual Result<void> set_metadata(const InodeMetadata& metadata)
|
||||||
{
|
{
|
||||||
m_metadata = metadata;
|
m_metadata = metadata;
|
||||||
m_metadata.ctime = *Timer::realtime_clock();
|
g_realtime_clock.get_time(m_metadata.ctime);
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,5 +1,4 @@
|
|||||||
#include "fs/devpts/FileSystem.h"
|
#include "fs/devpts/FileSystem.h"
|
||||||
#include "arch/Timer.h"
|
|
||||||
#include "fs/devices/DeviceRegistry.h"
|
#include "fs/devices/DeviceRegistry.h"
|
||||||
#include "fs/devpts/Inode.h"
|
#include "fs/devpts/Inode.h"
|
||||||
#include <luna/Alloc.h>
|
#include <luna/Alloc.h>
|
||||||
@ -22,7 +21,9 @@ namespace DevPTS
|
|||||||
root->set_fs(*fs, {});
|
root->set_fs(*fs, {});
|
||||||
root->set_inode_number();
|
root->set_inode_number();
|
||||||
root->m_metadata.mode = 0755;
|
root->m_metadata.mode = 0755;
|
||||||
root->m_metadata.atime = root->m_metadata.ctime = root->m_metadata.mtime = *Timer::realtime_clock();
|
g_realtime_clock.get_time(root->m_metadata.ctime);
|
||||||
|
g_realtime_clock.get_time(root->m_metadata.atime);
|
||||||
|
g_realtime_clock.get_time(root->m_metadata.mtime);
|
||||||
fs->set_root(root);
|
fs->set_root(root);
|
||||||
|
|
||||||
TRY(g_devpts_instances.try_append(fs.ptr()));
|
TRY(g_devpts_instances.try_append(fs.ptr()));
|
||||||
|
@ -43,7 +43,7 @@ namespace DevPTS
|
|||||||
|
|
||||||
inode->did_link();
|
inode->did_link();
|
||||||
|
|
||||||
m_metadata.mtime = *Timer::realtime_clock();
|
g_realtime_clock.get_time(m_metadata.mtime);
|
||||||
|
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
@ -61,7 +61,7 @@ namespace DevPTS
|
|||||||
|
|
||||||
inode->did_unlink();
|
inode->did_unlink();
|
||||||
|
|
||||||
m_metadata.mtime = *Timer::realtime_clock();
|
g_realtime_clock.get_time(m_metadata.mtime);
|
||||||
|
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
#include "fs/tmpfs/FileSystem.h"
|
#include "fs/tmpfs/FileSystem.h"
|
||||||
#include "arch/Timer.h"
|
|
||||||
#include "fs/devices/DeviceRegistry.h"
|
#include "fs/devices/DeviceRegistry.h"
|
||||||
#include "fs/tmpfs/Inode.h"
|
#include "fs/tmpfs/Inode.h"
|
||||||
|
#include "thread/Clock.h"
|
||||||
#include <luna/Alloc.h>
|
#include <luna/Alloc.h>
|
||||||
#include <luna/CString.h>
|
#include <luna/CString.h>
|
||||||
#include <luna/Ignore.h>
|
#include <luna/Ignore.h>
|
||||||
@ -27,7 +27,9 @@ namespace TmpFS
|
|||||||
inode->set_fs(*this, {});
|
inode->set_fs(*this, {});
|
||||||
inode->set_inode_number(m_next_inode_number++, {});
|
inode->set_inode_number(m_next_inode_number++, {});
|
||||||
inode->m_metadata.mode = mode;
|
inode->m_metadata.mode = mode;
|
||||||
inode->m_metadata.atime = inode->m_metadata.ctime = inode->m_metadata.mtime = *Timer::realtime_clock();
|
g_realtime_clock.get_time(inode->m_metadata.mtime);
|
||||||
|
g_realtime_clock.get_time(inode->m_metadata.atime);
|
||||||
|
g_realtime_clock.get_time(inode->m_metadata.ctime);
|
||||||
return (SharedPtr<VFS::Inode>)inode;
|
return (SharedPtr<VFS::Inode>)inode;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -37,7 +39,9 @@ namespace TmpFS
|
|||||||
inode->set_fs(*this, {});
|
inode->set_fs(*this, {});
|
||||||
TRY(inode->set_link(link, {}));
|
TRY(inode->set_link(link, {}));
|
||||||
inode->set_inode_number(m_next_inode_number++, {});
|
inode->set_inode_number(m_next_inode_number++, {});
|
||||||
inode->m_metadata.atime = inode->m_metadata.ctime = inode->m_metadata.mtime = *Timer::realtime_clock();
|
g_realtime_clock.get_time(inode->m_metadata.mtime);
|
||||||
|
g_realtime_clock.get_time(inode->m_metadata.atime);
|
||||||
|
g_realtime_clock.get_time(inode->m_metadata.ctime);
|
||||||
return (SharedPtr<VFS::Inode>)inode;
|
return (SharedPtr<VFS::Inode>)inode;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -52,7 +56,9 @@ namespace TmpFS
|
|||||||
inode->set_fs(*this, {});
|
inode->set_fs(*this, {});
|
||||||
inode->set_inode_number(m_next_inode_number++, {});
|
inode->set_inode_number(m_next_inode_number++, {});
|
||||||
inode->m_metadata.mode = mode;
|
inode->m_metadata.mode = mode;
|
||||||
inode->m_metadata.atime = inode->m_metadata.ctime = inode->m_metadata.mtime = *Timer::realtime_clock();
|
g_realtime_clock.get_time(inode->m_metadata.mtime);
|
||||||
|
g_realtime_clock.get_time(inode->m_metadata.atime);
|
||||||
|
g_realtime_clock.get_time(inode->m_metadata.ctime);
|
||||||
|
|
||||||
return (SharedPtr<VFS::Inode>)inode;
|
return (SharedPtr<VFS::Inode>)inode;
|
||||||
}
|
}
|
||||||
@ -69,7 +75,9 @@ namespace TmpFS
|
|||||||
// device ID atm.
|
// device ID atm.
|
||||||
inode->set_device_id(luna_dev_makedev(major, minor), {});
|
inode->set_device_id(luna_dev_makedev(major, minor), {});
|
||||||
inode->m_metadata.mode = mode;
|
inode->m_metadata.mode = mode;
|
||||||
inode->m_metadata.atime = inode->m_metadata.ctime = inode->m_metadata.mtime = *Timer::realtime_clock();
|
g_realtime_clock.get_time(inode->m_metadata.mtime);
|
||||||
|
g_realtime_clock.get_time(inode->m_metadata.atime);
|
||||||
|
g_realtime_clock.get_time(inode->m_metadata.ctime);
|
||||||
inode->m_metadata.size = device->size();
|
inode->m_metadata.size = device->size();
|
||||||
|
|
||||||
return (SharedPtr<VFS::Inode>)inode;
|
return (SharedPtr<VFS::Inode>)inode;
|
||||||
|
@ -45,7 +45,7 @@ namespace TmpFS
|
|||||||
|
|
||||||
inode->did_link();
|
inode->did_link();
|
||||||
|
|
||||||
m_metadata.mtime = *Timer::realtime_clock();
|
g_realtime_clock.get_time(m_metadata.mtime);
|
||||||
|
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
@ -63,7 +63,7 @@ namespace TmpFS
|
|||||||
|
|
||||||
inode->did_unlink();
|
inode->did_unlink();
|
||||||
|
|
||||||
m_metadata.mtime = *Timer::realtime_clock();
|
g_realtime_clock.get_time(m_metadata.mtime);
|
||||||
|
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
@ -118,7 +118,7 @@ namespace TmpFS
|
|||||||
|
|
||||||
m_metadata.size = m_data_buffer.size();
|
m_metadata.size = m_data_buffer.size();
|
||||||
|
|
||||||
m_metadata.mtime = *Timer::realtime_clock();
|
g_realtime_clock.get_time(m_metadata.mtime);
|
||||||
|
|
||||||
return length;
|
return length;
|
||||||
}
|
}
|
||||||
@ -133,7 +133,7 @@ namespace TmpFS
|
|||||||
|
|
||||||
m_metadata.size = m_data_buffer.size();
|
m_metadata.size = m_data_buffer.size();
|
||||||
|
|
||||||
m_metadata.mtime = *Timer::realtime_clock();
|
g_realtime_clock.get_time(m_metadata.mtime);
|
||||||
|
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
@ -1,7 +1,6 @@
|
|||||||
#include "Log.h"
|
#include "Log.h"
|
||||||
#include "Symbols.h"
|
#include "Symbols.h"
|
||||||
#include "arch/CPU.h"
|
#include "arch/CPU.h"
|
||||||
#include "arch/Timer.h"
|
|
||||||
#include "binfmt/BinaryFormat.h"
|
#include "binfmt/BinaryFormat.h"
|
||||||
#include "boot/Init.h"
|
#include "boot/Init.h"
|
||||||
#include "config.h"
|
#include "config.h"
|
||||||
@ -11,6 +10,7 @@
|
|||||||
#include "fs/devices/PTYMultiplexer.h"
|
#include "fs/devices/PTYMultiplexer.h"
|
||||||
#include "fs/tmpfs/FileSystem.h"
|
#include "fs/tmpfs/FileSystem.h"
|
||||||
#include "memory/MemoryManager.h"
|
#include "memory/MemoryManager.h"
|
||||||
|
#include "thread/Clock.h"
|
||||||
#include "thread/Scheduler.h"
|
#include "thread/Scheduler.h"
|
||||||
#include <luna/Units.h>
|
#include <luna/Units.h>
|
||||||
|
|
||||||
@ -96,7 +96,7 @@ extern "C" [[noreturn]] void _start()
|
|||||||
Init::check_magic();
|
Init::check_magic();
|
||||||
Init::early_init();
|
Init::early_init();
|
||||||
|
|
||||||
Timer::init();
|
Clock::init();
|
||||||
|
|
||||||
Thread::init();
|
Thread::init();
|
||||||
Scheduler::init();
|
Scheduler::init();
|
||||||
|
@ -2,6 +2,7 @@
|
|||||||
#include "sys/Syscall.h"
|
#include "sys/Syscall.h"
|
||||||
#include "thread/Scheduler.h"
|
#include "thread/Scheduler.h"
|
||||||
#include "thread/Timer.h"
|
#include "thread/Timer.h"
|
||||||
|
#include <luna/Common.h>
|
||||||
|
|
||||||
Result<u64> sys_alarm(Registers*, SyscallArgs args)
|
Result<u64> sys_alarm(Registers*, SyscallArgs args)
|
||||||
{
|
{
|
||||||
@ -11,19 +12,24 @@ Result<u64> sys_alarm(Registers*, SyscallArgs args)
|
|||||||
|
|
||||||
TRY(check_pledge(current, Promise::p_stdio));
|
TRY(check_pledge(current, Promise::p_stdio));
|
||||||
|
|
||||||
u64 ticks_left = current->timer ? current->timer->ticks_left() : 0;
|
Clock* clock = nullptr;
|
||||||
|
|
||||||
|
u64 ticks_left = current->timer ? current->timer->clock->ticks_left(current->timer) : 0;
|
||||||
|
|
||||||
if (current->timer)
|
if (current->timer)
|
||||||
{
|
{
|
||||||
if (current->timer->delta_ticks > 0) Scheduler::remove_from_timer_queue(current->timer);
|
clock = current->timer->clock;
|
||||||
|
if (clock) clock->remove_from_timer_queue(current->timer);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
current->timer = TRY(make<Scheduler::Timer>());
|
current->timer = TRY(make<Timer>());
|
||||||
|
|
||||||
current->timer->total_ticks = seconds * 1000;
|
if (!clock) clock = &g_realtime_clock;
|
||||||
|
|
||||||
|
current->timer->total_ticks = ceil_div((static_cast<long>(seconds) * 1'000'000'000), clock->resolution());
|
||||||
current->timer->thread = current;
|
current->timer->thread = current;
|
||||||
|
|
||||||
Scheduler::add_to_timer_queue(current->timer);
|
clock->add_to_timer_queue(current->timer);
|
||||||
|
|
||||||
return ticks_left * 1000;
|
return (ticks_left * clock->resolution()) / 1'000'000'000;
|
||||||
}
|
}
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
#include "Pledge.h"
|
#include "Pledge.h"
|
||||||
#include "arch/Timer.h"
|
|
||||||
#include "memory/MemoryManager.h"
|
#include "memory/MemoryManager.h"
|
||||||
#include "sys/Syscall.h"
|
#include "sys/Syscall.h"
|
||||||
|
#include "thread/Clock.h"
|
||||||
#include "thread/Scheduler.h"
|
#include "thread/Scheduler.h"
|
||||||
#include <bits/clockid.h>
|
#include <bits/clockid.h>
|
||||||
#include <bits/timespec.h>
|
#include <bits/timespec.h>
|
||||||
@ -15,18 +15,24 @@ Result<u64> sys_clock_gettime(Registers*, SyscallArgs args)
|
|||||||
|
|
||||||
TRY(check_pledge(current, Promise::p_stdio));
|
TRY(check_pledge(current, Promise::p_stdio));
|
||||||
|
|
||||||
|
Clock* clock;
|
||||||
|
|
||||||
switch (id)
|
switch (id)
|
||||||
{
|
{
|
||||||
case CLOCK_MONOTONIC: {
|
case CLOCK_MONOTONIC: {
|
||||||
if (!MemoryManager::copy_to_user_typed(ts, Timer::monotonic_clock())) return err(EFAULT);
|
clock = &g_monotonic_clock;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case CLOCK_REALTIME: {
|
case CLOCK_REALTIME: {
|
||||||
if (!MemoryManager::copy_to_user_typed(ts, Timer::realtime_clock())) return err(EFAULT);
|
clock = &g_realtime_clock;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
default: return err(EINVAL);
|
default: return err(EINVAL);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct timespec time;
|
||||||
|
clock->get_time(time);
|
||||||
|
if (!MemoryManager::copy_to_user_typed(ts, &time)) return err(EFAULT);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -318,7 +318,7 @@ Result<u64> sys_utimensat(Registers*, SyscallArgs args)
|
|||||||
auto metadata = inode->metadata();
|
auto metadata = inode->metadata();
|
||||||
if (ktimes[0].tv_nsec != UTIME_OMIT)
|
if (ktimes[0].tv_nsec != UTIME_OMIT)
|
||||||
{
|
{
|
||||||
if (ktimes[0].tv_nsec == UTIME_NOW) metadata.atime = *Timer::realtime_clock();
|
if (ktimes[0].tv_nsec == UTIME_NOW) g_realtime_clock.get_time(metadata.atime);
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if (ktimes[0].tv_nsec < 0 || ktimes[0].tv_nsec > 999'999'999) return err(EINVAL);
|
if (ktimes[0].tv_nsec < 0 || ktimes[0].tv_nsec > 999'999'999) return err(EINVAL);
|
||||||
@ -327,7 +327,7 @@ Result<u64> sys_utimensat(Registers*, SyscallArgs args)
|
|||||||
}
|
}
|
||||||
if (ktimes[1].tv_nsec != UTIME_OMIT)
|
if (ktimes[1].tv_nsec != UTIME_OMIT)
|
||||||
{
|
{
|
||||||
if (ktimes[1].tv_nsec == UTIME_NOW) metadata.mtime = *Timer::realtime_clock();
|
if (ktimes[1].tv_nsec == UTIME_NOW) g_realtime_clock.get_time(metadata.mtime);
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if (ktimes[1].tv_nsec < 0 || ktimes[1].tv_nsec > 999'999'999) return err(EINVAL);
|
if (ktimes[1].tv_nsec < 0 || ktimes[1].tv_nsec > 999'999'999) return err(EINVAL);
|
||||||
|
161
kernel/src/thread/Clock.cpp
Normal file
161
kernel/src/thread/Clock.cpp
Normal file
@ -0,0 +1,161 @@
|
|||||||
|
#include "thread/Clock.h"
|
||||||
|
#include "Log.h"
|
||||||
|
#include "arch/Serial.h"
|
||||||
|
#include "boot/bootboot.h"
|
||||||
|
#include "thread/Thread.h"
|
||||||
|
|
||||||
|
Clock g_realtime_clock;
|
||||||
|
Clock g_monotonic_clock;
|
||||||
|
|
||||||
|
static inline constexpr bool isleap(u32 year)
|
||||||
|
{
|
||||||
|
return year % 4 == 0 && (year % 100 != 0 || year % 400 == 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
static constexpr u32 make_yday(u32 year, u32 month)
|
||||||
|
{
|
||||||
|
constexpr u16 upto[12] = { 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334 };
|
||||||
|
|
||||||
|
u32 yd = upto[month - 1];
|
||||||
|
if (month > 2 && isleap(year)) yd++;
|
||||||
|
return yd;
|
||||||
|
}
|
||||||
|
|
||||||
|
// https://pubs.opengroup.org/onlinepubs/9699919799/basedefs/V1_chap04.html#tag_04_16
|
||||||
|
static constexpr u64 broken_down_to_unix(u64 year, u64 yday, u64 hour, u64 min, u64 sec)
|
||||||
|
{
|
||||||
|
return sec + min * 60 + hour * 3600 + yday * 86400 + (year - 70) * 31536000 + ((year - 69) / 4) * 86400 -
|
||||||
|
((year - 1) / 100) * 86400 + ((year + 299) / 400) * 86400;
|
||||||
|
}
|
||||||
|
|
||||||
|
// The bootloader encodes the date and time in Binary-Coded Decimal (BCD), which represents decimal digits using
|
||||||
|
// hexadecimal digits. For example, BCD 0x22 is 22 in decimal.
|
||||||
|
// https://gitlab.com/bztsrc/bootboot/-/blob/master/bootboot_spec_1st_ed.pdf, page 15.
|
||||||
|
static inline constexpr u32 bcd_number_to_decimal(u32 num)
|
||||||
|
{
|
||||||
|
return ((num >> 4) * 10) + (num & 0xf);
|
||||||
|
}
|
||||||
|
|
||||||
|
static u64 bootloader_time_to_unix(const u8 boottime[8])
|
||||||
|
{
|
||||||
|
const u32 year = bcd_number_to_decimal(boottime[0]) * 100 + bcd_number_to_decimal(boottime[1]);
|
||||||
|
const u32 month = bcd_number_to_decimal(boottime[2]);
|
||||||
|
const u32 day = bcd_number_to_decimal(boottime[3]);
|
||||||
|
const u32 hour = bcd_number_to_decimal(boottime[4]);
|
||||||
|
const u32 minute = bcd_number_to_decimal(boottime[5]);
|
||||||
|
const u32 second = bcd_number_to_decimal(boottime[6]);
|
||||||
|
// "The last byte can store 1/100th second precision, but in lack of support on most platforms, it is 0x00".
|
||||||
|
// Therefore, let's not rely on it.
|
||||||
|
kinfoln("Current time: %.2d/%.2d/%d %.2d:%.2d:%.2d UTC", day, month, year, hour, minute, second);
|
||||||
|
return broken_down_to_unix(year - 1900, make_yday(year, month) + (day - 1), hour, minute, second);
|
||||||
|
}
|
||||||
|
|
||||||
|
extern const BOOTBOOT bootboot;
|
||||||
|
|
||||||
|
void Clock::init()
|
||||||
|
{
|
||||||
|
struct timespec time = { .tv_sec = (time_t)bootloader_time_to_unix(bootboot.datetime), .tv_nsec = 0 };
|
||||||
|
g_realtime_clock.update(time);
|
||||||
|
arch_init();
|
||||||
|
}
|
||||||
|
|
||||||
|
void Clock::set_resolution(long resolution)
|
||||||
|
{
|
||||||
|
m_resolution = resolution;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Clock::update(const struct timespec& time)
|
||||||
|
{
|
||||||
|
m_time = time;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Clock::add_to_timer_queue(Timer* timer)
|
||||||
|
{
|
||||||
|
check(timer->clock == nullptr);
|
||||||
|
|
||||||
|
timer->delta_ticks = timer->total_ticks;
|
||||||
|
|
||||||
|
for (auto* t : m_timer_queue)
|
||||||
|
{
|
||||||
|
if (timer->delta_ticks <= t->delta_ticks)
|
||||||
|
{
|
||||||
|
t->delta_ticks -= timer->delta_ticks;
|
||||||
|
m_timer_queue.add_before(t, timer);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
timer->delta_ticks -= t->delta_ticks;
|
||||||
|
}
|
||||||
|
|
||||||
|
m_timer_queue.append(timer);
|
||||||
|
|
||||||
|
timer->clock = this;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Clock::remove_from_timer_queue(Timer* timer)
|
||||||
|
{
|
||||||
|
check(timer->clock == this);
|
||||||
|
|
||||||
|
auto maybe_next = m_timer_queue.next(timer);
|
||||||
|
if (maybe_next.has_value())
|
||||||
|
{
|
||||||
|
auto next = maybe_next.value();
|
||||||
|
next->delta_ticks += timer->delta_ticks;
|
||||||
|
}
|
||||||
|
m_timer_queue.remove(timer);
|
||||||
|
|
||||||
|
timer->clock = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Clock::tick()
|
||||||
|
{
|
||||||
|
struct timespec interval = { .tv_sec = 0, .tv_nsec = m_resolution };
|
||||||
|
|
||||||
|
timespecadd(&m_time, &interval, &m_time);
|
||||||
|
|
||||||
|
auto maybe_first = m_timer_queue.first();
|
||||||
|
if (!maybe_first.has_value()) return;
|
||||||
|
|
||||||
|
auto first = *maybe_first;
|
||||||
|
first->delta_ticks--;
|
||||||
|
|
||||||
|
LinkedList<Timer> timers_to_be_restarted;
|
||||||
|
|
||||||
|
m_timer_queue.delayed_for_each([&](Timer* t) {
|
||||||
|
if (t->delta_ticks == 0)
|
||||||
|
{
|
||||||
|
this->m_timer_queue.remove(t);
|
||||||
|
t->clock = nullptr;
|
||||||
|
t->thread->send_signal(t->signo);
|
||||||
|
if (t->restart) timers_to_be_restarted.append(t);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
});
|
||||||
|
|
||||||
|
timers_to_be_restarted.consume([this](Timer* t) { add_to_timer_queue(t); });
|
||||||
|
}
|
||||||
|
|
||||||
|
void Clock::get_time(struct timespec& out)
|
||||||
|
{
|
||||||
|
out = m_time;
|
||||||
|
}
|
||||||
|
|
||||||
|
long Clock::resolution()
|
||||||
|
{
|
||||||
|
return m_resolution;
|
||||||
|
}
|
||||||
|
|
||||||
|
u64 Clock::ticks_left(Timer* timer)
|
||||||
|
{
|
||||||
|
check(timer->clock == this);
|
||||||
|
|
||||||
|
u64 total = 0;
|
||||||
|
if (timer->delta_ticks == 0) return 0;
|
||||||
|
for (auto* t : m_timer_queue)
|
||||||
|
{
|
||||||
|
total += t->delta_ticks;
|
||||||
|
if (t == timer) break;
|
||||||
|
}
|
||||||
|
return total;
|
||||||
|
}
|
36
kernel/src/thread/Clock.h
Normal file
36
kernel/src/thread/Clock.h
Normal file
@ -0,0 +1,36 @@
|
|||||||
|
#pragma once
|
||||||
|
#include "thread/Timer.h"
|
||||||
|
#include <bits/timespec.h>
|
||||||
|
|
||||||
|
struct Clock
|
||||||
|
{
|
||||||
|
static void init();
|
||||||
|
static void arch_init();
|
||||||
|
|
||||||
|
void set_resolution(long resolution);
|
||||||
|
|
||||||
|
void update(const struct timespec& time);
|
||||||
|
|
||||||
|
void tick();
|
||||||
|
|
||||||
|
void add_to_timer_queue(Timer* timer);
|
||||||
|
void remove_from_timer_queue(Timer* timer);
|
||||||
|
|
||||||
|
void get_time(struct timespec& out);
|
||||||
|
long resolution();
|
||||||
|
|
||||||
|
u64 ticks_left(Timer* timer);
|
||||||
|
|
||||||
|
private:
|
||||||
|
struct timespec m_time
|
||||||
|
{
|
||||||
|
.tv_sec = 0, .tv_nsec = 0
|
||||||
|
};
|
||||||
|
|
||||||
|
long m_resolution = 1'000'000'000;
|
||||||
|
|
||||||
|
LinkedList<Timer> m_timer_queue;
|
||||||
|
};
|
||||||
|
|
||||||
|
extern Clock g_realtime_clock;
|
||||||
|
extern Clock g_monotonic_clock;
|
@ -219,7 +219,7 @@ namespace Scheduler
|
|||||||
|
|
||||||
if (thread->timer)
|
if (thread->timer)
|
||||||
{
|
{
|
||||||
Scheduler::remove_from_timer_queue(thread->timer);
|
thread->timer->clock->remove_from_timer_queue(thread->timer);
|
||||||
delete thread->timer;
|
delete thread->timer;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -300,8 +300,6 @@ 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++;
|
||||||
|
@ -19,10 +19,7 @@
|
|||||||
#error "Unknown architecture."
|
#error "Unknown architecture."
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
namespace Scheduler
|
|
||||||
{
|
|
||||||
class Timer;
|
class Timer;
|
||||||
}
|
|
||||||
|
|
||||||
enum class ThreadState
|
enum class ThreadState
|
||||||
{
|
{
|
||||||
@ -101,7 +98,7 @@ struct Thread : public LinkedListNode<Thread>
|
|||||||
|
|
||||||
mode_t umask { 0 };
|
mode_t umask { 0 };
|
||||||
|
|
||||||
Scheduler::Timer* timer { nullptr };
|
Timer* timer { nullptr };
|
||||||
|
|
||||||
StaticString<128> cmdline;
|
StaticString<128> cmdline;
|
||||||
|
|
||||||
|
@ -1,73 +0,0 @@
|
|||||||
#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;
|
|
||||||
if (delta_ticks == 0) return 0;
|
|
||||||
for (auto* t : g_timer_queue)
|
|
||||||
{
|
|
||||||
total += t->delta_ticks;
|
|
||||||
if (t == this) break;
|
|
||||||
}
|
|
||||||
return total;
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,9 +1,10 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
#include "thread/Thread.h"
|
#include <bits/signal.h>
|
||||||
#include <luna/LinkedList.h>
|
#include <luna/LinkedList.h>
|
||||||
|
|
||||||
namespace Scheduler
|
struct Thread;
|
||||||
{
|
struct Clock;
|
||||||
|
|
||||||
class Timer : public LinkedListNode<Timer>
|
class Timer : public LinkedListNode<Timer>
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
@ -13,11 +14,5 @@ namespace Scheduler
|
|||||||
int signo { SIGALRM };
|
int signo { SIGALRM };
|
||||||
bool restart { false };
|
bool restart { false };
|
||||||
|
|
||||||
u64 ticks_left();
|
Clock* clock;
|
||||||
};
|
};
|
||||||
|
|
||||||
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