feat(time): time/clock/mktime/strftime/nanosleep
This commit is contained in:
@@ -0,0 +1,112 @@
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include <config.h>
|
||||
#endif
|
||||
|
||||
#include <errno.h>
|
||||
|
||||
#include <time.h>
|
||||
|
||||
#include "../internal/syscall.h"
|
||||
|
||||
/*
|
||||
* struct tms layout for SYS_times: four process-CPU clock-tick counters,
|
||||
* in kernel order (x86_64: four longs; the kernel ABI names it __kernel_tms).
|
||||
* It is private to this file; <sys/times.h> (a later todo) will own the
|
||||
* public definition.
|
||||
*/
|
||||
struct tms
|
||||
{
|
||||
clock_t tms_utime; /* user CPU time */
|
||||
clock_t tms_stime; /* system CPU time */
|
||||
clock_t tms_cutime; /* user CPU time of waited-for children */
|
||||
clock_t tms_cstime; /* system CPU time of waited-for children */
|
||||
};
|
||||
|
||||
/*
|
||||
* clock: the calling process's CPU time in CLOCKS_PER_SEC units.
|
||||
*
|
||||
* SYS_times reports CPU time in USER_HZ ticks (100 per second on x86_64),
|
||||
* so the tick counts are scaled by CLOCKS_PER_SEC / 100 == 10000 to the
|
||||
* 1 MHz clock() unit. On failure SYS_times returns -1 and clock() reports
|
||||
* (clock_t)-1 with errno set.
|
||||
*/
|
||||
clock_t
|
||||
clock(void)
|
||||
{
|
||||
struct tms t;
|
||||
|
||||
if (syscall_ret(__syscall1(SYS_times, (long)&t)) < 0)
|
||||
{
|
||||
return (clock_t)-1;
|
||||
}
|
||||
return (clock_t)((t.tms_utime + t.tms_stime) * (CLOCKS_PER_SEC / 100));
|
||||
}
|
||||
|
||||
/*
|
||||
* clock_gettime/clock_settime/clock_getres: raw kernel clock reads and
|
||||
* writes over SYS_clock_gettime(228)/SYS_clock_settime(227)/
|
||||
* SYS_clock_getres(229). The clock ids (CLOCK_REALTIME and friends) are
|
||||
* kernel ABI values and pass through unchanged; the struct timespec
|
||||
* arguments are the kernel's own layout.
|
||||
*/
|
||||
int
|
||||
clock_gettime(clockid_t clockid, struct timespec *tp)
|
||||
{
|
||||
return syscall_ret(__syscall2(SYS_clock_gettime, (long)clockid, (long)tp));
|
||||
}
|
||||
|
||||
int
|
||||
clock_settime(clockid_t clockid, const struct timespec *tp)
|
||||
{
|
||||
return syscall_ret(__syscall2(SYS_clock_settime, (long)clockid, (long)tp));
|
||||
}
|
||||
|
||||
int
|
||||
clock_getres(clockid_t clockid, struct timespec *res)
|
||||
{
|
||||
return syscall_ret(__syscall2(SYS_clock_getres, (long)clockid, (long)res));
|
||||
}
|
||||
|
||||
/*
|
||||
* clock_getcpuclockid: the clock id that measures a given process's CPU
|
||||
* time.
|
||||
*
|
||||
* The calling process (pid 0 or our own pid) is always reported as
|
||||
* CLOCK_PROCESS_CPUTIME_ID. Any other pid is encoded with the kernel's
|
||||
* CPUCLOCK_PID scheme — (~pid << 3) | 2 — and validated by probing that
|
||||
* clock with SYS_clock_getres, which the kernel answers with ESRCH when no
|
||||
* such process exists. That probe failing is the only errno write this
|
||||
* file performs on its own; every other path leaves errno to syscall_ret.
|
||||
*/
|
||||
int
|
||||
clock_getcpuclockid(pid_t pid, clockid_t *clock_id)
|
||||
{
|
||||
pid_t self = (pid_t)syscall_ret(__syscall0(SYS_getpid));
|
||||
clockid_t id;
|
||||
|
||||
if (pid == 0)
|
||||
{
|
||||
pid = self;
|
||||
}
|
||||
if (pid == self)
|
||||
{
|
||||
*clock_id = CLOCK_PROCESS_CPUTIME_ID;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Linux CPUCLOCK_PID encoding of a process clock id. */
|
||||
id = (clockid_t)((~(unsigned)pid << 3) | 2u);
|
||||
|
||||
/* Probe the encoded id; the kernel rejects unknown pids with ESRCH. */
|
||||
{
|
||||
struct timespec res;
|
||||
|
||||
if (syscall_ret(__syscall2(SYS_clock_getres, (long)id, (long)&res)) < 0)
|
||||
{
|
||||
errno = ESRCH;
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
*clock_id = id;
|
||||
return 0;
|
||||
}
|
||||
Reference in New Issue
Block a user