SchOS/kernel/sys/sys_time.c
Nexoniarz d0f7acf9eb Initial commit: Schunix as it stands before the SchOS rename
An x86-64 operating system built from xv6, now largely rewritten: SMP,
a copy-on-write root filesystem (SchFS), PCI/USB/virtio drivers, a TTF
rasteriser, and a Linux-numbered syscall ABI.

No history before this point -- the tree was never under version control.
This commit exists so the rename that follows has something to undo to.
2026-08-09 13:47:01 +02:00

139 lines
3.3 KiB
C

#include "types.h"
#include "defs.h"
#include "param.h"
#include "date.h"
#include "spinlock.h"
#include "proc.h"
#include "x86.h"
#include "syscall.h"
#include "posix.h"
#include "uaccess.h"
#include "errno.h"
addr_t
sys_alarm(void)
{
int seconds;
if (argint(0, &seconds) < 0)
return -1;
myproc()->alarm_ticks = seconds * 100;
return 0;
}
addr_t
sys_gettimeofday(void)
{
struct timeval *tv;
if (argptr(0, (char**)&tv, sizeof(*tv)) < 0)
return -1;
if (tv) {
// Real time, from the hardware clock read at boot plus uptime -- not
// uptime alone, which is what this used to return and why every machine
// thought it was 1970. See kernel/core/time.c.
uint64 sec, usec;
wallclock(&sec, &usec);
tv->tv_sec = (long)sec;
tv->tv_usec = (long)usec;
}
return 0;
}
addr_t
sys_nanosleep(void)
{
addr_t tsaddr, raw;
if (argaddr(0, &tsaddr) < 0 || fetchaddr(tsaddr, &raw) < 0)
return -1;
int64 sec = (int64)raw;
if (sec > 0) {
acquire(&tickslock);
uint t0 = ticks;
while (ticks - t0 < (uint)(sec * 100)) {
if (myproc()->killed) { release(&tickslock); return -EINTR; }
sleep(&ticks, &tickslock);
}
release(&tickslock);
}
return 0;
}
addr_t
sys_clock_gettime(void)
{
int clkid;
struct timespec *tp;
argint(0, &clkid);
if (argptr(1, (char**)&tp, sizeof(*tp)) < 0)
return -1;
// CLOCK_MONOTONIC (1) counts from boot; everything else is treated as a
// realtime clock and counts from the epoch. Returning boot-relative values
// for CLOCK_REALTIME is what made timestamps land in 1970.
uint64 sec, usec;
wallclock(&sec, &usec);
if (clkid == 1)
sec -= boot_epoch;
tp->tv_sec = (long)sec;
tp->tv_nsec = (long)(usec * 1000);
return 0;
}
addr_t sys_getitimer(void) { return 0; } // stub
addr_t
sys_setitimer(void)
{
int which;
addr_t newp;
argint(0, &which); argaddr(1, &newp);
// We don't implement interval timers; just track the alarm if it's ITIMER_REAL.
if (which == 0 && newp) {
struct itimerval iv;
if (copy_from_user(&iv, newp, sizeof(iv)) == 0)
myproc()->alarm_ticks = (int)(iv.it_value.tv_sec * 100 +
iv.it_value.tv_usec / 10000);
}
return 0;
}
addr_t
sys_time(void)
{
addr_t tloc;
argaddr(0, &tloc);
uint64 sec;
wallclock(&sec, 0);
long t = (long)sec;
if (tloc)
put_user(t, tloc);
return (addr_t)t;
}
addr_t
sys_clock_getres(void)
{
struct timespec *tp;
if (argptr(1, (char**)&tp, sizeof(*tp)) < 0) return 0;
if (tp) { tp->tv_sec = 0; tp->tv_nsec = 10000000L; } // 10ms resolution
return 0;
}
addr_t
sys_clock_nanosleep(void)
{
// Treat the same as nanosleep: arg2 is the timespec, arg1 is flags.
// Linux: clock_nanosleep(clockid, flags, rqtp, rmtp)
addr_t tsaddr, raw;
if (argaddr(2, &tsaddr) < 0 || fetchaddr(tsaddr, &raw) < 0)
return -1;
int64 sec = (int64)raw;
if (sec > 0) {
acquire(&tickslock);
uint t0 = ticks;
while (ticks - t0 < (uint)(sec * 100)) {
if (myproc()->killed) { release(&tickslock); return -EINTR; }
sleep(&ticks, &tickslock);
}
release(&tickslock);
}
return 0;
}