#include "core/types.h" #include "core/defs.h" #include "core/param.h" #include "core/date.h" #include "core/spinlock.h" #include "core/proc.h" #include "arch/x86.h" #include "core/syscall.h" #include "uapi/posix.h" #include "core/uaccess.h" #include "uapi/errno.h" addr_t sys_alarm(void) { int seconds; if (argint(0, &seconds) < 0) return -1; myproc()->alarm_ticks = seconds * HZ; 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 * HZ)) { 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 * HZ + iv.it_value.tv_usec / USEC_PER_TICK); } 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 * HZ)) { if (myproc()->killed) { release(&tickslock); return -EINTR; } sleep(&ticks, &tickslock); } release(&tickslock); } return 0; }