From b75a4654cf1edc7093662a407ec39cfd7f6da2ab Mon Sep 17 00:00:00 2001 From: Justine Tunney Date: Wed, 5 Oct 2022 06:37:15 -0700 Subject: [PATCH] Introduce clock_nanosleep() --- libc/calls/_timespec_cmp.c | 2 +- libc/calls/_timespec_tomicros.c | 20 ++- libc/calls/_timespec_tomillis.c | 20 ++- libc/calls/_timespec_totimeval.c | 9 +- libc/calls/_timeval_cmp.c | 30 +++++ libc/calls/_timeval_eq.c | 26 ++++ libc/calls/_timeval_gt.c | 34 +++++ libc/calls/_timeval_gte.c | 28 ++++ libc/calls/_timeval_sub.c | 32 +++++ libc/calls/clock_nanosleep-nt.c | 57 ++++++++ .../clock_nanosleep-openbsd.c} | 40 +++--- libc/calls/clock_nanosleep-xnu.c | 49 +++++++ libc/calls/clock_nanosleep.c | 123 ++++++++++++++++++ libc/calls/nanosleep-nt.c | 8 +- libc/calls/nanosleep-xnu.c | 34 ++--- libc/calls/nanosleep.c | 14 +- libc/calls/sleep.c | 2 +- libc/calls/struct/timespec.h | 1 + libc/calls/struct/timespec.internal.h | 5 + libc/calls/struct/timeval.h | 11 +- libc/calls/usleep.c | 8 +- libc/calls/utimensat-sysv.c | 4 +- libc/calls/utimensat-xnu.c | 9 +- libc/fmt/conv.h | 1 - libc/intrin/describeflags.internal.h | 2 + libc/intrin/describesleepflags.c | 37 ++++++ libc/runtime/enable_tls.c | 6 +- libc/runtime/login_tty.c | 4 +- libc/runtime/morph.greg.c | 3 +- libc/sysv/syscalls.sh | 2 +- net/turfwar/turfwar.c | 10 +- third_party/nsync/common.internal.h | 13 +- third_party/nsync/mu_semaphore_futex.c | 9 +- 33 files changed, 553 insertions(+), 100 deletions(-) create mode 100644 libc/calls/_timeval_cmp.c create mode 100644 libc/calls/_timeval_eq.c create mode 100644 libc/calls/_timeval_gt.c create mode 100644 libc/calls/_timeval_gte.c create mode 100644 libc/calls/_timeval_sub.c create mode 100644 libc/calls/clock_nanosleep-nt.c rename libc/{intrin/timespec2timeval.c => calls/clock_nanosleep-openbsd.c} (70%) create mode 100644 libc/calls/clock_nanosleep-xnu.c create mode 100644 libc/calls/clock_nanosleep.c create mode 100644 libc/intrin/describesleepflags.c diff --git a/libc/calls/_timespec_cmp.c b/libc/calls/_timespec_cmp.c index 46b9bf122..88c13f248 100644 --- a/libc/calls/_timespec_cmp.c +++ b/libc/calls/_timespec_cmp.c @@ -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; diff --git a/libc/calls/_timespec_tomicros.c b/libc/calls/_timespec_tomicros.c index 543c31234..72d591858 100644 --- a/libc/calls/_timespec_tomicros.c +++ b/libc/calls/_timespec_tomicros.c @@ -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; diff --git a/libc/calls/_timespec_tomillis.c b/libc/calls/_timespec_tomillis.c index 20ef6f2c5..31a2ecda8 100644 --- a/libc/calls/_timespec_tomillis.c +++ b/libc/calls/_timespec_tomillis.c @@ -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; diff --git a/libc/calls/_timespec_totimeval.c b/libc/calls/_timespec_totimeval.c index f530ce71e..32bb83e31 100644 --- a/libc/calls/_timespec_totimeval.c +++ b/libc/calls/_timespec_totimeval.c @@ -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}; + } } diff --git a/libc/calls/_timeval_cmp.c b/libc/calls/_timeval_cmp.c new file mode 100644 index 000000000..e29eebbad --- /dev/null +++ b/libc/calls/_timeval_cmp.c @@ -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; +} diff --git a/libc/calls/_timeval_eq.c b/libc/calls/_timeval_eq.c new file mode 100644 index 000000000..7039451a2 --- /dev/null +++ b/libc/calls/_timeval_eq.c @@ -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; +} diff --git a/libc/calls/_timeval_gt.c b/libc/calls/_timeval_gt.c new file mode 100644 index 000000000..8d0812b06 --- /dev/null +++ b/libc/calls/_timeval_gt.c @@ -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; +} diff --git a/libc/calls/_timeval_gte.c b/libc/calls/_timeval_gte.c new file mode 100644 index 000000000..3dc063d69 --- /dev/null +++ b/libc/calls/_timeval_gte.c @@ -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; +} diff --git a/libc/calls/_timeval_sub.c b/libc/calls/_timeval_sub.c new file mode 100644 index 000000000..bbf58c26b --- /dev/null +++ b/libc/calls/_timeval_sub.c @@ -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; +} diff --git a/libc/calls/clock_nanosleep-nt.c b/libc/calls/clock_nanosleep-nt.c new file mode 100644 index 000000000..e25605f8d --- /dev/null +++ b/libc/calls/clock_nanosleep-nt.c @@ -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); + } + } +} diff --git a/libc/intrin/timespec2timeval.c b/libc/calls/clock_nanosleep-openbsd.c similarity index 70% rename from libc/intrin/timespec2timeval.c rename to libc/calls/clock_nanosleep-openbsd.c index b19456080..656c682e0 100644 --- a/libc/intrin/timespec2timeval.c +++ b/libc/calls/clock_nanosleep-openbsd.c @@ -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; } diff --git a/libc/calls/clock_nanosleep-xnu.c b/libc/calls/clock_nanosleep-xnu.c new file mode 100644 index 000000000..fd3a7ddf7 --- /dev/null +++ b/libc/calls/clock_nanosleep-xnu.c @@ -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; +} diff --git a/libc/calls/clock_nanosleep.c b/libc/calls/clock_nanosleep.c new file mode 100644 index 000000000..6eb147f00 --- /dev/null +++ b/libc/calls/clock_nanosleep.c @@ -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; +} diff --git a/libc/calls/nanosleep-nt.c b/libc/calls/nanosleep-nt.c index 070f907dd..f0cd505f4 100644 --- a/libc/calls/nanosleep-nt.c +++ b/libc/calls/nanosleep-nt.c @@ -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;;) { diff --git a/libc/calls/nanosleep-xnu.c b/libc/calls/nanosleep-xnu.c index bc37cd02e..653147f62 100644 --- a/libc/calls/nanosleep-xnu.c +++ b/libc/calls/nanosleep-xnu.c @@ -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; } diff --git a/libc/calls/nanosleep.c b/libc/calls/nanosleep.c index c8d40aed7..b39620b82 100644 --- a/libc/calls/nanosleep.c +++ b/libc/calls/nanosleep.c @@ -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); diff --git a/libc/calls/sleep.c b/libc/calls/sleep.c index aaacfaf02..74ea99d5d 100644 --- a/libc/calls/sleep.c +++ b/libc/calls/sleep.c @@ -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 */ diff --git a/libc/calls/struct/timespec.h b/libc/calls/struct/timespec.h index 75be831a2..7f48efef4 100644 --- a/libc/calls/struct/timespec.h +++ b/libc/calls/struct/timespec.h @@ -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 *); diff --git a/libc/calls/struct/timespec.internal.h b/libc/calls/struct/timespec.internal.h index f3e768f55..61f260d9c 100644 --- a/libc/calls/struct/timespec.internal.h +++ b/libc/calls/struct/timespec.internal.h @@ -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; diff --git a/libc/calls/struct/timeval.h b/libc/calls/struct/timeval.h index 60390752e..5d6a66ef3 100644 --- a/libc/calls/struct/timeval.h +++ b/libc/calls/struct/timeval.h @@ -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) */ diff --git a/libc/calls/usleep.c b/libc/calls/usleep.c index 4c8ccf6bc..1e07016e4 100644 --- a/libc/calls/usleep.c +++ b/libc/calls/usleep.c @@ -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); } diff --git a/libc/calls/utimensat-sysv.c b/libc/calls/utimensat-sysv.c index 65f5950e7..b449db299 100644 --- a/libc/calls/utimensat-sysv.c +++ b/libc/calls/utimensat-sysv.c @@ -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); diff --git a/libc/calls/utimensat-xnu.c b/libc/calls/utimensat-xnu.c index c9266cad3..c6a19b499 100644 --- a/libc/calls/utimensat-xnu.c +++ b/libc/calls/utimensat-xnu.c @@ -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; diff --git a/libc/fmt/conv.h b/libc/fmt/conv.h index 71fb95067..d0dda329a 100644 --- a/libc/fmt/conv.h +++ b/libc/fmt/conv.h @@ -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; diff --git a/libc/intrin/describeflags.internal.h b/libc/intrin/describeflags.internal.h index 73a9b4822..134cd7ff2 100644 --- a/libc/intrin/describeflags.internal.h +++ b/libc/intrin/describeflags.internal.h @@ -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) diff --git a/libc/intrin/describesleepflags.c b/libc/intrin/describesleepflags.c new file mode 100644 index 000000000..9bdd12f4b --- /dev/null +++ b/libc/intrin/describesleepflags.c @@ -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; + } +} diff --git a/libc/runtime/enable_tls.c b/libc/runtime/enable_tls.c index 24b40f39c..e89c46ae0 100644 --- a/libc/runtime/enable_tls.c +++ b/libc/runtime/enable_tls.c @@ -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); diff --git a/libc/runtime/login_tty.c b/libc/runtime/login_tty.c index 219790ca0..b0b74ed06 100644 --- a/libc/runtime/login_tty.c +++ b/libc/runtime/login_tty.c @@ -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 { diff --git a/libc/runtime/morph.greg.c b/libc/runtime/morph.greg.c index d3a578009..e8b035153 100644 --- a/libc/runtime/morph.greg.c +++ b/libc/runtime/morph.greg.c @@ -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" diff --git a/libc/sysv/syscalls.sh b/libc/sysv/syscalls.sh index 7d9ce94b8..4c7df745b 100755 --- a/libc/sysv/syscalls.sh +++ b/libc/sysv/syscalls.sh @@ -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 diff --git a/net/turfwar/turfwar.c b/net/turfwar/turfwar.c index 41c8eac42..2c9266108 100644 --- a/net/turfwar/turfwar.c +++ b/net/turfwar/turfwar.c @@ -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; } diff --git a/third_party/nsync/common.internal.h b/third_party/nsync/common.internal.h index 91553e49c..4db9254e1 100644 --- a/third_party/nsync/common.internal.h +++ b/third_party/nsync/common.internal.h @@ -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) \ diff --git a/third_party/nsync/mu_semaphore_futex.c b/third_party/nsync/mu_semaphore_futex.c index 237f83ed2..4dcbb8c19 100644 --- a/third_party/nsync/mu_semaphore_futex.c +++ b/third_party/nsync/mu_semaphore_futex.c @@ -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 */ };