Improve system calls

- Wrap clock_getres()
- Wrap sched_setscheduler()
- Make sleep() api conformant
- Polyfill sleep() using select()
- Improve clock_gettime() polyfill
- Make nanosleep() POSIX conformant
- Slightly improve some DNS functions
- Further strengthen pledge() sandboxing
- Improve rounding of timeval / timespec
- Allow layering of pledge() calls on Linux
- Polyfill sched_yield() using select() on XNU
- Delete more system constants we probably don't need
This commit is contained in:
Justine Tunney 2022-07-08 06:29:24 -07:00
parent 5df3e4e7a8
commit 853b6c3864
330 changed files with 1971 additions and 1223 deletions

View file

@ -16,15 +16,15 @@
TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE.
*/
#include "libc/calls/math.h"
#include "libc/calls/struct/rusage.h"
#include "libc/macros.internal.h"
/**
* Adds resource usages.
* Accumulates resource statistics in `y` to `x`.
*/
void AddRusage(struct rusage *x, const struct rusage *y) {
x->ru_utime = AddTimeval(x->ru_utime, y->ru_utime);
x->ru_stime = AddTimeval(x->ru_stime, y->ru_stime);
void _addrusage(struct rusage *x, const struct rusage *y) {
x->ru_utime = _timeval_add(x->ru_utime, y->ru_utime);
x->ru_stime = _timeval_add(x->ru_stime, y->ru_stime);
x->ru_maxrss = MAX(x->ru_maxrss, y->ru_maxrss);
x->ru_ixrss += y->ru_ixrss;
x->ru_idrss += y->ru_idrss;

View file

@ -16,12 +16,12 @@
TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE.
*/
#include "libc/calls/math.h"
#include "libc/calls/struct/timeval.h"
/**
* Adds two microsecond timestamps.
*/
struct timeval AddTimeval(struct timeval x, struct timeval y) {
struct timeval _timeval_add(struct timeval x, struct timeval y) {
x.tv_sec += y.tv_sec;
x.tv_usec += y.tv_usec;
if (x.tv_usec >= 1000000) {

69
libc/calls/clock_getres.c Normal file
View file

@ -0,0 +1,69 @@
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi
Copyright 2022 Justine Alexandra Roberts Tunney
Permission to use, copy, modify, and/or distribute this software for
any purpose with or without fee is hereby granted, provided that the
above copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE.
*/
#include "libc/calls/asan.internal.h"
#include "libc/calls/strace.internal.h"
#include "libc/dce.h"
#include "libc/intrin/describeflags.internal.h"
#include "libc/sysv/consts/clock.h"
#include "libc/sysv/errfuns.h"
#include "libc/time/time.h"
int sys_clock_getres(int, struct timespec *) hidden;
static int sys_clock_getres_poly(int clock, struct timespec *ts, int64_t real) {
if (clock == CLOCK_REALTIME) {
ts->tv_sec = 0;
ts->tv_nsec = real;
return 0;
} else if (clock == CLOCK_MONOTONIC) {
ts->tv_sec = 0;
ts->tv_nsec = 1;
return 0;
} else {
return einval();
}
}
static int sys_clock_getres_nt(int clock, struct timespec *ts) {
return sys_clock_getres_poly(clock, ts, 100);
}
static int sys_clock_getres_xnu(int clock, struct timespec *ts) {
return sys_clock_getres_poly(clock, ts, 1000);
}
/**
* Returns granularity of clock.
*/
int clock_getres(int clock, struct timespec *ts) {
int rc;
if (!ts || (IsAsan() && !__asan_is_valid_timespec(ts))) {
rc = efault();
} else if (clock == 127) {
rc = einval(); // 127 is used by consts.sh to mean unsupported
} else if (IsWindows()) {
rc = sys_clock_getres_nt(clock, ts);
} else if (IsXnu()) {
rc = sys_clock_getres_xnu(clock, ts);
} else {
rc = sys_clock_getres(clock, ts);
}
STRACE("clock_getres(%d, [%s]) → %d% m", clock, DescribeTimespec(rc, ts), rc);
return rc;
}

View file

@ -0,0 +1,60 @@
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi
Copyright 2022 Justine Alexandra Roberts Tunney
Permission to use, copy, modify, and/or distribute this software for
any purpose with or without fee is hereby granted, provided that the
above copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE.
*/
#include "libc/bits/likely.h"
#include "libc/calls/clock_gettime.internal.h"
#include "libc/intrin/spinlock.h"
#include "libc/nexgen32e/rdtsc.h"
#include "libc/nexgen32e/threaded.h"
#include "libc/nexgen32e/x86feature.h"
#include "libc/sysv/consts/clock.h"
#include "libc/sysv/errfuns.h"
#include "libc/time/clockstonanos.internal.h"
#include "libc/time/time.h"
static struct {
bool once;
char lock;
uint64_t base;
struct timespec mono;
} g_mono;
int sys_clock_gettime_mono(struct timespec *ts) {
// this routine stops being monotonic after 194 years of uptime
uint64_t nanos;
struct timespec res;
if (X86_HAVE(INVTSC)) {
if (__threaded) {
_spinlock(&g_mono.lock);
}
if (UNLIKELY(!g_mono.once)) {
clock_gettime(CLOCK_REALTIME, &g_mono.mono);
g_mono.base = rdtsc();
g_mono.once = true;
}
nanos = ClocksToNanos(rdtsc(), g_mono.base);
res = g_mono.mono;
res.tv_sec += nanos / 1000000000;
res.tv_nsec += nanos % 1000000000;
_spunlock(&g_mono.lock);
*ts = res;
return 0;
} else {
return einval();
}
}

View file

@ -16,51 +16,22 @@
TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE.
*/
#include "libc/bits/likely.h"
#include "libc/calls/clock_gettime.internal.h"
#include "libc/calls/internal.h"
#include "libc/calls/struct/timespec.h"
#include "libc/fmt/conv.h"
#include "libc/intrin/kprintf.h"
#include "libc/intrin/spinlock.h"
#include "libc/nexgen32e/rdtsc.h"
#include "libc/nexgen32e/threaded.h"
#include "libc/nexgen32e/x86feature.h"
#include "libc/nt/struct/filetime.h"
#include "libc/nt/synchronization.h"
#include "libc/sysv/consts/clock.h"
#include "libc/sysv/errfuns.h"
#include "libc/time/clockstonanos.internal.h"
textwindows int sys_clock_gettime_nt(int clockid, struct timespec *ts) {
uint64_t nanos;
static bool once;
static char lock;
struct timespec res;
static uint64_t base;
textwindows int sys_clock_gettime_nt(int clock, struct timespec *ts) {
struct NtFileTime ft;
static struct timespec mono;
if (!ts) return efault();
if (clockid == CLOCK_REALTIME) {
if (clock == CLOCK_REALTIME) {
GetSystemTimeAsFileTime(&ft);
*ts = FileTimeToTimeSpec(ft);
return 0;
} else if ((clockid == CLOCK_MONOTONIC || clockid == CLOCK_MONOTONIC_RAW) &&
X86_HAVE(INVTSC)) {
// this routine stops being monotonic after 194 years of uptime
if (__threaded) _spinlock(&lock);
if (UNLIKELY(!once)) {
GetSystemTimeAsFileTime(&ft);
mono = FileTimeToTimeSpec(ft);
base = rdtsc();
once = true;
}
nanos = ClocksToNanos(rdtsc(), base);
res = mono;
res.tv_sec += nanos / 1000000000;
res.tv_nsec += nanos % 1000000000;
_spunlock(&lock);
*ts = res;
return 0;
} else if (clock == CLOCK_MONOTONIC) {
return sys_clock_gettime_mono(ts);
} else {
return einval();
}

View file

@ -17,19 +17,28 @@
PERFORMANCE OF THIS SOFTWARE.
*/
#include "libc/calls/calls.h"
#include "libc/calls/clock_gettime.internal.h"
#include "libc/calls/internal.h"
#include "libc/sysv/consts/clock.h"
#include "libc/sysv/errfuns.h"
int sys_clock_gettime_xnu(int clockid, struct timespec *ts) {
int sys_clock_gettime_xnu(int clock, struct timespec *ts) {
axdx_t ad;
ad = sys_gettimeofday((struct timeval *)ts, NULL, NULL);
if (ad.ax != -1) {
if (ad.ax) {
ts->tv_sec = ad.ax;
ts->tv_nsec = ad.dx;
if (clock == CLOCK_REALTIME) {
ad = sys_gettimeofday((struct timeval *)ts, 0, 0);
if (ad.ax != -1) {
if (ad.ax) {
ts->tv_sec = ad.ax;
ts->tv_nsec = ad.dx;
}
ts->tv_nsec *= 1000;
return 0;
} else {
return -1;
}
ts->tv_nsec *= 1000;
return 0;
} else if (clock == CLOCK_MONOTONIC) {
return sys_clock_gettime_mono(ts);
} else {
return -1;
return einval();
}
}

View file

@ -48,23 +48,25 @@
* __clock_gettime l: 35𝑐 11𝑛𝑠
* sys_clock_gettime l: 220𝑐 71𝑛𝑠
*
* @param clockid can be CLOCK_REALTIME, CLOCK_MONOTONIC, etc.
* @param clock can be CLOCK_REALTIME, CLOCK_MONOTONIC, etc.
* @param ts is where the result is stored
* @return 0 on success, or -1 w/ errno
* @error EINVAL if clockid isn't supported on this system
* @error EINVAL if clock isn't supported on this system
* @see strftime(), gettimeofday()
* @asyncsignalsafe
*/
int clock_gettime(int clockid, struct timespec *ts) {
int clock_gettime(int clock, struct timespec *ts) {
int rc;
if (IsAsan() && !__asan_is_valid_timespec(ts)) {
if (clock == 127) {
rc = einval(); // 127 is used by consts.sh to mean unsupported
} else if (!ts || (IsAsan() && !__asan_is_valid_timespec(ts))) {
rc = efault();
} else {
rc = __clock_gettime(clockid, ts);
rc = __clock_gettime(clock, ts);
}
#if SYSDEBUG
if (!__time_critical) {
STRACE("clock_gettime(%d, [%s]) → %d% m", clockid, DescribeTimespec(rc, ts),
STRACE("clock_gettime(%d, [%s]) → %d% m", clock, DescribeTimespec(rc, ts),
rc);
}
#endif

View file

@ -9,6 +9,7 @@ typedef int clock_gettime_f(int, struct timespec *);
extern clock_gettime_f *__clock_gettime;
clock_gettime_f *__clock_gettime_get(bool *) hidden;
int __clock_gettime_init(int, struct timespec *) hidden;
int sys_clock_gettime_mono(struct timespec *) hidden;
COSMOPOLITAN_C_END_
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */

View file

@ -1,15 +0,0 @@
#ifndef COSMOPOLITAN_LIBC_CALLS_MATH_H_
#define COSMOPOLITAN_LIBC_CALLS_MATH_H_
#include "libc/calls/struct/rusage.h"
#include "libc/calls/struct/timespec.h"
#include "libc/calls/struct/timeval.h"
#if !(__ASSEMBLER__ + __LINKER__ + 0)
COSMOPOLITAN_C_START_
struct timeval AddTimeval(struct timeval, struct timeval);
struct timespec AddTimespec(struct timespec, struct timespec);
void AddRusage(struct rusage *, const struct rusage *);
COSMOPOLITAN_C_END_
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
#endif /* COSMOPOLITAN_LIBC_CALLS_MATH_H_ */

View file

@ -16,64 +16,84 @@
TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE.
*/
#include "libc/assert.h"
#include "libc/calls/internal.h"
#include "libc/calls/sig.internal.h"
#include "libc/calls/state.internal.h"
#include "libc/calls/strace.internal.h"
#include "libc/errno.h"
#include "libc/limits.h"
#include "libc/macros.internal.h"
#include "libc/nexgen32e/rdtsc.h"
#include "libc/nt/errors.h"
#include "libc/nt/nt/time.h"
#include "libc/nt/synchronization.h"
#include "libc/sysv/consts/clock.h"
#include "libc/sysv/errfuns.h"
#include "libc/time/clockstonanos.internal.h"
textwindows noinstrument int sys_nanosleep_nt(const struct timespec *req,
struct timespec *rem) {
int rc;
textwindows int sys_nanosleep_nt(const struct timespec *req,
struct timespec *rem) {
bool alertable;
uint32_t slice;
int64_t ms, sec, nsec;
uint64_t begin;
int64_t ms, toto, nanos;
struct timespec elapsed;
// check req is legal timespec
if (!(0 <= req->tv_nsec && req->tv_nsec < 1000000000)) {
return einval();
}
// save beginning timestamp
if (!__time_critical && rem) {
begin = rdtsc();
} else {
begin = 0; // to prevent uninitialized warning
}
// convert timespec to milliseconds
if (__builtin_mul_overflow(req->tv_sec, 1000, &ms) ||
__builtin_add_overflow(ms, req->tv_nsec / 1000000, &ms)) {
__builtin_add_overflow(ms, (req->tv_nsec + 999999) / 1000000, &ms)) {
ms = INT64_MAX;
}
if (!ms && (req->tv_sec || req->tv_nsec)) {
ms = 1;
}
rc = 0;
do {
for (toto = ms;;) {
// check if signal was delivered
if (!__time_critical && _check_interrupts(false, g_fds.p)) {
rc = eintr();
break;
if (rem) {
nanos = ClocksToNanos(rdtsc(), begin);
elapsed.tv_sec = nanos / 1000000000;
elapsed.tv_nsec = nanos % 1000000000;
*rem = _timespec_sub(*req, elapsed);
if (rem->tv_sec < 0) {
rem->tv_sec = 0;
rem->tv_nsec = 0;
}
}
return eintr();
}
// configure the sleep
slice = MIN(__SIG_POLLING_INTERVAL_MS, ms);
if (__time_critical) {
alertable = false;
} else {
alertable = true;
POLLTRACE("sys_nanosleep_nt polling for %'ldms of %'ld");
POLLTRACE("... sleeping %'ldms of %'ld", toto - ms, toto);
}
// perform the sleep
if (SleepEx(slice, alertable) == kNtWaitIoCompletion) {
POLLTRACE("IOCP EINTR");
POLLTRACE("IOCP EINTR"); // in case we ever figure it out
continue;
}
ms -= slice;
} while (ms > 0);
ms = MAX(ms, 0);
if (rem) {
sec = ms / 1000;
nsec = ms % 1000 * 1000000000;
rem->tv_nsec -= nsec;
if (rem->tv_nsec < 0) {
--rem->tv_sec;
rem->tv_nsec = 1000000000 - rem->tv_nsec;
}
rem->tv_sec -= sec;
if (rem->tv_sec < 0) {
rem->tv_sec = 0;
rem->tv_nsec = 0;
// check if full duration has elapsed
if ((ms -= slice) <= 0) {
if (rem) {
rem->tv_sec = 0;
rem->tv_nsec = 0;
}
return 0;
}
}
return rc;
}

View file

@ -16,15 +16,43 @@
TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE.
*/
#include "libc/calls/calls.h"
#include "libc/calls/internal.h"
#include "libc/calls/struct/timespec.h"
#include "libc/calls/struct/timeval.h"
#include "libc/macros.internal.h"
#include "libc/nexgen32e/nexgen32e.h"
#include "libc/errno.h"
#include "libc/fmt/conv.h"
#include "libc/sock/internal.h"
#include "libc/sysv/consts/clock.h"
int sys_nanosleep_xnu(const struct timespec *req, struct timespec *rem) {
long millis;
millis = req->tv_nsec / 1000;
millis = MAX(1, millis);
return sys_select(0, 0, 0, 0, &(struct timeval){req->tv_sec, millis});
int rc;
axdx_t axdx;
struct timeval tv;
struct timespec begin, end, elapsed;
if (rem) {
if (sys_clock_gettime_xnu(CLOCK_MONOTONIC, &begin) == -1) {
return -1;
}
}
tv = _timespec2timeval(*req);
rc = sys_select(0, 0, 0, 0, &tv);
if (rem) {
if (!rc) {
rem->tv_sec = 0;
rem->tv_nsec = 0;
} else if (rc == -1 && errno == EINTR) {
sys_clock_gettime_xnu(CLOCK_MONOTONIC, &end);
elapsed = _timespec_sub(end, begin);
*rem = _timespec_sub(*req, elapsed);
if (rem->tv_sec < 0) {
rem->tv_sec = 0;
rem->tv_nsec = 0;
}
}
}
return rc;
}

View file

@ -27,10 +27,26 @@
/**
* Sleeps for a particular amount of time.
*
* @param req is the duration of time we should sleep
* @param rem if non-NULL will receive the amount of time that wasn't
* slept because a signal was delivered. If no signal's delivered
* then this value will be set to `{0, 0}`. It's also fine to set
* this value to the same pointer as `req`.
* @return 0 on success, or -1 w/ errno
* @raise EINVAL if `req->tv_nsec [0,1000000000)`
* @raise EINTR if a signal was delivered, and `rem` is updated
* @raise EFAULT if `req` is NULL or `req` / `rem` is a bad pointer
* @raise ENOSYS on bare metal
* @note POSIX.1 specifies nanosleep() measures against `CLOCK_REALTIME`
* however Linux measures uses `CLOCK_MONOTONIC`. This shouldn't
* matter, since POSIX.1 further specifies that discontinuous
* changes in `CLOCK_REALTIME` shouldn't impact nanosleep()
* @norestart
*/
noinstrument int nanosleep(const struct timespec *req, struct timespec *rem) {
int nanosleep(const struct timespec *req, struct timespec *rem) {
int rc;
if (!req || (IsAsan() && (!__asan_is_valid_timespec(req) ||
(rem && !__asan_is_valid_timespec(rem))))) {
rc = efault();
@ -46,9 +62,21 @@ noinstrument int nanosleep(const struct timespec *req, struct timespec *rem) {
} else {
rc = sys_nanosleep_nt(req, rem);
}
// Linux Kernel doesn't change the remainder value on success, but
// some kernels like OpenBSD will. POSIX doesn't specify the Linux
// behavior. So we polyfill it here.
if (!rc && rem) {
rem->tv_sec = 0;
rem->tv_nsec = 0;
}
#if defined(SYSDEBUG) && _POLLTRACE
if (!__time_critical) {
POLLTRACE("nanosleep(%s, [%s]) → %d% m", DescribeTimespec(rc, req),
DescribeTimespec(rc, rem), rc);
}
#endif
return rc;
}

50
libc/calls/pause-nt.c Normal file
View file

@ -0,0 +1,50 @@
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi
Copyright 2022 Justine Alexandra Roberts Tunney
Permission to use, copy, modify, and/or distribute this software for
any purpose with or without fee is hereby granted, provided that the
above copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE.
*/
#include "libc/calls/internal.h"
#include "libc/calls/sig.internal.h"
#include "libc/calls/strace.internal.h"
#include "libc/calls/syscall_support-nt.internal.h"
#include "libc/nt/errors.h"
#include "libc/nt/synchronization.h"
#include "libc/sysv/errfuns.h"
textwindows int sys_pause_nt(void) {
long ms, totoms;
ms = 0;
totoms = 0;
for (;;) {
if (_check_interrupts(false, g_fds.p)) {
return eintr();
}
if (SleepEx(__SIG_POLLING_INTERVAL_MS, true) == kNtWaitIoCompletion) {
POLLTRACE("IOCP EINTR"); // in case we ever figure it out
continue;
}
#if defined(SYSDEBUG) && defined(_POLLTRACE)
ms += __SIG_POLLING_INTERVAL_MS;
if (ms >= __SIG_LOGGING_INTERVAL_MS) {
totoms += ms, ms = 0;
POLLTRACE("... pausing for %'lums...", totoms);
}
#endif
}
}

View file

@ -18,34 +18,51 @@
*/
#include "libc/calls/calls.h"
#include "libc/calls/strace.internal.h"
#include "libc/calls/struct/sigset.h"
#include "libc/calls/syscall-sysv.internal.h"
#include "libc/calls/syscall_support-nt.internal.h"
#include "libc/dce.h"
#include "libc/errno.h"
#include "libc/nt/synchronization.h"
#include "libc/sysv/consts/sig.h"
#include "libc/sysv/errfuns.h"
#include "libc/sock/internal.h"
/**
* Waits for signal.
*
* This suspends execution until an unmasked signal is delivered and its
* callback function has been called. The current signal mask is used.
* This suspends execution until an unmasked signal is delivered. If the
* signal delivery kills the process, this won't return. The signal mask
* of the current thread is used. If a signal handler exists, this shall
* return after it's been invoked.
*
* @return should always be -1 w/ EINTR
* This function is equivalent to:
*
* select(0, 0, 0, 0, 0);
*
* However this has a tinier footprint and better logging.
*
* @return -1 w/ errno set to EINTR
* @see sigsuspend()
* @norestart
*/
int pause(void) {
int e, rc;
sigset_t mask;
e = errno;
int rc;
STRACE("pause() → [...]");
if ((rc = sys_pause()) == -1 && errno == ENOSYS) {
errno = e;
if (sigprocmask(SIG_BLOCK, 0, &mask) == -1) return -1;
rc = sigsuspend(&mask);
if (!IsWindows()) {
// We'll polyfill pause() using select() with a null timeout, which
// should hopefully do the same thing, which means wait forever but
// the usual signal interrupt rules apply.
//
// "If the readfds, writefds, and errorfds arguments are all null
// pointers and the timeout argument is not a null pointer, the
// pselect() or select() function shall block for the time
// specified, or until interrupted by a signal. If the readfds,
// writefds, and errorfds arguments are all null pointers and the
// timeout argument is a null pointer, the pselect() or select()
// function shall block until interrupted by a signal." ──Quoth
// IEEE 1003.1-2017 §functions/select
//
rc = sys_select(0, 0, 0, 0, 0);
} else {
rc = sys_pause_nt();
}
STRACE("[...] pause → %d% m", rc);
return rc;
}

View file

@ -26,7 +26,7 @@
/**
* Tunes process on Linux.
*
* @raise ENOSYS on non-Linux.
* @raise ENOSYS on non-Linux
*/
privileged int prctl(int operation, ...) {
int rc;

View file

@ -0,0 +1,33 @@
#ifndef COSMOPOLITAN_LIBC_CALLS_SCHED_SYSV_INTERNAL_H_
#define COSMOPOLITAN_LIBC_CALLS_SCHED_SYSV_INTERNAL_H_
#include "libc/calls/struct/sched_param.h"
#if !(__ASSEMBLER__ + __LINKER__ + 0)
COSMOPOLITAN_C_START_
#define MAXCPUS_NETBSD 256
#define MAXCPUS_OPENBSD 64
#define P_ALL_LWPS 0 /* for effect on all threads in pid */
int sys_sched_get_priority_max(int);
int sys_sched_get_priority_min(int);
int sys_sched_getparam(int, struct sched_param *);
int sys_sched_getscheduler(int);
int sys_sched_setaffinity(int, uint64_t, const void *) hidden;
int sys_sched_setparam(int, const struct sched_param *);
int sys_sched_setscheduler(int, int, const struct sched_param *);
int sys_sched_yield(void) hidden;
int64_t sys_sched_getaffinity(int, uint64_t, void *) hidden;
int sys_sched_getscheduler_netbsd(int);
int sys_sched_setparam_netbsd(int, int, int, const struct sched_param *) //
asm("sys_sched_setparam");
int sys_sched_getparam_netbsd(int, int, int *, struct sched_param *) //
asm("sys_sched_getparam");
int sys_sched_setaffinity_netbsd(int, int, size_t, const void *) //
asm("sys_sched_setaffinity");
int sys_sched_getaffinity_netbsd(int, int, size_t, void *) //
asm("sys_sched_setaffinity");
COSMOPOLITAN_C_END_
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
#endif /* COSMOPOLITAN_LIBC_CALLS_SCHED_SYSV_INTERNAL_H_ */

View file

@ -0,0 +1,53 @@
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi
Copyright 2022 Justine Alexandra Roberts Tunney
Permission to use, copy, modify, and/or distribute this software for
any purpose with or without fee is hereby granted, provided that the
above copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE.
*/
#include "libc/calls/calls.h"
#include "libc/calls/sched-sysv.internal.h"
#include "libc/calls/strace.internal.h"
#include "libc/dce.h"
#include "libc/intrin/describeflags.internal.h"
#include "libc/sysv/consts/sched.h"
#include "libc/sysv/errfuns.h"
static int sys_sched_get_priority_max_netbsd(int policy) {
if (policy == SCHED_OTHER) {
return -1;
} else if (policy == SCHED_RR || policy == SCHED_FIFO) {
return 63; // NetBSD Libc needs 19 system calls to compute this!
} else {
return einval();
}
}
/**
* Returns maximum `sched_param::sched_priority` for `policy`.
*
* @return priority, or -1 w/ errno
* @raise ENOSYS on XNU, Windows, OpenBSD
* @raise EINVAL if `policy` is invalid
*/
int sched_get_priority_max(int policy) {
int rc;
if (IsNetbsd()) {
rc = sys_sched_get_priority_max_netbsd(policy);
} else {
rc = sys_sched_get_priority_max(policy);
}
STRACE("sched_get_priority_max(%s) → %d% m", DescribeSchedPolicy(policy), rc);
return rc;
}

View file

@ -0,0 +1,53 @@
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi
Copyright 2022 Justine Alexandra Roberts Tunney
Permission to use, copy, modify, and/or distribute this software for
any purpose with or without fee is hereby granted, provided that the
above copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE.
*/
#include "libc/calls/calls.h"
#include "libc/calls/sched-sysv.internal.h"
#include "libc/calls/strace.internal.h"
#include "libc/dce.h"
#include "libc/intrin/describeflags.internal.h"
#include "libc/sysv/consts/sched.h"
#include "libc/sysv/errfuns.h"
static int sys_sched_get_priority_min_netbsd(int policy) {
if (policy == SCHED_OTHER) {
return -1;
} else if (policy == SCHED_RR || policy == SCHED_FIFO) {
return 0; // NetBSD Libc needs 19 system calls to compute this!
} else {
return einval();
}
}
/**
* Returns minimum `sched_param::sched_priority` for `policy`.
*
* @return priority, or -1 w/ errno
* @raise ENOSYS on XNU, Windows, OpenBSD
* @raise EINVAL if `policy` is invalid
*/
int sched_get_priority_min(int policy) {
int rc;
if (IsNetbsd()) {
rc = sys_sched_get_priority_min_netbsd(policy);
} else {
rc = sys_sched_get_priority_min(policy);
}
STRACE("sched_get_priority_min(%s) → %d% m", DescribeSchedPolicy(policy), rc);
return rc;
}

View file

@ -17,6 +17,7 @@
PERFORMANCE OF THIS SOFTWARE.
*/
#include "libc/calls/calls.h"
#include "libc/calls/sched-sysv.internal.h"
#include "libc/calls/strace.internal.h"
#include "libc/calls/syscall-sysv.internal.h"
#include "libc/str/str.h"

View file

@ -0,0 +1,28 @@
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi
Copyright 2022 Justine Alexandra Roberts Tunney
Permission to use, copy, modify, and/or distribute this software for
any purpose with or without fee is hereby granted, provided that the
above copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE.
*/
#include "libc/calls/sched-sysv.internal.h"
#include "libc/calls/struct/sched_param.h"
/**
* Gets scheduler policy parameter.
* @raise ENOSYS on XNU, Windows
*/
int sched_getparam(int pid, struct sched_param *param) {
return sys_sched_getparam(pid, param);
}

View file

@ -0,0 +1,31 @@
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi
Copyright 2022 Justine Alexandra Roberts Tunney
Permission to use, copy, modify, and/or distribute this software for
any purpose with or without fee is hereby granted, provided that the
above copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE.
*/
#include "libc/calls/calls.h"
#include "libc/calls/sched-sysv.internal.h"
#include "libc/calls/struct/sched_param.h"
int sys_sched_getscheduler_netbsd(int pid) {
int policy;
struct sched_param sp;
if (sys_sched_getparam_netbsd(pid, P_ALL_LWPS, &policy, &sp) != -1) {
return policy;
} else {
return -1;
}
}

View file

@ -0,0 +1,39 @@
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi
Copyright 2022 Justine Alexandra Roberts Tunney
Permission to use, copy, modify, and/or distribute this software for
any purpose with or without fee is hereby granted, provided that the
above copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE.
*/
#include "libc/calls/sched-sysv.internal.h"
#include "libc/calls/strace.internal.h"
#include "libc/calls/struct/sched_param.h"
#include "libc/dce.h"
/**
* Gets scheduler policy for `pid`.
*
* @param pid is id of process (where 0 is same as getpid())
* @return scheduler policy, or -1 w/ errno
*/
int sched_getscheduler(int pid) {
int rc;
if (IsNetbsd()) {
rc = sys_sched_getscheduler_netbsd(pid);
} else {
rc = sys_sched_getscheduler(pid);
}
STRACE("sched_getscheduler(%d) → %d% m", pid, rc);
return rc;
}

View file

@ -18,6 +18,7 @@
*/
#include "libc/bits/safemacros.internal.h"
#include "libc/calls/calls.h"
#include "libc/calls/sched-sysv.internal.h"
#include "libc/calls/strace.internal.h"
#include "libc/calls/syscall-sysv.internal.h"
#include "libc/calls/syscall_support-nt.internal.h"

View file

@ -0,0 +1,28 @@
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi
Copyright 2022 Justine Alexandra Roberts Tunney
Permission to use, copy, modify, and/or distribute this software for
any purpose with or without fee is hereby granted, provided that the
above copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE.
*/
#include "libc/calls/sched-sysv.internal.h"
#include "libc/calls/struct/sched_param.h"
/**
* Sets scheduler policy parameter.
* @raise ENOSYS on XNU, Windows
*/
int sched_setparam(int pid, const struct sched_param *param) {
return sys_sched_setparam(pid, param);
}

View file

@ -0,0 +1,106 @@
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi
Copyright 2022 Justine Alexandra Roberts Tunney
Permission to use, copy, modify, and/or distribute this software for
any purpose with or without fee is hereby granted, provided that the
above copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE.
*/
#include "libc/calls/sched-sysv.internal.h"
#include "libc/calls/strace.internal.h"
#include "libc/calls/struct/sched_param.h"
#include "libc/dce.h"
#include "libc/intrin/describeflags.internal.h"
#include "libc/nexgen32e/threaded.h"
#include "libc/str/str.h"
#include "libc/sysv/errfuns.h"
/**
* Sets scheduling policy of process, e.g.
*
* struct sched_param p = {sched_get_priority_max(SCHED_OTHER)};
* LOGIFNEG1(sched_setscheduler(0, SCHED_OTHER, &p));
*
* Processes with numerically higher priority values are scheduled
* before processes with numerically lower priority values.
*
* @param pid is the id of the process whose scheduling policy should be
* changed. This applies to all threads associated with the process.
* Linux is special; the kernel treats this as a thread id (noting
* that `getpid() == gettid()` is always the case on Linux for the
* main thread) and will only take effect for the specified tid.
* Therefore this function is POSIX-compliant iif `!__threaded`.
* Setting `pid` to zero means the same thing as getpid().
*
* @param policy specifies the kernel's timesharing strategy.
*
* The `policy` must have one of:
*
* - `SCHED_OTHER` (or `SCHED_NORMAL`) for the default policy
* - `SCHED_RR` for real-time round-robin scheduling
* - `SCHED_FIFO` for real-time first-in first-out scheduling
* - `SCHED_BATCH` for "batch" style execution of processes if
* supported (Linux), otherwise it's treated as `SCHED_OTHER`
* - `SCHED_IDLE` for running very low priority background jobs
* if it's supported (Linux), otherwise this is `SCHED_OTHER`
*
* The `policy` may optionally bitwise-or any one of:
*
* - `SCHED_RESET_ON_FORK` will cause the scheduling policy to be
* automatically reset to `SCHED_NORMAL` upon fork() if supported;
* otherwise this flag is polyfilled as zero, so that it may be
* safely used (without having to check if the o/s is Linux).
*
* @param param must be set to the scheduler parameter, which should be
* greater than or equal to sched_get_priority_min(policy) and less
* than or equal to sched_get_priority_max(policy). Linux allows the
* static priority range 1 to 99 for the `SCHED_FIFO` and `SCHED_RR`
* policies, and the priority 0 for the remaining policies.
*
* @return the former scheduling policy of the specified process. If
* this function fails, then the scheduling policy is not changed,
* and -1 w/ errno is returned.
*
* @raise ENOSYS on XNU, Windows, OpenBSD
* @raise EPERM if not authorized to use scheduler in question (e.g.
* trying to use a real-time scheduler as non-root on Linux) or
* possibly because pledge() was used and isn't allowing this
* @raise EINVAL if `param` is NULL
* @raise EINVAL if `policy` is invalid
* @raise EINVAL if `param` has value out of ranges defined by `policy`
*/
int sched_setscheduler(int pid, int policy, const struct sched_param *param) {
int rc, old;
if (IsNetbsd()) {
rc = sys_sched_getscheduler_netbsd(pid);
} else {
rc = sys_sched_getscheduler(pid);
}
if (rc != -1) {
old = rc;
if (IsNetbsd()) {
rc = sys_sched_setparam_netbsd(pid, P_ALL_LWPS, policy, param);
} else {
rc = sys_sched_setscheduler(pid, policy, param);
}
if (rc != -1) {
rc = old;
}
}
STRACE("sched_setscheduler(%d, %s, %s) → %d% m", pid,
DescribeSchedPolicy(policy), DescribeSchedParam(param), rc);
return rc;
}

View file

@ -1,14 +0,0 @@
#ifndef COSMOPOLITAN_LIBC_CALLS_SCHED_H_
#define COSMOPOLITAN_LIBC_CALLS_SCHED_H_
#include "libc/calls/struct/sched_param.h"
#if !(__ASSEMBLER__ + __LINKER__ + 0)
COSMOPOLITAN_C_START_
int sched_setscheduler(int, int, const struct sched_param *);
int sched_getscheduler(int);
int sched_setparam(int, const struct sched_param *);
int sched_getparam(int, struct sched_param *);
COSMOPOLITAN_C_END_
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
#endif /* COSMOPOLITAN_LIBC_CALLS_SCHED_H_ */

View file

@ -26,6 +26,7 @@
#include "libc/dce.h"
#include "libc/errno.h"
#include "libc/fmt/conv.h"
#include "libc/intrin/kprintf.h"
#include "libc/log/check.h"
#include "libc/math.h"
#include "libc/nexgen32e/nexgen32e.h"
@ -80,6 +81,7 @@ textwindows void _check_sigalrm(void) {
textwindows int sys_setitimer_nt(int which, const struct itimerval *newvalue,
struct itimerval *out_opt_oldvalue) {
long double elapsed, untilnext;
if (which != ITIMER_REAL ||
(newvalue && (!(0 <= newvalue->it_value.tv_usec &&
newvalue->it_value.tv_usec < 1000000) ||
@ -87,6 +89,7 @@ textwindows int sys_setitimer_nt(int which, const struct itimerval *newvalue,
newvalue->it_interval.tv_usec < 1000000)))) {
return einval();
}
if (out_opt_oldvalue) {
if (__hastimer) {
elapsed = nowl() - __lastalrm;
@ -106,6 +109,7 @@ textwindows int sys_setitimer_nt(int which, const struct itimerval *newvalue,
out_opt_oldvalue->it_value.tv_usec = 0;
}
}
if (newvalue) {
if (newvalue->it_interval.tv_sec || newvalue->it_interval.tv_usec ||
newvalue->it_value.tv_sec || newvalue->it_value.tv_usec) {
@ -124,5 +128,6 @@ textwindows int sys_setitimer_nt(int which, const struct itimerval *newvalue,
__hastimer = false;
}
}
return 0;
}

View file

@ -16,16 +16,32 @@
TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE.
*/
#include "libc/calls/strace.internal.h"
#include "libc/calls/struct/timespec.h"
#include "libc/sysv/errfuns.h"
#include "libc/errno.h"
#include "libc/limits.h"
#include "libc/time/time.h"
/**
* Sleeps for a particular amount of time.
* Sleeps for particular number of seconds.
*
* @return 0 if the full time elapsed, otherwise we assume an interrupt
* was delivered, in which case the errno condition is ignored, and
* this function shall return the number of unslept seconds rounded
* using the ceiling function
* @see nanosleep(), usleep()
* @asyncsignalsafe
* @norestart
*/
int sleep(uint32_t seconds) {
return nanosleep(&(struct timespec){seconds, 0}, NULL);
unsigned sleep(unsigned seconds) {
int err;
unsigned unslept;
struct timespec tv = {seconds};
err = errno;
nanosleep(&tv, &tv);
errno = err;
unslept = tv.tv_sec;
if (tv.tv_nsec && unslept < UINT_MAX) {
++unslept;
}
return unslept;
}

View file

@ -6,8 +6,8 @@ COSMOPOLITAN_C_START_
#define BPF_MAXINSNS 4096
#define BPF_CLASS(code) ((code)&0x07)
#define BPF_LD 0x00 /* load ops */
#define BPF_LDX 0x01 /* load into register */
#define BPF_LD 0x00 /* load into accumulator */
#define BPF_LDX 0x01 /* load into index register */
#define BPF_ST 0x02 /* store from immediate */
#define BPF_STX 0x03 /* store from register */
#define BPF_ALU 0x04 /* 32-bit arithmetic */
@ -19,6 +19,7 @@ COSMOPOLITAN_C_START_
#define BPF_W 0x00 /* 32-bit */
#define BPF_H 0x08 /* 16-bit */
#define BPF_B 0x10 /* 8-bit */
#define BPF_DW 0x18 /* 64-bit (eBPF only) */
#define BPF_MODE(code) ((code)&0xe0)
#define BPF_IMM 0x00 /* 64-bit immediate */
@ -52,7 +53,6 @@ COSMOPOLITAN_C_START_
#define BPF_JMP32 0x06
#define BPF_ALU64 0x07
#define BPF_DW 0x18
#define BPF_ATOMIC 0xc0
#define BPF_XADD 0xc0
#define BPF_MOV 0xb0

View file

@ -25,6 +25,7 @@ struct rusage {
int getrusage(int, struct rusage *);
int wait3(int *, int, struct rusage *);
int wait4(int, int *, int, struct rusage *);
void _addrusage(struct rusage *, const struct rusage *);
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
#endif /* COSMOPOLITAN_LIBC_CALLS_STRUCT_RUSAGE_H_ */

View file

@ -6,5 +6,12 @@ struct sched_param {
int32_t sched_priority;
};
int sched_get_priority_max(int);
int sched_get_priority_min(int);
int sched_getparam(int, struct sched_param *);
int sched_getscheduler(int);
int sched_setparam(int, const struct sched_param *);
int sched_setscheduler(int, int, const struct sched_param *);
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
#endif /* COSMOPOLITAN_LIBC_CALLS_STRUCT_SCHED_PARAM_H_ */

View file

@ -8,6 +8,9 @@ struct timespec {
};
int sys_futex(int *, int, int, const struct timespec *, int *);
bool _timespec_gt(struct timespec, struct timespec);
struct timespec _timespec_add(struct timespec, struct timespec);
struct timespec _timespec_sub(struct timespec, struct timespec);
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
#endif /* COSMOPOLITAN_LIBC_CALLS_STRUCT_TIMESPEC_H_ */

View file

@ -0,0 +1,34 @@
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi
Copyright 2022 Justine Alexandra Roberts Tunney
Permission to use, copy, modify, and/or distribute this software for
any purpose with or without fee is hereby granted, provided that the
above copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE.
*/
#include "libc/calls/struct/timespec.h"
/**
* Returns true if timespec `x` is greater than `y`.
*/
bool _timespec_gt(struct timespec x, struct timespec y) {
if (x.tv_sec > y.tv_sec) {
return true;
}
if (x.tv_sec == y.tv_sec) {
if (x.tv_nsec > y.tv_nsec) {
return true;
}
}
return false;
}

View file

@ -8,6 +8,7 @@ struct timeval {
};
int lutimes(const char *, const struct timeval[2]);
struct timeval _timeval_add(struct timeval, struct timeval);
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
#endif /* COSMOPOLITAN_LIBC_CALLS_STRUCT_TIMEVAL_H_ */

View file

@ -74,8 +74,6 @@ i32 sys_pipe2(i32[hasatleast 2], u32) hidden;
i32 sys_pledge(const char *, const char *) hidden;
i32 sys_posix_openpt(i32) hidden;
i32 sys_renameat(i32, const char *, i32, const char *) hidden;
i32 sys_sched_setaffinity(i32, u64, const void *) hidden;
i32 sys_sched_yield(void) hidden;
i32 sys_setgid(i32) hidden;
i32 sys_setpgid(i32, i32) hidden;
i32 sys_setpriority(i32, u32, i32) hidden;
@ -103,7 +101,6 @@ i64 sys_pwrite(i32, const void *, u64, i64, i64) hidden;
i64 sys_read(i32, void *, u64) hidden;
i64 sys_readlink(const char *, char *, u64) hidden;
i64 sys_readlinkat(int, const char *, char *, u64) hidden;
i64 sys_sched_getaffinity(i32, u64, void *) hidden;
i64 sys_sendfile(i32, i32, i64 *, u64) hidden;
i64 sys_splice(i32, i64 *, i32, i64 *, u64, u32) hidden;
i64 sys_write(i32, const void *, u64) hidden;

View file

@ -13,6 +13,7 @@ int __mkntpath2(const char *, char16_t[hasatleast PATH_MAX], int) hidden;
int __mkntpathat(int, const char *, int, char16_t[hasatleast PATH_MAX]) hidden;
int __sample_pids(int[hasatleast 64], int64_t[hasatleast 64], bool) hidden;
int ntaccesscheck(const char16_t *, uint32_t) paramsnonnull() hidden;
int sys_pause_nt(void) hidden;
int64_t __fix_enotdir(int64_t, char16_t *) hidden;
int64_t __fix_enotdir3(int64_t, char16_t *, char16_t *) hidden;
int64_t __winerr(void) nocallback privileged;

View file

@ -16,12 +16,12 @@
TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE.
*/
#include "libc/calls/math.h"
#include "libc/calls/struct/timespec.h"
/**
* Adds two nanosecond timestamps.
*/
struct timespec AddTimespec(struct timespec x, struct timespec y) {
struct timespec _timespec_add(struct timespec x, struct timespec y) {
x.tv_sec += y.tv_sec;
x.tv_nsec += y.tv_nsec;
if (x.tv_nsec >= 10000000000) {

32
libc/calls/timespec_sub.c Normal file
View file

@ -0,0 +1,32 @@
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi
Copyright 2022 Justine Alexandra Roberts Tunney
Permission to use, copy, modify, and/or distribute this software for
any purpose with or without fee is hereby granted, provided that the
above copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE.
*/
#include "libc/calls/struct/timespec.h"
/**
* Subtracts two nanosecond timestamps.
*/
struct timespec _timespec_sub(struct timespec x, struct timespec y) {
x.tv_sec -= y.tv_sec;
x.tv_nsec -= y.tv_nsec;
if (x.tv_nsec < 0) {
x.tv_nsec += 1000000000;
x.tv_sec -= 1;
}
return x;
}

View file

@ -16,17 +16,21 @@
TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE.
*/
#include "libc/calls/strace.internal.h"
#include "libc/calls/struct/timespec.h"
#include "libc/sysv/errfuns.h"
#include "libc/time/time.h"
/**
* Sleeps for particular amount of microseconds.
* Sleeps for particular number of microseconds.
*
* @return 0 on success, or -1 w/ errno
* @raise EINTR if a signal was delivered while sleeping
* @see nanosleep(), sleep()
* @norestart
*/
int usleep(uint32_t microseconds) {
return nanosleep(&(struct timespec){(uint64_t)microseconds / 1000000,
(uint64_t)microseconds % 1000000 * 1000},
NULL);
int usleep(uint32_t micros) {
struct timespec ts = {
micros / 1000000,
micros % 1000000 * 1000,
};
return nanosleep(&ts, 0);
}

View file

@ -19,6 +19,7 @@
#include "libc/bits/weaken.h"
#include "libc/calls/internal.h"
#include "libc/errno.h"
#include "libc/fmt/conv.h"
#include "libc/sysv/consts/at.h"
#include "libc/time/time.h"
#include "libc/zipos/zipos.internal.h"
@ -37,10 +38,8 @@ int sys_utimensat(int dirfd, const char *path, const struct timespec ts[2],
if (rc == -1 && errno == ENOSYS && path) {
errno = olderr;
if (ts) {
tv[0].tv_sec = ts[0].tv_sec;
tv[0].tv_usec = ts[0].tv_nsec / 1000;
tv[1].tv_sec = ts[1].tv_sec;
tv[1].tv_usec = ts[1].tv_nsec / 1000;
tv[0] = _timespec2timeval(ts[0]);
tv[1] = _timespec2timeval(ts[1]);
rc = sys_utimes(path, tv);
} else {
rc = sys_utimes(path, NULL);

View file

@ -18,6 +18,7 @@
*/
#include "libc/calls/internal.h"
#include "libc/calls/struct/stat.h"
#include "libc/fmt/conv.h"
#include "libc/nexgen32e/nexgen32e.h"
#include "libc/sysv/consts/at.h"
#include "libc/sysv/consts/utime.h"
@ -40,20 +41,16 @@ int sys_utimensat_xnu(int dirfd, const char *path, const struct timespec ts[2],
if (ts[0].tv_nsec == UTIME_NOW) {
tv[0] = now;
} else if (ts[0].tv_nsec == UTIME_OMIT) {
tv[0].tv_sec = st.st_atim.tv_sec;
tv[0].tv_usec = st.st_atim.tv_nsec / 1000;
tv[0] = _timespec2timeval(st.st_atim);
} else {
tv[0].tv_sec = ts[0].tv_sec;
tv[0].tv_usec = ts[0].tv_nsec / 1000;
tv[0] = _timespec2timeval(ts[0]);
}
if (ts[1].tv_nsec == UTIME_NOW) {
tv[1] = now;
} else if (ts[1].tv_nsec == UTIME_OMIT) {
tv[1].tv_sec = st.st_mtim.tv_sec;
tv[1].tv_usec = st.st_mtim.tv_nsec / 1000;
tv[1] = _timespec2timeval(st.st_mtim);
} else {
tv[1].tv_sec = ts[1].tv_sec;
tv[1].tv_usec = ts[1].tv_nsec / 1000;
tv[1] = _timespec2timeval(ts[1]);
}
} else {
tv[0] = now;