kernel+libc: Add setitimer()
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
c4d2847da1
commit
678121c3ed
@ -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
|
||||
|
@ -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
|
||||
{
|
||||
|
@ -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;
|
||||
}
|
@ -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(¤t->real_timer); }
|
||||
if (current->virtual_timer.clock)
|
||||
{
|
||||
current->virtual_timer.clock->remove_from_timer_queue(¤t->virtual_timer);
|
||||
}
|
||||
if (current->profiling_timer.clock)
|
||||
{
|
||||
current->profiling_timer.clock->remove_from_timer_queue(¤t->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);
|
||||
|
86
kernel/src/sys/setitimer.cpp
Normal file
86
kernel/src/sys/setitimer.cpp
Normal 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 = ¤t->real_timer;
|
||||
clock = &g_realtime_clock;
|
||||
break;
|
||||
case ITIMER_VIRTUAL:
|
||||
timer = ¤t->virtual_timer;
|
||||
clock = ¤t->virtual_clock;
|
||||
break;
|
||||
case ITIMER_PROF:
|
||||
timer = ¤t->profiling_timer;
|
||||
clock = ¤t->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;
|
||||
}
|
@ -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) };
|
||||
}
|
||||
|
@ -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:
|
||||
|
@ -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--;
|
||||
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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 };
|
||||
};
|
||||
|
18
libc/include/bits/itimer.h
Normal file
18
libc/include/bits/itimer.h
Normal 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
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
@ -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)
|
||||
|
Loading…
Reference in New Issue
Block a user