mirror of
https://github.com/RGBCube/serenity
synced 2025-07-26 23:17:46 +00:00
Kernel: Move some time related code from Scheduler into TimeManagement
Use the TimerQueue to expire blocking operations, which is one less thing the Scheduler needs to check on every iteration. Also, add a BlockTimeout class that will automatically handle relative or absolute timeouts as well as overriding timeouts (e.g. socket timeouts) more consistently. Also, rework the TimerQueue class to be able to fire events from any processor, which requires Timer to be RefCounted. Also allow creating id-less timers for use by blocking operations.
This commit is contained in:
parent
e0e26c6c67
commit
6cb640eeba
19 changed files with 461 additions and 263 deletions
|
@ -33,14 +33,15 @@ unsigned Process::sys$alarm(unsigned seconds)
|
|||
{
|
||||
REQUIRE_PROMISE(stdio);
|
||||
unsigned previous_alarm_remaining = 0;
|
||||
if (m_alarm_deadline && m_alarm_deadline > g_uptime) {
|
||||
previous_alarm_remaining = (m_alarm_deadline - g_uptime) / TimeManagement::the().ticks_per_second();
|
||||
auto uptime = TimeManagement::the().uptime_ms();
|
||||
if (m_alarm_deadline && m_alarm_deadline > uptime) {
|
||||
previous_alarm_remaining = m_alarm_deadline - uptime;
|
||||
}
|
||||
if (!seconds) {
|
||||
m_alarm_deadline = 0;
|
||||
return previous_alarm_remaining;
|
||||
}
|
||||
m_alarm_deadline = g_uptime + seconds * TimeManagement::the().ticks_per_second();
|
||||
m_alarm_deadline = uptime + seconds * 1000;
|
||||
return previous_alarm_remaining;
|
||||
}
|
||||
|
||||
|
|
|
@ -32,9 +32,9 @@ namespace Kernel {
|
|||
int Process::sys$beep()
|
||||
{
|
||||
PCSpeaker::tone_on(440);
|
||||
u64 wakeup_time = Thread::current()->sleep(100);
|
||||
auto result = Thread::current()->sleep({ 0, 200 });
|
||||
PCSpeaker::tone_off();
|
||||
if (wakeup_time > g_uptime)
|
||||
if (result.was_interrupted())
|
||||
return -EINTR;
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -37,13 +37,9 @@ int Process::sys$clock_gettime(clockid_t clock_id, Userspace<timespec*> user_ts)
|
|||
timespec ts = {};
|
||||
|
||||
switch (clock_id) {
|
||||
case CLOCK_MONOTONIC: {
|
||||
auto ticks_per_second = TimeManagement::the().ticks_per_second();
|
||||
auto uptime = g_uptime;
|
||||
ts.tv_sec = uptime / ticks_per_second;
|
||||
ts.tv_nsec = (1000000000 * (uptime % ticks_per_second)) / ticks_per_second;
|
||||
case CLOCK_MONOTONIC:
|
||||
ts = TimeManagement::the().monotonic_time();
|
||||
break;
|
||||
}
|
||||
case CLOCK_REALTIME:
|
||||
ts = TimeManagement::the().epoch_time();
|
||||
break;
|
||||
|
@ -91,29 +87,19 @@ int Process::sys$clock_nanosleep(Userspace<const Syscall::SC_clock_nanosleep_par
|
|||
|
||||
bool is_absolute = params.flags & TIMER_ABSTIME;
|
||||
|
||||
auto ticks_per_second = TimeManagement::the().ticks_per_second();
|
||||
|
||||
switch (params.clock_id) {
|
||||
case CLOCK_MONOTONIC: {
|
||||
u64 ticks_to_sleep = requested_sleep.tv_sec * ticks_per_second;
|
||||
ticks_to_sleep += (requested_sleep.tv_nsec * ticks_per_second) / 1000000000;
|
||||
if (is_absolute)
|
||||
ticks_to_sleep -= g_uptime;
|
||||
if (!ticks_to_sleep)
|
||||
return 0;
|
||||
u64 wakeup_time = Thread::current()->sleep(ticks_to_sleep);
|
||||
if (wakeup_time > g_uptime) {
|
||||
u64 ticks_left = wakeup_time - g_uptime;
|
||||
if (!is_absolute && params.remaining_sleep) {
|
||||
timespec remaining_sleep = {};
|
||||
remaining_sleep.tv_sec = ticks_left / ticks_per_second;
|
||||
ticks_left -= remaining_sleep.tv_sec * ticks_per_second;
|
||||
remaining_sleep.tv_nsec = (ticks_left * 1000000000) / ticks_per_second;
|
||||
if (!copy_to_user(params.remaining_sleep, &remaining_sleep))
|
||||
return -EFAULT;
|
||||
}
|
||||
return -EINTR;
|
||||
bool was_interrupted;
|
||||
if (is_absolute) {
|
||||
was_interrupted = Thread::current()->sleep_until(requested_sleep).was_interrupted();
|
||||
} else {
|
||||
timespec remaining_sleep;
|
||||
was_interrupted = Thread::current()->sleep(requested_sleep, &remaining_sleep).was_interrupted();
|
||||
if (was_interrupted && params.remaining_sleep && !copy_to_user(params.remaining_sleep, &remaining_sleep))
|
||||
return -EFAULT;
|
||||
}
|
||||
if (was_interrupted)
|
||||
return -EINTR;
|
||||
return 0;
|
||||
}
|
||||
default:
|
||||
|
|
|
@ -29,19 +29,6 @@
|
|||
|
||||
namespace Kernel {
|
||||
|
||||
static void compute_relative_timeout_from_absolute(const timeval& absolute_time, timeval& relative_time)
|
||||
{
|
||||
// Convert absolute time to relative time of day.
|
||||
timeval_sub(absolute_time, kgettimeofday(), relative_time);
|
||||
}
|
||||
|
||||
static void compute_relative_timeout_from_absolute(const timespec& absolute_time, timeval& relative_time)
|
||||
{
|
||||
timeval tv_absolute_time;
|
||||
timespec_to_timeval(absolute_time, tv_absolute_time);
|
||||
compute_relative_timeout_from_absolute(tv_absolute_time, relative_time);
|
||||
}
|
||||
|
||||
WaitQueue& Process::futex_queue(Userspace<const i32*> userspace_address)
|
||||
{
|
||||
auto& queue = m_futex_queues.ensure(userspace_address.ptr());
|
||||
|
@ -66,20 +53,17 @@ int Process::sys$futex(Userspace<const Syscall::SC_futex_params*> user_params)
|
|||
if (user_value != params.val)
|
||||
return -EAGAIN;
|
||||
|
||||
timespec ts_abstimeout { 0, 0 };
|
||||
if (params.timeout && !copy_from_user(&ts_abstimeout, params.timeout))
|
||||
return -EFAULT;
|
||||
|
||||
timeval* optional_timeout = nullptr;
|
||||
timeval relative_timeout { 0, 0 };
|
||||
Thread::BlockTimeout timeout;
|
||||
if (params.timeout) {
|
||||
compute_relative_timeout_from_absolute(ts_abstimeout, relative_timeout);
|
||||
optional_timeout = &relative_timeout;
|
||||
timespec ts_abstimeout { 0, 0 };
|
||||
if (!copy_from_user(&ts_abstimeout, params.timeout))
|
||||
return -EFAULT;
|
||||
timeout = Thread::BlockTimeout(true, &ts_abstimeout);
|
||||
}
|
||||
|
||||
// FIXME: This is supposed to be interruptible by a signal, but right now WaitQueue cannot be interrupted.
|
||||
WaitQueue& wait_queue = futex_queue((FlatPtr)params.userspace_address);
|
||||
Thread::BlockResult result = Thread::current()->wait_on(wait_queue, "Futex", optional_timeout);
|
||||
Thread::BlockResult result = Thread::current()->wait_on(wait_queue, "Futex", timeout);
|
||||
if (result == Thread::BlockResult::InterruptedByTimeout) {
|
||||
return -ETIMEDOUT;
|
||||
}
|
||||
|
|
|
@ -46,18 +46,12 @@ int Process::sys$select(const Syscall::SC_select_params* user_params)
|
|||
if (params.nfds < 0)
|
||||
return -EINVAL;
|
||||
|
||||
timespec computed_timeout;
|
||||
bool select_has_timeout = false;
|
||||
Thread::BlockTimeout timeout;
|
||||
if (params.timeout) {
|
||||
timespec timeout_copy;
|
||||
if (!copy_from_user(&timeout_copy, params.timeout))
|
||||
return -EFAULT;
|
||||
if (timeout_copy.tv_sec || timeout_copy.tv_nsec) {
|
||||
timespec ts_since_boot;
|
||||
timeval_to_timespec(Scheduler::time_since_boot(), ts_since_boot);
|
||||
timespec_add(ts_since_boot, timeout_copy, computed_timeout);
|
||||
select_has_timeout = true;
|
||||
}
|
||||
timeout = Thread::BlockTimeout(false, &timeout_copy);
|
||||
}
|
||||
|
||||
auto current_thread = Thread::current();
|
||||
|
@ -107,8 +101,8 @@ int Process::sys$select(const Syscall::SC_select_params* user_params)
|
|||
dbg() << "selecting on (read:" << rfds.size() << ", write:" << wfds.size() << "), timeout=" << params.timeout;
|
||||
#endif
|
||||
|
||||
if (!params.timeout || select_has_timeout) {
|
||||
if (current_thread->block<Thread::SelectBlocker>(select_has_timeout ? &computed_timeout : nullptr, rfds, wfds, efds).was_interrupted())
|
||||
if (timeout.should_block()) {
|
||||
if (current_thread->block<Thread::SelectBlocker>(timeout, rfds, wfds, efds).was_interrupted())
|
||||
return -EINTR;
|
||||
}
|
||||
|
||||
|
@ -148,9 +142,13 @@ int Process::sys$poll(Userspace<const Syscall::SC_poll_params*> user_params)
|
|||
|
||||
SmapDisabler disabler;
|
||||
|
||||
timespec timeout = {};
|
||||
if (params.timeout && !copy_from_user(&timeout, params.timeout))
|
||||
return -EFAULT;
|
||||
Thread::BlockTimeout timeout;
|
||||
if (params.timeout) {
|
||||
timespec timeout_copy;
|
||||
if (!copy_from_user(&timeout_copy, params.timeout))
|
||||
return -EFAULT;
|
||||
timeout = Thread::BlockTimeout(false, &timeout_copy);
|
||||
}
|
||||
|
||||
sigset_t sigmask = {};
|
||||
if (params.sigmask && !copy_from_user(&sigmask, params.sigmask))
|
||||
|
@ -178,15 +176,6 @@ int Process::sys$poll(Userspace<const Syscall::SC_poll_params*> user_params)
|
|||
wfds.append(pfd.fd);
|
||||
}
|
||||
|
||||
timespec actual_timeout;
|
||||
bool has_timeout = false;
|
||||
if (params.timeout && (timeout.tv_sec || timeout.tv_nsec)) {
|
||||
timespec ts_since_boot;
|
||||
timeval_to_timespec(Scheduler::time_since_boot(), ts_since_boot);
|
||||
timespec_add(ts_since_boot, timeout, actual_timeout);
|
||||
has_timeout = true;
|
||||
}
|
||||
|
||||
auto current_thread = Thread::current();
|
||||
|
||||
u32 previous_signal_mask = 0;
|
||||
|
@ -198,11 +187,11 @@ int Process::sys$poll(Userspace<const Syscall::SC_poll_params*> user_params)
|
|||
});
|
||||
|
||||
#if defined(DEBUG_IO) || defined(DEBUG_POLL_SELECT)
|
||||
dbg() << "polling on (read:" << rfds.size() << ", write:" << wfds.size() << "), timeout=" << timeout.tv_sec << "s" << timeout.tv_nsec << "ns";
|
||||
dbg() << "polling on (read:" << rfds.size() << ", write:" << wfds.size() << ")";
|
||||
#endif
|
||||
|
||||
if (!params.timeout || has_timeout) {
|
||||
if (current_thread->block<Thread::SelectBlocker>(has_timeout ? &actual_timeout : nullptr, rfds, wfds, Thread::SelectBlocker::FDVector()).was_interrupted())
|
||||
if (timeout.should_block()) {
|
||||
if (current_thread->block<Thread::SelectBlocker>(timeout, rfds, wfds, Thread::SelectBlocker::FDVector()).was_interrupted())
|
||||
return -EINTR;
|
||||
}
|
||||
|
||||
|
|
|
@ -40,7 +40,7 @@ clock_t Process::sys$times(Userspace<tms*> user_times)
|
|||
if (!copy_to_user(user_times, ×))
|
||||
return -EFAULT;
|
||||
|
||||
return g_uptime & 0x7fffffff;
|
||||
return TimeManagement::the().uptime_ms() & 0x7fffffff;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue