Introduce clock_nanosleep()

This commit is contained in:
Justine Tunney 2022-10-05 06:37:15 -07:00
parent fe3216e961
commit b75a4654cf
No known key found for this signature in database
GPG key ID: BE714B4575D6E328
33 changed files with 553 additions and 100 deletions

View file

@ -19,7 +19,7 @@
#include "libc/calls/struct/timespec.h"
/**
* Compares two nanosecond timestamps.
* Compares nanosecond timestamps.
*/
int _timespec_cmp(struct timespec a, struct timespec b) {
int cmp;

View file

@ -20,14 +20,24 @@
#include "libc/limits.h"
/**
* Converts timespec interval to microseconds.
* Reduces `ts` from 1e-9 to 1e-6 granularity w/ ceil rounding.
*/
int64_t _timespec_tomicros(struct timespec x) {
int64_t _timespec_tomicros(struct timespec ts) {
int64_t us;
if (!__builtin_mul_overflow(x.tv_sec, 1000000ul, &us) &&
!__builtin_add_overflow(us, x.tv_nsec / 1000, &us)) {
// reduce precision from nanos to micros
if (ts.tv_nsec <= 999999000) {
ts.tv_nsec = (ts.tv_nsec + 999) / 1000;
} else {
ts.tv_nsec = 0;
if (ts.tv_sec < INT64_MAX) {
ts.tv_sec += 1;
}
}
// convert to scalar result
if (!__builtin_mul_overflow(ts.tv_sec, 1000000ul, &us) &&
!__builtin_add_overflow(us, ts.tv_nsec, &us)) {
return us;
} else if (x.tv_sec < 0) {
} else if (ts.tv_sec < 0) {
return INT64_MIN;
} else {
return INT64_MAX;

View file

@ -20,14 +20,24 @@
#include "libc/limits.h"
/**
* Converts timespec interval to milliseconds.
* Reduces `ts` from 1e-9 to 1e-3 granularity w/ ceil rounding.
*/
int64_t _timespec_tomillis(struct timespec x) {
int64_t _timespec_tomillis(struct timespec ts) {
int64_t ms;
if (!__builtin_mul_overflow(x.tv_sec, 1000ul, &ms) &&
!__builtin_add_overflow(ms, x.tv_nsec / 1000000, &ms)) {
// reduce precision from nanos to millis
if (ts.tv_nsec <= 999000000) {
ts.tv_nsec = (ts.tv_nsec + 999999) / 1000000;
} else {
ts.tv_nsec = 0;
if (ts.tv_sec < INT64_MAX) {
ts.tv_sec += 1;
}
}
// convert to scalar result
if (!__builtin_mul_overflow(ts.tv_sec, 1000ul, &ms) &&
!__builtin_add_overflow(ms, ts.tv_nsec, &ms)) {
return ms;
} else if (x.tv_sec < 0) {
} else if (ts.tv_sec < 0) {
return INT64_MIN;
} else {
return INT64_MAX;

View file

@ -18,6 +18,13 @@
*/
#include "libc/calls/struct/timeval.h"
/**
* Reduces `ts` from 1e-9 to 1e-6 granularity w/ ceil rounding.
*/
struct timeval _timespec_totimeval(struct timespec ts) {
return (struct timeval){ts.tv_sec, ts.tv_nsec / 1000};
if (ts.tv_nsec < 1000000000 - 999) {
return (struct timeval){ts.tv_sec, (ts.tv_nsec + 999) / 1000};
} else {
return (struct timeval){ts.tv_sec + 1, 0};
}
}

30
libc/calls/_timeval_cmp.c Normal file
View file

@ -0,0 +1,30 @@
/*-*- 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/timeval.h"
/**
* Compares microseconds timestamps.
*/
int _timeval_cmp(struct timeval a, struct timeval b) {
int cmp;
if (!(cmp = (a.tv_sec > b.tv_sec) - (a.tv_sec < b.tv_sec))) {
cmp = (a.tv_usec > b.tv_usec) - (a.tv_usec < b.tv_usec);
}
return cmp;
}

26
libc/calls/_timeval_eq.c Normal file
View file

@ -0,0 +1,26 @@
/*-*- 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/timeval.h"
/**
* Checks if 𝑥 = 𝑦.
*/
bool _timeval_eq(struct timeval x, struct timeval y) {
return x.tv_sec == y.tv_sec && x.tv_usec == y.tv_usec;
}

34
libc/calls/_timeval_gt.c Normal file
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/timeval.h"
/**
* Returns true if timeval `x` is greater than `y`.
*/
bool _timeval_gt(struct timeval x, struct timeval y) {
if (x.tv_sec > y.tv_sec) {
return true;
}
if (x.tv_sec == y.tv_sec) {
if (x.tv_usec > y.tv_usec) {
return true;
}
}
return false;
}

28
libc/calls/_timeval_gte.c Normal file
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/struct/timeval.h"
/**
* Checks if 𝑥 𝑦.
*/
bool _timeval_gte(struct timeval x, struct timeval y) {
if (x.tv_sec > y.tv_sec) return true;
if (x.tv_sec < y.tv_sec) return false;
return x.tv_usec >= y.tv_usec;
}

32
libc/calls/_timeval_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/timeval.h"
/**
* Subtracts two nanosecond timestamps.
*/
struct timeval _timeval_sub(struct timeval a, struct timeval b) {
a.tv_sec -= b.tv_sec;
if (a.tv_usec < b.tv_usec) {
a.tv_usec += 1000000;
a.tv_sec--;
}
a.tv_usec -= b.tv_usec;
return a;
}

View file

@ -0,0 +1,57 @@
/*-*- 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 2021 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/struct/timespec.h"
#include "libc/calls/struct/timespec.internal.h"
#include "libc/macros.internal.h"
#include "libc/nt/synchronization.h"
#include "libc/sysv/consts/timer.h"
#include "libc/sysv/errfuns.h"
textwindows int sys_clock_nanosleep_nt(int clock, int flags,
const struct timespec *req,
struct timespec *rem) {
struct timespec now, abs;
if (flags & TIMER_ABSTIME) {
abs = *req;
for (;;) {
if (sys_clock_gettime_nt(clock, &now)) return -1;
if (_timespec_gte(now, abs)) return 0;
if (_check_interrupts(false, g_fds.p)) return eintr();
SleepEx(MIN(__SIG_POLLING_INTERVAL_MS,
_timespec_tomillis(_timespec_sub(abs, now))),
false);
}
} else {
if (sys_clock_gettime_nt(clock, &now)) return -1;
abs = _timespec_add(now, *req);
for (;;) {
sys_clock_gettime_nt(clock, &now);
if (_timespec_gte(now, abs)) return 0;
if (_check_interrupts(false, g_fds.p)) {
if (rem) *rem = _timespec_sub(abs, now);
return eintr();
}
SleepEx(MIN(__SIG_POLLING_INTERVAL_MS,
_timespec_tomillis(_timespec_sub(abs, now))),
false);
}
}
}

View file

@ -17,29 +17,29 @@
PERFORMANCE OF THIS SOFTWARE.
*/
#include "libc/calls/struct/timespec.h"
#include "libc/dce.h"
#include "libc/fmt/conv.h"
#include "libc/calls/struct/timespec.internal.h"
#include "libc/sysv/consts/clock.h"
#include "libc/sysv/errfuns.h"
// we don't want instrumentation because:
// - nanosleep() depends on this and ftrace can take microsecs
/**
* Converts `struct timespec` to `struct timeval`.
*
* This divides ts.tv_nsec by 1000 with upward rounding and overflow
* handling. Your ts.tv_nsec must be on the interval `[0,1000000000)`
* otherwise `{-1, -1}` is returned.
*
* @return converted timeval whose tv_usec will be -1 on error
*/
noinstrument struct timeval _timespec2timeval(struct timespec ts) {
if (0 <= ts.tv_nsec && ts.tv_nsec < 1000000000) {
if (0 <= ts.tv_nsec && ts.tv_nsec < 1000000000 - 999) {
return (struct timeval){ts.tv_sec, (ts.tv_nsec + 999) / 1000};
int sys_clock_nanosleep_openbsd(int clock, int flags,
const struct timespec *req,
struct timespec *rem) {
int res;
struct timespec now, rel;
if (clock == CLOCK_REALTIME) {
if (!flags) {
res = sys_nanosleep(req, rem);
} else {
return (struct timeval){ts.tv_sec + 1, 0};
sys_clock_gettime(clock, &now);
if (_timespec_gt(*req, now)) {
rel = _timespec_sub(*req, now);
res = sys_nanosleep(&rel, 0);
} else {
res = 0;
}
}
} else {
return (struct timeval){-1, -1};
res = enotsup();
}
return res;
}

View file

@ -0,0 +1,49 @@
/*-*- 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.internal.h"
#include "libc/calls/struct/timeval.h"
#include "libc/calls/struct/timeval.internal.h"
#include "libc/fmt/conv.h"
#include "libc/sock/internal.h"
#include "libc/sysv/consts/clock.h"
#include "libc/sysv/consts/timer.h"
#include "libc/sysv/errfuns.h"
int sys_clock_nanosleep_xnu(int clock, int flags, const struct timespec *req,
struct timespec *rem) {
int res;
struct timeval now, abs, rel;
if (clock == CLOCK_REALTIME) {
if (flags & TIMER_ABSTIME) {
abs = _timespec_totimeval(*req);
sys_gettimeofday_xnu(&now, 0, 0);
if (_timeval_gt(abs, now)) {
rel = _timeval_sub(abs, now);
res = sys_select(0, 0, 0, 0, &rel);
} else {
res = 0;
}
} else {
res = sys_nanosleep_xnu(req, rem);
}
} else {
res = enotsup();
}
return res;
}

View file

@ -0,0 +1,123 @@
/*-*- 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/struct/timespec.h"
#include "libc/calls/struct/timespec.internal.h"
#include "libc/calls/struct/timeval.h"
#include "libc/calls/struct/timeval.internal.h"
#include "libc/dce.h"
#include "libc/intrin/describeflags.internal.h"
#include "libc/intrin/strace.internal.h"
#include "libc/sysv/consts/clock.h"
#include "libc/sysv/consts/timer.h"
#include "libc/sysv/errfuns.h"
/**
* Sleeps for particular amount of time.
*
* Here's how you could sleep for one second:
*
* clock_nanosleep(0, 0, &(struct timespec){1}, 0);
*
* Your sleep will be interrupted automatically if you do something like
* press ctrl-c during the wait. That's an `EINTR` error and it lets you
* immediately react to status changes. This is always the case, even if
* you're using `SA_RESTART` since this is a `@norestart` system call.
*
* void OnCtrlC(int sig) {} // EINTR only happens after delivery
* signal(SIGINT, OnCtrlC); // do delivery rather than kill proc
* printf("save me from sleeping forever by pressing ctrl-c\n");
* clock_nanosleep(0, 0, &(struct timespec){INT_MAX}, 0);
* printf("you're my hero\n");
*
* If you want to perform an uninterruptible sleep without having to use
* sigprocmask() to block all signals then this function provides a good
* solution to that problem. For example:
*
* struct timespec rel, now, abs;
* clock_gettime(CLOCK_REALTIME, &now);
* rel = _timespec_frommillis(100);
* abs = _timespec_add(now, rel);
* while (clock_nanosleep(CLOCK_REALTIME, TIMER_ABSTIME, &abs, 0));
*
* will accurately spin on `EINTR` errors. That way you're not impeding
* signal delivery and you're not losing precision on your wait timeout.
* This function has first-class support on Linux, FreeBSD, and NetBSD;
* on OpenBSD it's good; on XNU it's bad; and on Windows it's ugly.
*
* @param clock should be `CLOCK_REALTIME` and you may consult the docs
* of your preferred platforms to see what other clocks might work
* @param flags can be 0 for relative and `TIMER_ABSTIME` for absolute
* @param req can be a relative or absolute time, depending on `flags`
* @param rem will be updated with the unslept time only when `flags`
* is zero, otherwise `rem` is ignored; when this call completes,
* that means `rem` will be set to `{0, 0}`, and shall only have
* something else when -1 is returned with `EINTR`, which means
* there was a signal delivery that happened mid-sleep and `rem`
* reflects (poorly) how much remaining time was left over, in
* case the caller wishes to retry the sleep operation, noting
* this isn't recommended since relative timestamps can drift
* @return 0 on success, or -1 w/ errno
* @raise EINTR when a signal got delivered while we were waiting
* @raise ENOTSUP if `clock` is known but we can't use it here
* @raise EINVAL if `clock` is unknown to current platform
* @raise EINVAL if `flags` has an unrecognized value
* @raise EINVAL if `req->tv_nsec [0,1000000000)`
* @raise EFAULT if bad memory was passed
* @raise ENOSYS on bare metal
* @norestart
*/
int clock_nanosleep(int clock, int flags, 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();
} else if (clock == 127 || //
(flags & ~TIMER_ABSTIME) || //
req->tv_sec < 0 || //
!(0 <= req->tv_nsec && req->tv_nsec <= 999999999)) {
rc = einval();
} else if (IsLinux() || IsFreebsd() || IsNetbsd()) {
rc = sys_clock_nanosleep(clock, flags, req, rem);
} else if (IsXnu()) {
rc = sys_clock_nanosleep_xnu(clock, flags, req, rem);
} else if (IsOpenbsd()) {
rc = sys_clock_nanosleep_openbsd(clock, flags, req, rem);
} else if (IsMetal()) {
rc = enosys();
} else {
rc = sys_clock_nanosleep_nt(clock, flags, 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 && !flags && rem) {
rem->tv_sec = 0;
rem->tv_nsec = 0;
}
STRACE("clock_nanosleep(%s, %s, %s, [%s]) → %d% m", DescribeClockName(clock),
DescribeSleepFlags(flags), flags, DescribeTimespec(0, req),
DescribeTimespec(rc, rem), rc);
return rc;
}

View file

@ -20,8 +20,9 @@
#include "libc/calls/internal.h"
#include "libc/calls/sig.internal.h"
#include "libc/calls/state.internal.h"
#include "libc/intrin/strace.internal.h"
#include "libc/calls/struct/timespec.h"
#include "libc/calls/struct/timespec.internal.h"
#include "libc/intrin/strace.internal.h"
#include "libc/limits.h"
#include "libc/macros.internal.h"
#include "libc/nexgen32e/rdtsc.h"
@ -52,10 +53,7 @@ textwindows int sys_nanosleep_nt(const struct timespec *req,
}
// convert timespec to milliseconds
if (__builtin_mul_overflow(req->tv_sec, 1000, &ms) ||
__builtin_add_overflow(ms, (req->tv_nsec + 999999) / 1000000, &ms)) {
ms = INT64_MAX;
}
ms = _timespec_tomillis(*req);
for (toto = ms;;) {

View file

@ -19,40 +19,34 @@
#include "libc/calls/struct/timespec.h"
#include "libc/calls/struct/timespec.internal.h"
#include "libc/calls/struct/timeval.h"
#include "libc/calls/struct/timeval.internal.h"
#include "libc/errno.h"
#include "libc/fmt/conv.h"
#include "libc/sock/internal.h"
#include "libc/sysv/consts/clock.h"
// nanosleep() on xnu: a bloodbath of a polyfill
// consider using clock_nanosleep(TIMER_ABSTIME)
int sys_nanosleep_xnu(const struct timespec *req, struct timespec *rem) {
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);
struct timeval wt, t1, t2, td;
if (rem) sys_gettimeofday_xnu(&t1, 0, 0);
wt = _timespec_totimeval(*req); // rounds up
rc = sys_select(0, 0, 0, 0, &wt);
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) {
// xnu select() doesn't modify timeout
// so we need, yet another system call
sys_gettimeofday_xnu(&t2, 0, 0);
td = _timeval_sub(t2, t1);
if (_timeval_gte(td, wt)) {
rem->tv_sec = 0;
rem->tv_nsec = 0;
} else {
*rem = _timeval_totimespec(_timeval_sub(wt, td));
}
}
}
return rc;
}

View file

@ -23,25 +23,23 @@
#include "libc/dce.h"
#include "libc/intrin/describeflags.internal.h"
#include "libc/intrin/strace.internal.h"
#include "libc/sysv/consts/clock.h"
#include "libc/sysv/errfuns.h"
/**
* Sleeps for a particular amount of time.
* Sleeps for relative 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`.
* 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()
* @see clock_nanosleep()
* @norestart
*/
int nanosleep(const struct timespec *req, struct timespec *rem) {
@ -53,7 +51,9 @@ int nanosleep(const struct timespec *req, struct timespec *rem) {
} else if (req->tv_sec < 0 ||
!(0 <= req->tv_nsec && req->tv_nsec <= 999999999)) {
rc = einval();
} else if (!IsWindows() && !IsMetal() && !IsXnu()) {
} else if (IsLinux()) {
rc = sys_clock_nanosleep(CLOCK_REALTIME, 0, req, rem);
} else if (IsOpenbsd() || IsFreebsd() || IsNetbsd()) {
rc = sys_nanosleep(req, rem);
} else if (IsXnu()) {
rc = sys_nanosleep_xnu(req, rem);

View file

@ -28,7 +28,7 @@
* 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()
* @see clock_nanosleep()
* @asyncsignalsafe
* @norestart
*/

View file

@ -10,6 +10,7 @@ struct timespec {
int clock_getres(int, struct timespec *);
int clock_gettime(int, struct timespec *);
int clock_nanosleep(int, int, const struct timespec *, struct timespec *);
int futimens(int, const struct timespec[2]);
int nanosleep(const struct timespec *, struct timespec *);
int sys_futex(int *, int, int, const struct timespec *, int *);

View file

@ -4,6 +4,7 @@
#include "libc/mem/alloca.h"
#if !(__ASSEMBLER__ + __LINKER__ + 0)
COSMOPOLITAN_C_START_
/* clang-format off */
int __sys_utimensat(int, const char *, const struct timespec[2], int) hidden;
int __utimens(int, const char *, const struct timespec[2], int) hidden;
@ -11,6 +12,10 @@ int sys_clock_getres(int, struct timespec *) hidden;
int sys_clock_gettime(int, struct timespec *) hidden;
int sys_clock_gettime_nt(int, struct timespec *) hidden;
int sys_clock_gettime_xnu(int, struct timespec *) hidden;
int sys_clock_nanosleep(int, int, const struct timespec *, struct timespec *) hidden;
int sys_clock_nanosleep_nt(int, int, const struct timespec *, struct timespec *) hidden;
int sys_clock_nanosleep_xnu(int, int, const struct timespec *, struct timespec *) hidden;
int sys_clock_nanosleep_openbsd(int, int, const struct timespec *, struct timespec *) hidden;
int sys_futimens(int, const struct timespec[2]) hidden;
int sys_nanosleep(const struct timespec *, struct timespec *) hidden;
int sys_nanosleep_nt(const struct timespec *, struct timespec *) hidden;

View file

@ -16,9 +16,14 @@ int gettimeofday(struct timeval *, struct timezone *);
int lutimes(const char *, const struct timeval[2]);
int utimes(const char *, const struct timeval[2]);
struct timeval _timeval_add(struct timeval, struct timeval);
struct timeval _timespec_totimeval(struct timespec);
struct timespec _timeval_totimespec(struct timeval);
int _timeval_cmp(struct timeval, struct timeval) pureconst;
bool _timeval_eq(struct timeval, struct timeval) pureconst;
bool _timeval_gt(struct timeval, struct timeval) pureconst;
bool _timeval_gte(struct timeval, struct timeval) pureconst;
struct timeval _timeval_add(struct timeval, struct timeval) pureconst;
struct timeval _timeval_sub(struct timeval, struct timeval) pureconst;
struct timeval _timespec_totimeval(struct timespec) pureconst;
struct timespec _timeval_totimespec(struct timeval) pureconst;
COSMOPOLITAN_C_END_
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */

View file

@ -24,13 +24,11 @@
*
* @return 0 on success, or -1 w/ errno
* @raise EINTR if a signal was delivered while sleeping
* @see nanosleep(), sleep()
* @see clock_nanosleep()
* @norestart
*/
int usleep(uint32_t micros) {
struct timespec ts = {
micros / 1000000,
micros % 1000000 * 1000,
};
struct timespec ts;
ts = _timespec_frommicros(micros);
return nanosleep(&ts, 0);
}

View file

@ -39,8 +39,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] = _timespec2timeval(ts[0]);
tv[1] = _timespec2timeval(ts[1]);
tv[0] = _timespec_totimeval(ts[0]);
tv[1] = _timespec_totimeval(ts[1]);
rc = sys_utimes(path, tv);
} else {
rc = sys_utimes(path, NULL);

View file

@ -17,6 +17,7 @@
PERFORMANCE OF THIS SOFTWARE.
*/
#include "libc/calls/struct/stat.h"
#include "libc/calls/struct/timeval.h"
#include "libc/calls/struct/timeval.internal.h"
#include "libc/fmt/conv.h"
#include "libc/nexgen32e/nexgen32e.h"
@ -41,16 +42,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] = _timespec2timeval(st.st_atim);
tv[0] = _timespec_totimeval(st.st_atim);
} else {
tv[0] = _timespec2timeval(ts[0]);
tv[0] = _timespec_totimeval(ts[0]);
}
if (ts[1].tv_nsec == UTIME_NOW) {
tv[1] = now;
} else if (ts[1].tv_nsec == UTIME_OMIT) {
tv[1] = _timespec2timeval(st.st_mtim);
tv[1] = _timespec_totimeval(st.st_mtim);
} else {
tv[1] = _timespec2timeval(ts[1]);
tv[1] = _timespec_totimeval(ts[1]);
}
} else {
tv[0] = now;

View file

@ -43,7 +43,6 @@ size_t wcsxfrm(wchar_t *, const wchar_t *, size_t);
cosmopolitan § conversion » time
*/
struct timeval _timespec2timeval(struct timespec);
int64_t DosDateTimeToUnix(unsigned, unsigned) libcesque nosideeffect;
struct timeval WindowsTimeToTimeVal(int64_t) libcesque nosideeffect;
struct timespec WindowsTimeToTimeSpec(int64_t) libcesque nosideeffect;

View file

@ -50,6 +50,7 @@ const char *DescribeRemapFlags(char[48], int);
const char *DescribeRlimitName(char[20], int);
const char *DescribeSchedPolicy(char[48], int);
const char *DescribeSeccompOperation(int);
const char *DescribeSleepFlags(char[16], int);
const char *DescribeSockLevel(char[12], int);
const char *DescribeSockOptname(char[32], int, int);
const char *DescribeSocketFamily(char[12], int);
@ -92,6 +93,7 @@ const char *DescribeWhence(char[12], int);
#define DescribeRemapFlags(x) DescribeRemapFlags(alloca(48), x)
#define DescribeRlimitName(rl) DescribeRlimitName(alloca(20), rl)
#define DescribeSchedPolicy(x) DescribeSchedPolicy(alloca(48), x)
#define DescribeSleepFlags(x) DescribeSleepFlags(alloca(16), x)
#define DescribeSockLevel(x) DescribeSockLevel(alloca(12), x)
#define DescribeSockOptname(x, y) DescribeSockOptname(alloca(32), x, y)
#define DescribeSocketFamily(x) DescribeSocketFamily(alloca(12), x)

View file

@ -0,0 +1,37 @@
/*-*- 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/fmt/itoa.h"
#include "libc/fmt/magnumstrs.internal.h"
#include "libc/intrin/describeflags.internal.h"
#include "libc/sysv/consts/timer.h"
/**
* Describes clock_nanosleep() flags argument.
*/
const char *(DescribeSleepFlags)(char buf[16], int x) {
switch (x) {
case 0:
return "0";
case TIMER_ABSTIME:
return "TIMER_ABSTIME";
default:
FormatInt32(buf, x);
return buf;
}
}

View file

@ -111,10 +111,10 @@ privileged void __enable_tls(void) {
// malloc() being linked, which links _mapanon(). otherwise
// if you exceed this, you need to STATIC_YOINK("_mapanon").
// please note that it's probably too early to call calloc()
assert(_weaken(_mapanon));
_npassert(_weaken(_mapanon));
siz = ROUNDUP(siz, FRAMESIZE);
mem = _weaken(_mapanon)(siz);
assert(mem);
_npassert(mem);
}
if (IsAsan()) {
// poison the space between .tdata and .tbss
@ -140,7 +140,7 @@ privileged void __enable_tls(void) {
int ax, dx;
if (IsWindows()) {
__tls_index = __imp_TlsAlloc();
assert(0 <= __tls_index && __tls_index < 64);
_npassert(0 <= __tls_index && __tls_index < 64);
asm("mov\t%1,%%gs:%0" : "=m"(*((long *)0x1480 + __tls_index)) : "r"(tib));
} else if (IsFreebsd()) {
sys_enable_tls(AMD64_SET_FSBASE, tib);

View file

@ -34,11 +34,11 @@
* @raise EPERM if terminal is already controlling another sid
*/
int login_tty(int fd) {
int rc;
int i, rc;
if (IsLinux() || IsBsd()) {
setsid();
if (!sys_ioctl(fd, TIOCSCTTY, 0)) {
for (int i = 0; i < 3; ++i) dup2(fd, i);
for (i = 0; i < 3; ++i) dup2(fd, i);
if (fd > 2) close(fd);
rc = 0;
} else {

View file

@ -17,14 +17,13 @@
PERFORMANCE OF THIS SOFTWARE.
*/
#define ShouldUseMsabiAttribute() 1
#include "libc/assert.h"
#include "libc/calls/internal.h"
#include "libc/intrin/strace.internal.h"
#include "libc/calls/struct/sigset.h"
#include "libc/dce.h"
#include "libc/errno.h"
#include "libc/intrin/asmflag.h"
#include "libc/intrin/kprintf.h"
#include "libc/intrin/strace.internal.h"
#include "libc/nt/enum/pageflags.h"
#include "libc/nt/memory.h"
#include "libc/nt/runtime.h"

View file

@ -71,6 +71,7 @@ scall sys_dup 0x0290290292029020 globl hidden
scall sys_dup2 0x05a05a05a205a021 globl hidden
scall sys_pause 0xfffffffffffff022 globl hidden
scall sys_nanosleep 0x1ae05b0f0ffff023 globl hidden
scall sys_clock_nanosleep 0x1ddfff0f4ffff0e6 globl hidden
scall sys_getitimer 0x1aa0460562056024 globl hidden
scall sys_setitimer 0x1a90450532053026 globl hidden
scall sys_alarm 0xfffffffffffff025 globl hidden
@ -264,7 +265,6 @@ scall sys_ktimer_settime 0xffffff0edfffffff globl # no wrapper
scall sys_clock_settime 0x1ac0580e9ffff0e3 globl # no wrapper
scall sys_clock_gettime 0x1ab0570e8ffff0e4 globl hidden # Linux 2.6+ (c. 2003); XNU uses magic address
scall sys_clock_getres 0x1ad0590eaffff0e5 globl hidden
scall sys_clock_nanosleep 0x1ddfff0f4ffff0e6 globl # no wrapper
scall sys_tgkill 0xfffffffffffff0ea globl hidden
scall sys_mbind 0xfffffffffffff0ed globl # no wrapper; numa numa yeah
scall set_mempolicy 0xfffffffffffff0ee globl

View file

@ -1402,6 +1402,7 @@ void *RecentWorker(void *arg) {
pthread_setname_np(pthread_self(), "RecentWorker");
LOG("RecentWorker started\n");
StartOver:
db = 0;
stmt = 0;
bzero(&t, sizeof(t));
CHECK_SQL(DbOpen("db.sqlite3", &db));
@ -1429,6 +1430,7 @@ StartOver:
&sb, &sblen, (void *)sqlite3_column_text(stmt, 1), -1, 0),
sqlite3_column_int64(stmt, 2)));
}
CHECK_SQL(sqlite3_reset(stmt));
CHECK_SQL(sqlite3_exec(db, "END TRANSACTION", 0, 0, 0));
CHECK_SYS(appends(&t.data.p, "]}\n"));
t.data.n = appendz(t.data.p).i;
@ -1478,15 +1480,17 @@ OnError:
// single thread for inserting batched claims into the database
// this helps us avoid over 9000 threads having fcntl bloodbath
void *ClaimWorker(void *arg) {
sqlite3 *db;
int i, n, rc;
sqlite3 *db = 0;
sqlite3_stmt *stmt = 0;
sqlite3_stmt *stmt;
bool warmedup = false;
struct Claim *v = _gc(xcalloc(BATCH_MAX, sizeof(struct Claim)));
BlockSignals();
pthread_setname_np(pthread_self(), "ClaimWorker");
LOG("ClaimWorker started\n");
StartOver:
db = 0;
stmt = 0;
CHECK_SQL(DbOpen("db.sqlite3", &db));
CHECK_DB(DbPrepare(db, &stmt,
"INSERT INTO land (ip, nick, created)\n"
@ -1525,8 +1529,6 @@ StartOver:
OnError:
sqlite3_finalize(stmt);
sqlite3_close(db);
stmt = 0;
db = 0;
goto StartOver;
}

View file

@ -1,5 +1,6 @@
#ifndef NSYNC_COMMON_H_
#define NSYNC_COMMON_H_
#include "libc/assert.h"
#include "third_party/nsync/atomic.h"
#include "third_party/nsync/atomic.internal.h"
#include "third_party/nsync/cv.h"
@ -220,12 +221,12 @@ static const uint32_t NSYNC_WAITER_TAG = 0x726d2ba9;
#define WAITER_IN_USE 0x2 /* waiter in use by a thread */
#define CONTAINER(t_, f_, p_) ((t_ *)(((char *)(p_)) - offsetof(t_, f_)))
#define ASSERT(x) \
do { \
if (!(x)) { \
*(volatile int *)0 = 0; \
} \
} while (0)
#ifdef TINY
#define ASSERT(x) _unassert(x)
#else
#define ASSERT(x) _npassert(x)
#endif
/* Return a pointer to the nsync_waiter_s containing nsync_dll_element_ *e. */
#define DLL_NSYNC_WAITER(e) \

View file

@ -15,6 +15,7 @@
See the License for the specific language governing permissions and
limitations under the License.
*/
#include "libc/assert.h"
#include "libc/errno.h"
#include "libc/str/str.h"
#include "libc/thread/thread.h"
@ -30,13 +31,17 @@ Copyright 2016 Google, Inc.\\n\
https://github.com/google/nsync\"");
// clang-format off
#ifdef TINY
#define ASSERT(x) _unassert(x)
#else
#define ASSERT(x) _npassert(x)
#endif
/* Check that atomic operations on nsync_atomic_uint32_ can be applied to int. */
static const int assert_int_size = 1 /
(sizeof (assert_int_size) == sizeof (uint32_t) &&
sizeof (nsync_atomic_uint32_) == sizeof (uint32_t));
#define ASSERT(x) do { if (!(x)) { *(volatile int *)0 = 0; } } while (0)
struct futex {
int i; /* lo half=count; hi half=waiter count */
};