113 lines
3.1 KiB
C
113 lines
3.1 KiB
C
#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;
|
|
}
|