kernel+libc: Add setitimer()
All checks were successful
continuous-integration/drone/push Build is passing

This commit is contained in:
apio 2023-11-16 21:48:18 +01:00
parent c4d2847da1
commit 678121c3ed
Signed by: asleepymoon
GPG Key ID: B8A7D06E42258954
15 changed files with 174 additions and 50 deletions

View File

@ -47,7 +47,7 @@ set(SOURCES
src/sys/signal.cpp
src/sys/socket.cpp
src/sys/poll.cpp
src/sys/alarm.cpp
src/sys/setitimer.cpp
src/sys/pledge.cpp
src/sys/memstat.cpp
src/fs/VFS.cpp

View File

@ -8,8 +8,8 @@
_e(umount) _e(pstat) _e(getrusage) _e(symlinkat) _e(readlinkat) _e(umask) _e(linkat) _e(faccessat) \
_e(pivot_root) _e(sigreturn) _e(sigaction) _e(kill) _e(sigprocmask) _e(setpgid) _e(isatty) \
_e(getpgid) _e(socket) _e(bind) _e(connect) _e(listen) _e(accept) _e(poll) _e(msync) \
_e(truncate) _e(ftruncate) _e(utimensat) _e(alarm) _e(pledge) _e(memstat) _e(setsid) \
_e(getsid)
_e(truncate) _e(ftruncate) _e(utimensat) _e(setitimer) _e(pledge) _e(memstat) \
_e(setsid) _e(getsid)
enum Syscalls
{

View File

@ -1,35 +0,0 @@
#include "Pledge.h"
#include "sys/Syscall.h"
#include "thread/Scheduler.h"
#include "thread/Timer.h"
#include <luna/Common.h>
Result<u64> sys_alarm(Registers*, SyscallArgs args)
{
unsigned int seconds = (unsigned int)args[0];
auto* current = Scheduler::current();
TRY(check_pledge(current, Promise::p_stdio));
Clock* clock = nullptr;
u64 ticks_left = current->timer ? current->timer->clock->ticks_left(current->timer) : 0;
if (current->timer)
{
clock = current->timer->clock;
if (clock) clock->remove_from_timer_queue(current->timer);
}
else
current->timer = TRY(make<Timer>());
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;
clock->add_to_timer_queue(current->timer);
return (ticks_left * clock->resolution()) / 1'000'000'000;
}

View File

@ -107,6 +107,17 @@ Result<u64> sys_execve(Registers* regs, SyscallArgs args)
guard.deactivate();
// Reset all timers.
if (current->real_timer.clock) { current->real_timer.clock->remove_from_timer_queue(&current->real_timer); }
if (current->virtual_timer.clock)
{
current->virtual_timer.clock->remove_from_timer_queue(&current->virtual_timer);
}
if (current->profiling_timer.clock)
{
current->profiling_timer.clock->remove_from_timer_queue(&current->profiling_timer);
}
for (int i = 0; i < FD_MAX; i++)
{
auto& descriptor = current->fd_table[i];
@ -173,6 +184,9 @@ Result<u64> sys_fork(Registers* regs, SyscallArgs)
thread->pgid = current->pgid;
thread->sid = current->sid;
thread->virtual_clock.set_resolution(1'000'000);
thread->profiling_clock.set_resolution(1'000'000);
for (int i = 0; i < FD_MAX; i++) { thread->fd_table[i] = current->fd_table[i]; }
image->apply(thread);

View File

@ -0,0 +1,86 @@
#define _TIMESPEC_MACROS_INCLUDED
#include "Pledge.h"
#include "memory/MemoryManager.h"
#include "sys/Syscall.h"
#include "thread/Scheduler.h"
#include "thread/Timer.h"
#include <bits/itimer.h>
#include <luna/Common.h>
Result<u64> sys_setitimer(Registers*, SyscallArgs args)
{
int which = (int)args[0];
const struct itimerval* new_timer = (const struct itimerval*)args[1];
struct itimerval* old_timer = (struct itimerval*)args[2];
auto* current = Scheduler::current();
TRY(check_pledge(current, Promise::p_stdio));
Timer* timer;
Clock* clock;
switch (which)
{
case ITIMER_REAL:
timer = &current->real_timer;
clock = &g_realtime_clock;
break;
case ITIMER_VIRTUAL:
timer = &current->virtual_timer;
clock = &current->virtual_clock;
break;
case ITIMER_PROF:
timer = &current->profiling_timer;
clock = &current->profiling_clock;
break;
default: return err(EINVAL);
}
if (old_timer)
{
if (timer->clock)
{
struct itimerval result;
auto total = timer->clock->from_ticks(timer->total_ticks);
auto left = timer->clock->from_ticks(timer->clock->ticks_left(timer));
result.it_interval = TIMESPEC_TO_TIMEVAL(total);
result.it_value = TIMESPEC_TO_TIMEVAL(left);
if (!MemoryManager::copy_to_user_typed(old_timer, &result)) return err(EFAULT);
}
else
{
struct itimerval result;
memset(&result, 0, sizeof(result));
if (!MemoryManager::copy_to_user_typed(old_timer, &result)) return err(EFAULT);
}
}
if (new_timer)
{
if (timer->clock) timer->clock->remove_from_timer_queue(timer);
struct itimerval itimer;
if (!MemoryManager::copy_from_user_typed(new_timer, &itimer)) return err(EFAULT);
timer->signo = SIGALRM; // FIXME: Also use SIGVTALRM or SIGPROF for other timer types.
timer->thread = current;
if (itimer.it_interval.tv_sec != 0 || itimer.it_interval.tv_usec != 0)
{
timer->restart = true;
timer->total_ticks =
(itimer.it_interval.tv_sec * 1'000'000'000 + itimer.it_interval.tv_usec * 1000) / clock->resolution();
}
else
timer->restart = false;
if (itimer.it_value.tv_sec != 0 || itimer.it_value.tv_usec != 0)
{
timer->delta_ticks =
(itimer.it_value.tv_sec * 1'000'000'000 + itimer.it_value.tv_usec * 1000) / clock->resolution();
clock->add_to_timer_queue(timer);
}
}
return 0;
}

View File

@ -73,8 +73,6 @@ 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)
@ -159,3 +157,10 @@ u64 Clock::ticks_left(Timer* timer)
}
return total;
}
struct timespec Clock::from_ticks(u64 ticks)
{
u64 nanoseconds = ticks * m_resolution;
return timespec { .tv_sec = static_cast<time_t>(nanoseconds / 1'000'000'000),
.tv_nsec = static_cast<long>(nanoseconds % 1'000'000'000) };
}

View File

@ -19,6 +19,8 @@ struct Clock
void get_time(struct timespec& out);
long resolution();
struct timespec from_ticks(u64 ticks);
u64 ticks_left(Timer* timer);
private:

View File

@ -102,6 +102,9 @@ namespace Scheduler
thread->is_kernel = true;
thread->active_directory = MMU::kernel_page_directory();
thread->virtual_clock.set_resolution(1'000'000);
thread->profiling_clock.set_resolution(1'000'000);
thread->auth = Credentials { .uid = 0, .euid = 0, .suid = 0, .gid = 0, .egid = 0, .sgid = 0 };
g_threads.append(thread);
@ -217,11 +220,7 @@ namespace Scheduler
MemoryManager::unmap_owned_and_free_vm(stack.bottom(), stack.bytes() / ARCH_PAGE_SIZE).release_value();
}
if (thread->timer)
{
thread->timer->clock->remove_from_timer_queue(thread->timer);
delete thread->timer;
}
if (thread->real_timer.clock) { thread->real_timer.clock->remove_from_timer_queue(&thread->real_timer); }
delete thread;
@ -302,7 +301,12 @@ namespace Scheduler
if (is_in_kernel(regs)) g_current->kernel_ticks_self++;
else
{
g_current->virtual_clock.tick();
g_current->user_ticks_self++;
}
g_current->profiling_clock.tick();
g_current->ticks_left--;

View File

@ -98,7 +98,12 @@ struct Thread : public LinkedListNode<Thread>
mode_t umask { 0 };
Timer* timer { nullptr };
Timer real_timer;
Timer virtual_timer;
Timer profiling_timer;
Clock virtual_clock;
Clock profiling_clock;
StaticString<128> cmdline;

View File

@ -8,11 +8,11 @@ struct Clock;
class Timer : public LinkedListNode<Timer>
{
public:
u64 delta_ticks;
u64 total_ticks;
u64 delta_ticks { 0 };
u64 total_ticks { 0 };
Thread* thread;
int signo { SIGALRM };
bool restart { false };
Clock* clock;
Clock* clock { nullptr };
};

View File

@ -0,0 +1,18 @@
/* bits/itimer.h: Constants for setitimer() and getitimer(). */
#ifndef _BITS_ITIMER_H
#define _BITS_ITIMER_H
#include <bits/timespec.h>
#define ITIMER_REAL 0
#define ITIMER_VIRTUAL 1
#define ITIMER_PROF 2
struct itimerval
{
struct timeval it_interval;
struct timeval it_value;
};
#endif

View File

@ -33,4 +33,13 @@ struct timeval
} \
} while (0);
#endif
#define TIMEVAL_TO_TIMESPEC(x) \
{ \
.tv_sec = (x).tv_sec, .tv_nsec = (x).tv_usec * 1000 \
}
#define TIMESPEC_TO_TIMEVAL(x) \
{ \
.tv_sec = (x).tv_sec, .tv_usec = (x).tv_nsec / 1000 \
}
#endif

View File

@ -6,6 +6,7 @@
#define _INCLUDE_TIMESPEC_MACROS
#include <bits/attrs.h>
#include <bits/itimer.h>
#include <bits/timespec.h>
#ifdef __cplusplus
@ -25,6 +26,9 @@ extern "C"
/* Change a symlink's access and modification timestamps, with microsecond precision. */
int lutimes(const char* path, const struct timeval buf[2]);
/* Set an interval timer. */
int setitimer(int which, const struct itimerval* new_timer, struct itimerval* old_timer);
#ifdef __cplusplus
}
#endif

View File

@ -200,4 +200,10 @@ extern "C"
return ru.ru_utime.tv_sec * CLOCKS_PER_SEC + ru.ru_utime.tv_usec;
}
int setitimer(int which, const struct itimerval* new_timer, struct itimerval* old_timer)
{
long rc = syscall(SYS_setitimer, which, new_timer, old_timer);
__errno_return(rc, int);
}
}

View File

@ -11,6 +11,7 @@
#include <sys/mman.h>
#include <sys/stat.h>
#include <sys/syscall.h>
#include <sys/time.h>
#include <sys/utsname.h>
#include <unistd.h>
@ -519,7 +520,12 @@ extern "C"
unsigned int alarm(unsigned int seconds)
{
return (unsigned int)syscall(SYS_alarm, seconds);
struct itimerval old_value;
struct itimerval new_value;
memset(&new_value, 0, sizeof(new_value));
new_value.it_value.tv_sec = seconds;
if (setitimer(ITIMER_REAL, &new_value, &old_value) < 0) return 0;
return (unsigned int)old_value.it_value.tv_sec;
}
int pledge(const char* promises, const char* execpromises)