From 672ccda37cb81b3cdbacf6bae49c72770996850e Mon Sep 17 00:00:00 2001 From: Justine Tunney Date: Sat, 8 Oct 2022 02:40:44 -0700 Subject: [PATCH] Clean up some sleep code --- libc/calls/_timespec_sleep.c | 38 +++++ ...timecritical.c => _timespec_sleep_until.c} | 17 +- libc/calls/clock_gettime.c | 3 +- libc/calls/clock_nanosleep.c | 3 +- libc/calls/gettimeofday.c | 5 +- libc/calls/interrupts-nt.c | 7 +- libc/calls/nanosleep-nt.c | 99 ------------ libc/calls/nanosleep.c | 41 +---- libc/calls/now.c | 15 +- libc/calls/oldbench.c | 9 +- libc/calls/sleep.c | 7 +- libc/calls/struct/timespec.h | 7 +- libc/calls/usleep.c | 8 +- libc/sysv/consts.sh | 2 +- libc/sysv/consts/FUTEX_WAKE.s | 2 +- libc/thread/tls.h | 4 +- .../{testing/array.h => array.internal.h} | 6 +- third_party/nsync/compat.S | 8 + third_party/nsync/futex.c | 145 +++++++++--------- .../nsync/{testing/heap.h => heap.internal.h} | 0 third_party/nsync/{testing => mem}/array.c | 2 +- third_party/nsync/mu_semaphore.c | 132 ++++++++++++---- third_party/nsync/mu_semaphore.internal.h | 25 --- third_party/nsync/mu_semaphore_futex.c | 129 ---------------- third_party/nsync/mu_semaphore_win32.c | 85 ---------- ...ss_test.c => cv_mu_timeout_stress_test_.c} | 0 .../nsync/testing/cv_wait_example_test.c | 4 +- third_party/nsync/testing/dll_test.c | 2 +- .../nsync/testing/mu_wait_example_test.c | 4 +- third_party/nsync/testing/testing.mk | 12 +- third_party/nsync/testing/time_extra.c | 14 -- third_party/nsync/testing/time_extra.h | 4 - third_party/nsync/testing/wait_test.c | 2 +- third_party/nsync/time.c | 54 ------- third_party/nsync/time.h | 13 +- 35 files changed, 310 insertions(+), 598 deletions(-) create mode 100644 libc/calls/_timespec_sleep.c rename libc/calls/{timecritical.c => _timespec_sleep_until.c} (80%) delete mode 100644 libc/calls/nanosleep-nt.c rename third_party/nsync/{testing/array.h => array.internal.h} (95%) mode change 100644 => 100755 rename third_party/nsync/{testing/heap.h => heap.internal.h} (100%) rename third_party/nsync/{testing => mem}/array.c (98%) mode change 100644 => 100755 third_party/nsync/mu_semaphore.internal.h delete mode 100644 third_party/nsync/mu_semaphore_futex.c delete mode 100644 third_party/nsync/mu_semaphore_win32.c rename third_party/nsync/testing/{cv_mu_timeout_stress_test.c => cv_mu_timeout_stress_test_.c} (100%) delete mode 100644 third_party/nsync/time.c diff --git a/libc/calls/_timespec_sleep.c b/libc/calls/_timespec_sleep.c new file mode 100644 index 000000000..472241876 --- /dev/null +++ b/libc/calls/_timespec_sleep.c @@ -0,0 +1,38 @@ +/*-*- 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/assert.h" +#include "libc/calls/struct/timespec.h" +#include "libc/errno.h" +#include "libc/sysv/consts/clock.h" + +/** + * Sleeps for specified delay. + * + * @return unslept time which may be non-zero if the call was interrupted + */ +struct timespec _timespec_sleep(struct timespec delay) { + int rc; + struct timespec remain; + if (!(rc = clock_nanosleep(CLOCK_REALTIME, 0, &delay, &remain))) { + return (struct timespec){0}; + } else { + _npassert(rc == EINTR); + return remain; + } +} diff --git a/libc/calls/timecritical.c b/libc/calls/_timespec_sleep_until.c similarity index 80% rename from libc/calls/timecritical.c rename to libc/calls/_timespec_sleep_until.c index 8215b1eec..088cdb6e8 100644 --- a/libc/calls/timecritical.c +++ b/libc/calls/_timespec_sleep_until.c @@ -16,5 +16,20 @@ │ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │ │ PERFORMANCE OF THIS SOFTWARE. │ ╚─────────────────────────────────────────────────────────────────────────────*/ +#include "libc/assert.h" +#include "libc/calls/struct/timespec.h" +#include "libc/errno.h" +#include "libc/sysv/consts/clock.h" +#include "libc/sysv/consts/timer.h" -bool __time_critical; +/** + * Sleeps until the specified time. + * + * @return 0 on success, or EINTR if interrupted + */ +int _timespec_sleep_until(struct timespec abs_deadline) { + int rc; + rc = clock_nanosleep(CLOCK_REALTIME, TIMER_ABSTIME, &abs_deadline, 0); + _npassert(!rc || rc == EINTR); + return rc; +} diff --git a/libc/calls/clock_gettime.c b/libc/calls/clock_gettime.c index 5ab89d11f..794fecf1b 100644 --- a/libc/calls/clock_gettime.c +++ b/libc/calls/clock_gettime.c @@ -33,6 +33,7 @@ #include "libc/mem/alloca.h" #include "libc/nt/synchronization.h" #include "libc/sysv/errfuns.h" +#include "libc/thread/tls.h" /** * Returns nanosecond time. @@ -83,7 +84,7 @@ int clock_gettime(int clock, struct timespec *ts) { rc = __clock_gettime(clock, ts); } #if SYSDEBUG - if (!__time_critical) { + if (!(__get_tls()->tib_flags & TIB_FLAG_TIME_CRITICAL)) { STRACE("clock_gettime(%s, [%s]) → %d% m", DescribeClockName(clock), DescribeTimespec(rc, ts), rc); } diff --git a/libc/calls/clock_nanosleep.c b/libc/calls/clock_nanosleep.c index d47a333bd..bd49b0236 100644 --- a/libc/calls/clock_nanosleep.c +++ b/libc/calls/clock_nanosleep.c @@ -29,6 +29,7 @@ #include "libc/sysv/consts/clock.h" #include "libc/sysv/consts/timer.h" #include "libc/sysv/errfuns.h" +#include "libc/thread/tls.h" /** * Sleeps for particular amount of time. @@ -112,7 +113,7 @@ errno_t clock_nanosleep(int clock, int flags, const struct timespec *req, } #if SYSDEBUG - if (!__time_critical) { + if (!(__get_tls()->tib_flags & TIB_FLAG_TIME_CRITICAL)) { STRACE("clock_nanosleep(%s, %s, %s, [%s]) → %s", DescribeClockName(clock), DescribeSleepFlags(flags), DescribeTimespec(0, req), DescribeTimespec(rc, rem), DescribeErrnoResult(rc)); diff --git a/libc/calls/gettimeofday.c b/libc/calls/gettimeofday.c index 67492d6b1..6df46f178 100644 --- a/libc/calls/gettimeofday.c +++ b/libc/calls/gettimeofday.c @@ -18,7 +18,6 @@ ╚─────────────────────────────────────────────────────────────────────────────*/ #include "libc/assert.h" #include "libc/calls/state.internal.h" -#include "libc/intrin/strace.internal.h" #include "libc/calls/struct/itimerval.internal.h" #include "libc/calls/struct/timeval.h" #include "libc/calls/struct/timeval.internal.h" @@ -26,7 +25,9 @@ #include "libc/dce.h" #include "libc/intrin/asan.internal.h" #include "libc/intrin/describeflags.internal.h" +#include "libc/intrin/strace.internal.h" #include "libc/sysv/errfuns.h" +#include "libc/thread/tls.h" #include "libc/time/struct/timezone.h" typedef axdx_t gettimeofday_f(struct timeval *, struct timezone *, void *); @@ -62,7 +63,7 @@ int gettimeofday(struct timeval *tv, struct timezone *tz) { rc = __gettimeofday(tv, tz, 0).ax; } #if SYSDEBUG - if (!__time_critical) { + if (!(__get_tls()->tib_flags & TIB_FLAG_TIME_CRITICAL)) { STRACE("gettimeofday([%s], %p) → %d% m", DescribeTimeval(rc, tv), tz, rc); } #endif diff --git a/libc/calls/interrupts-nt.c b/libc/calls/interrupts-nt.c index 90ddfa4cf..cede1e7d3 100644 --- a/libc/calls/interrupts-nt.c +++ b/libc/calls/interrupts-nt.c @@ -31,11 +31,12 @@ textwindows bool _check_interrupts(bool restartable, struct Fd *fd) { bool res; - if (__time_critical) return false; if (__threaded && __threaded != gettid()) return false; if (_weaken(_check_sigalrm)) _weaken(_check_sigalrm)(); - if (_weaken(_check_sigchld)) _weaken(_check_sigchld)(); - if (fd && _weaken(_check_sigwinch)) _weaken(_check_sigwinch)(fd); + if (!(__get_tls()->tib_flags & TIB_FLAG_TIME_CRITICAL)) { + if (_weaken(_check_sigchld)) _weaken(_check_sigchld)(); + if (fd && _weaken(_check_sigwinch)) _weaken(_check_sigwinch)(fd); + } res = _weaken(__sig_check) && _weaken(__sig_check)(restartable); return res; } diff --git a/libc/calls/nanosleep-nt.c b/libc/calls/nanosleep-nt.c deleted file mode 100644 index f0cd505f4..000000000 --- a/libc/calls/nanosleep-nt.c +++ /dev/null @@ -1,99 +0,0 @@ -/*-*- 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/assert.h" -#include "libc/calls/internal.h" -#include "libc/calls/sig.internal.h" -#include "libc/calls/state.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" -#include "libc/nt/errors.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_nanosleep_nt(const struct timespec *req, - struct timespec *rem) { - bool alertable; - uint32_t slice; - 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 - ms = _timespec_tomillis(*req); - - for (toto = ms;;) { - - // check if signal was delivered - if (!__time_critical && _check_interrupts(false, g_fds.p)) { - 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("... sleeping %'ldms of %'ld", toto - ms, toto); - } - - // perform the sleep - if (SleepEx(slice, alertable) == kNtWaitIoCompletion) { - POLLTRACE("IOCP EINTR"); // in case we ever figure it out - continue; - } - - // check if full duration has elapsed - if ((ms -= slice) <= 0) { - if (rem) { - rem->tv_sec = 0; - rem->tv_nsec = 0; - } - return 0; - } - } -} diff --git a/libc/calls/nanosleep.c b/libc/calls/nanosleep.c index 7d83bcd5f..9349320bf 100644 --- a/libc/calls/nanosleep.c +++ b/libc/calls/nanosleep.c @@ -16,18 +16,9 @@ │ 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/calls.h" -#include "libc/calls/state.internal.h" -#include "libc/calls/struct/timespec.internal.h" -#include "libc/dce.h" +#include "libc/calls/struct/timespec.h" #include "libc/errno.h" -#include "libc/intrin/describeflags.internal.h" -#include "libc/intrin/strace.internal.h" #include "libc/sysv/consts/clock.h" -#include "libc/sysv/errfuns.h" - -// TODO(jart): Just delegate to clock_nanosleep() /** * Sleeps for relative amount of time. @@ -45,32 +36,10 @@ */ 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(); - } else if (req->tv_sec < 0 || - !(0 <= req->tv_nsec && req->tv_nsec <= 999999999)) { - rc = einval(); - } else if (IsLinux() || IsFreebsd() || IsNetbsd()) { - rc = sys_clock_nanosleep(CLOCK_REALTIME, 0, req, rem); - if (rc > 0) errno = rc, rc = -1; - } else if (IsOpenbsd()) { - rc = sys_nanosleep(req, rem); - } else if (IsXnu()) { - rc = sys_nanosleep_xnu(req, rem); - } else if (IsMetal()) { - rc = enosys(); + if (!(rc = clock_nanosleep(CLOCK_REALTIME, 0, req, rem))) { + return 0; } else { - rc = sys_nanosleep_nt(req, rem); + errno = rc; + return -1; } - -#ifdef SYSDEBUG - if (!__time_critical) { - STRACE("nanosleep(%s, [%s]) → %d% m", DescribeTimespec(rc, req), - DescribeTimespec(rc, rem), rc); - } -#endif - - return rc; } diff --git a/libc/calls/now.c b/libc/calls/now.c index 481a5dd44..7d4cc5b0c 100644 --- a/libc/calls/now.c +++ b/libc/calls/now.c @@ -17,20 +17,21 @@ │ PERFORMANCE OF THIS SOFTWARE. │ ╚─────────────────────────────────────────────────────────────────────────────*/ #include "libc/assert.h" -#include "libc/intrin/bits.h" -#include "libc/intrin/initializer.internal.h" -#include "libc/intrin/safemacros.internal.h" #include "libc/calls/calls.h" #include "libc/calls/clock_gettime.internal.h" #include "libc/calls/state.internal.h" -#include "libc/intrin/strace.internal.h" #include "libc/calls/syscall_support-sysv.internal.h" #include "libc/dce.h" +#include "libc/intrin/bits.h" +#include "libc/intrin/initializer.internal.h" +#include "libc/intrin/safemacros.internal.h" +#include "libc/intrin/strace.internal.h" #include "libc/macros.internal.h" #include "libc/nexgen32e/rdtsc.h" #include "libc/nexgen32e/x86feature.h" #include "libc/str/str.h" #include "libc/sysv/consts/clock.h" +#include "libc/thread/tls.h" #include "libc/time/time.h" static clock_gettime_f *__gettime; @@ -53,11 +54,9 @@ static long double GetTimeSample(void) { } static long double MeasureNanosPerCycle(void) { - bool tc; int i, n; long double avg, samp; - tc = __time_critical; - __time_critical = true; + __get_tls()->tib_flags |= TIB_FLAG_TIME_CRITICAL; if (IsWindows()) { n = 10; } else { @@ -67,7 +66,7 @@ static long double MeasureNanosPerCycle(void) { samp = GetTimeSample(); avg += (samp - avg) / i; } - __time_critical = tc; + __get_tls()->tib_flags &= ~TIB_FLAG_TIME_CRITICAL; STRACE("MeasureNanosPerCycle cpn*1000=%d", (long)(avg * 1000)); return avg; } diff --git a/libc/calls/oldbench.c b/libc/calls/oldbench.c index 847938552..7eca8c8f9 100644 --- a/libc/calls/oldbench.c +++ b/libc/calls/oldbench.c @@ -18,17 +18,18 @@ ╚─────────────────────────────────────────────────────────────────────────────*/ #include "libc/calls/calls.h" #include "libc/calls/state.internal.h" -#include "libc/intrin/strace.internal.h" #include "libc/calls/struct/timespec.h" #include "libc/dce.h" #include "libc/intrin/bits.h" #include "libc/intrin/initializer.internal.h" #include "libc/intrin/safemacros.internal.h" +#include "libc/intrin/strace.internal.h" #include "libc/macros.internal.h" #include "libc/nexgen32e/rdtsc.h" #include "libc/nexgen32e/x86feature.h" #include "libc/str/str.h" #include "libc/sysv/consts/clock.h" +#include "libc/thread/tls.h" #include "libc/time/time.h" static struct Now { @@ -50,11 +51,9 @@ static long double GetTimeSample(void) { } static long double MeasureNanosPerCycle(void) { - bool tc; int i, n; long double avg, samp; - tc = __time_critical; - __time_critical = true; + __get_tls()->tib_flags |= TIB_FLAG_TIME_CRITICAL; if (IsWindows()) { n = 30; } else { @@ -64,7 +63,7 @@ static long double MeasureNanosPerCycle(void) { samp = GetTimeSample(); avg += (samp - avg) / i; } - __time_critical = tc; + __get_tls()->tib_flags &= ~TIB_FLAG_TIME_CRITICAL; STRACE("MeasureNanosPerCycle cpn*1000=%d", (long)(avg * 1000)); return avg; } diff --git a/libc/calls/sleep.c b/libc/calls/sleep.c index 74ea99d5d..ab9962fc2 100644 --- a/libc/calls/sleep.c +++ b/libc/calls/sleep.c @@ -17,8 +17,8 @@ │ PERFORMANCE OF THIS SOFTWARE. │ ╚─────────────────────────────────────────────────────────────────────────────*/ #include "libc/calls/struct/timespec.h" -#include "libc/errno.h" #include "libc/limits.h" +#include "libc/sysv/consts/clock.h" #include "libc/time/time.h" /** @@ -33,12 +33,9 @@ * @norestart */ unsigned sleep(unsigned seconds) { - int err; unsigned unslept; struct timespec tv = {seconds}; - err = errno; - nanosleep(&tv, &tv); - errno = err; + if (!clock_nanosleep(CLOCK_REALTIME, 0, &tv, &tv)) return 0; unslept = tv.tv_sec; if (tv.tv_nsec && unslept < UINT_MAX) { ++unslept; diff --git a/libc/calls/struct/timespec.h b/libc/calls/struct/timespec.h index 7f48efef4..6b50a2612 100644 --- a/libc/calls/struct/timespec.h +++ b/libc/calls/struct/timespec.h @@ -3,6 +3,9 @@ #if !(__ASSEMBLER__ + __LINKER__ + 0) COSMOPOLITAN_C_START_ +#define _timespec_zero ((struct timespec){0}) +#define _timespec_max ((struct timespec){0x7fffffffffffffff, 999999999}) + struct timespec { int64_t tv_sec; int64_t tv_nsec; /* nanoseconds */ @@ -29,8 +32,10 @@ struct timespec _timespec_add(struct timespec, struct timespec) pureconst; struct timespec _timespec_fromnanos(int64_t) pureconst; struct timespec _timespec_frommicros(int64_t) pureconst; struct timespec _timespec_frommillis(int64_t) pureconst; -struct timespec _timespec_mono(void); struct timespec _timespec_real(void); +struct timespec _timespec_mono(void); +struct timespec _timespec_sleep(struct timespec); +int _timespec_sleep_until(struct timespec); struct timespec _timespec_sub(struct timespec, struct timespec) pureconst; COSMOPOLITAN_C_END_ diff --git a/libc/calls/usleep.c b/libc/calls/usleep.c index 1e07016e4..a20c1ca67 100644 --- a/libc/calls/usleep.c +++ b/libc/calls/usleep.c @@ -17,6 +17,8 @@ │ PERFORMANCE OF THIS SOFTWARE. │ ╚─────────────────────────────────────────────────────────────────────────────*/ #include "libc/calls/struct/timespec.h" +#include "libc/sysv/consts/clock.h" +#include "libc/sysv/errfuns.h" #include "libc/time/time.h" /** @@ -28,7 +30,7 @@ * @norestart */ int usleep(uint32_t micros) { - struct timespec ts; - ts = _timespec_frommicros(micros); - return nanosleep(&ts, 0); + struct timespec ts = _timespec_frommicros(micros); + if (clock_nanosleep(CLOCK_REALTIME, 0, &ts, 0)) return eintr(); + return 0; } diff --git a/libc/sysv/consts.sh b/libc/sysv/consts.sh index 784fc49d9..8691f8a01 100755 --- a/libc/sysv/consts.sh +++ b/libc/sysv/consts.sh @@ -1314,7 +1314,7 @@ syscon rusage RUSAGE_BOTH -2 99 99 99 99 99 # woop # # group name GNU/Systemd XNU's Not UNIX! FreeBSD OpenBSD NetBSD The New Technology Commentary syscon futex FUTEX_WAIT 0 0 0 1 0 0 -syscon futex FUTEX_WAKE 1 0 1 2 0 1 +syscon futex FUTEX_WAKE 1 0 1 2 1 1 syscon futex FUTEX_REQUEUE 3 0 0 3 0 0 syscon futex FUTEX_PRIVATE_FLAG 128 0 128 128 0 0 diff --git a/libc/sysv/consts/FUTEX_WAKE.s b/libc/sysv/consts/FUTEX_WAKE.s index 740ca398a..f8004bc14 100644 --- a/libc/sysv/consts/FUTEX_WAKE.s +++ b/libc/sysv/consts/FUTEX_WAKE.s @@ -1,2 +1,2 @@ .include "o/libc/sysv/consts/syscon.internal.inc" -.syscon futex,FUTEX_WAKE,1,0,1,2,0,1 +.syscon futex,FUTEX_WAKE,1,0,1,2,1,1 diff --git a/libc/thread/tls.h b/libc/thread/tls.h index 208c4ebf3..bce67c812 100644 --- a/libc/thread/tls.h +++ b/libc/thread/tls.h @@ -4,6 +4,8 @@ #define TLS_ALIGNMENT 64 +#define TIB_FLAG_TIME_CRITICAL 1 + #if !(__ASSEMBLER__ + __LINKER__ + 0) COSMOPOLITAN_C_START_ @@ -24,7 +26,7 @@ struct CosmoTib { _Atomic(int32_t) tib_tid; /* 0x38 */ int32_t tib_errno; /* 0x3c */ void *tib_nsync; - void *tib_reserved1; + uint64_t tib_flags; void *tib_reserved2; void *tib_reserved3; void *tib_reserved4; diff --git a/third_party/nsync/testing/array.h b/third_party/nsync/array.internal.h old mode 100644 new mode 100755 similarity index 95% rename from third_party/nsync/testing/array.h rename to third_party/nsync/array.internal.h index 91f362891..05e5dc18a --- a/third_party/nsync/testing/array.h +++ b/third_party/nsync/array.internal.h @@ -1,5 +1,5 @@ -#ifndef NSYNC_TESTING_ARRAY_H_ -#define NSYNC_TESTING_ARRAY_H_ +#ifndef NSYNC_ARRAY_H_ +#define NSYNC_ARRAY_H_ /* clang-format off */ /* Return the number of elements in a C array a. @@ -58,4 +58,4 @@ struct a_hdr_ { (a)->a_ = NULL; (a)->h_.max_ = 0; (a)->h_.len_ = 0; \ } while (0) -#endif /*NSYNC_TESTING_ARRAY_H_*/ +#endif /*NSYNC_ARRAY_H_*/ diff --git a/third_party/nsync/compat.S b/third_party/nsync/compat.S index 5cdeee4bc..98bf9c00d 100644 --- a/third_party/nsync/compat.S +++ b/third_party/nsync/compat.S @@ -41,3 +41,11 @@ nsync_time_ms: nsync_time_us: jmp _timespec_frommicros .endfn nsync_time_us,globl + +nsync_time_sleep: + jmp _timespec_sleep + .endfn nsync_time_us,globl + +nsync_time_sleep_until: + jmp _timespec_sleep_until + .endfn nsync_time_us,globl diff --git a/third_party/nsync/futex.c b/third_party/nsync/futex.c index 4b8398a05..c2801ba75 100644 --- a/third_party/nsync/futex.c +++ b/third_party/nsync/futex.c @@ -17,7 +17,9 @@ │ PERFORMANCE OF THIS SOFTWARE. │ ╚─────────────────────────────────────────────────────────────────────────────*/ #include "libc/atomic.h" +#include "libc/calls/calls.h" #include "libc/calls/sig.internal.h" +#include "libc/calls/state.internal.h" #include "libc/calls/struct/timespec.h" #include "libc/calls/struct/timespec.internal.h" #include "libc/dce.h" @@ -33,8 +35,10 @@ #include "libc/sysv/consts/timer.h" #include "libc/thread/freebsd.internal.h" #include "libc/thread/thread.h" +#include "libc/thread/tls.h" +#include "third_party/nsync/atomic.h" #include "third_party/nsync/common.internal.h" -#include "third_party/nsync/mu_semaphore.internal.h" +#include "third_party/nsync/time.h" // clang-format off /* futex() polyfill w/ sched_yield() fallback */ @@ -51,15 +55,15 @@ bool FUTEX_TIMEOUT_IS_ABSOLUTE; __attribute__((__constructor__)) static void nsync_futex_init_ (void) { int x = 0; - if (NSYNC_FUTEX_WIN32 && IsWindows ()) { + FUTEX_WAIT_ = FUTEX_WAIT; + + if (IsWindows ()) { FUTEX_IS_SUPPORTED = true; - FUTEX_WAIT_ = FUTEX_WAIT; return; } if (IsFreebsd ()) { FUTEX_IS_SUPPORTED = true; - FUTEX_WAIT_ = FUTEX_WAIT; FUTEX_TIMEOUT_IS_ABSOLUTE = true; FUTEX_PRIVATE_FLAG_ = FUTEX_PRIVATE_FLAG; return; @@ -105,44 +109,41 @@ __attribute__((__constructor__)) static void nsync_futex_init_ (void) { } static int nsync_futex_polyfill_ (int *p, int expect, struct timespec *timeout) { - int rc; - atomic_int *w; - int64_t max, nanos; + int64_t nanos, maxnanos; + nsync_atomic_uint32_ *w; struct timespec ts, deadline; - w = (atomic_int *)p; - if (atomic_load_explicit (p, memory_order_relaxed) != expect) { + w = (nsync_atomic_uint32_ *)p; + if (ATM_LOAD (p) != expect) { return -EAGAIN; } - ts = _timespec_real (); + ts = nsync_time_now (); if (!timeout) { deadline = nsync_time_no_deadline; } else if (FUTEX_TIMEOUT_IS_ABSOLUTE) { deadline = *timeout; } else { - deadline = _timespec_add (ts, *timeout); + deadline = nsync_time_add (ts, *timeout); } nanos = 100; - max = __SIG_POLLING_INTERVAL_MS * 1000L * 1000; - while (_timespec_gt (deadline, ts)) { - if (atomic_load_explicit (p, memory_order_relaxed) != expect) { + maxnanos = __SIG_POLLING_INTERVAL_MS * 1000L * 1000; + while (nsync_time_cmp (deadline, ts) > 0) { + if (ATM_LOAD (p) != expect) { return 0; } - ts = _timespec_add (ts, _timespec_fromnanos (nanos)); - if (_timespec_gt (ts, deadline)) { + ts = nsync_time_add (ts, _timespec_fromnanos (nanos)); + if (nsync_time_cmp (ts, deadline) > 0) { ts = deadline; } - rc = clock_nanosleep (CLOCK_REALTIME, TIMER_ABSTIME, &ts, 0); - if (rc) { - ASSERT (rc == EINTR); + if (nsync_time_sleep_until (ts)) { return -EINTR; } - if (nanos < max) { + if (nanos < maxnanos) { nanos <<= 1; - if (nanos > max) { - nanos = max; + if (nanos > maxnanos) { + nanos = maxnanos; } } } @@ -154,38 +155,42 @@ int nsync_futex_wait_ (int *p, int expect, char pshare, struct timespec *timeout uint32_t ms; int rc, op, fop; - if (!FUTEX_IS_SUPPORTED) { - return nsync_futex_polyfill_ (p, expect, timeout); - } - op = FUTEX_WAIT_; if (pshare == PTHREAD_PROCESS_PRIVATE) { op |= FUTEX_PRIVATE_FLAG_; } - if (NSYNC_FUTEX_WIN32 && IsWindows ()) { - // Windows 8 futexes don't support multiple processes :( - if (pshare) { - return nsync_futex_polyfill_ (p, expect, timeout); - } - if (timeout) { - ms = _timespec_tomillis (*timeout); + if (FUTEX_IS_SUPPORTED) { + if (IsWindows ()) { + // Windows 8 futexes don't support multiple processes :( + if (pshare) { + goto Polyfill; + } + if (timeout) { + ms = _timespec_tomillis (*timeout); + } else { + ms = -1; + } + if (WaitOnAddress (p, &expect, sizeof(int), ms)) { + rc = 0; + } else { + rc = -GetLastError (); + } + } else if (IsFreebsd ()) { + rc = sys_umtx_timedwait_uint ( + p, expect, pshare, timeout); } else { - ms = -1; + rc = _futex (p, op, expect, timeout, 0, + FUTEX_WAIT_BITS_); + if (IsOpenbsd() && rc > 0) { + rc = -rc; + } } - if (WaitOnAddress (p, &expect, sizeof(int), ms)) { - rc = 0; - } else { - rc = -GetLastError (); - } - } else if (IsFreebsd ()) { - rc = sys_umtx_timedwait_uint (p, expect, pshare, timeout); } else { - rc = _futex (p, op, expect, timeout, 0, FUTEX_WAIT_BITS_); - if (IsOpenbsd() && rc > 0) { - // [jart] openbsd does this without setting carry flag - rc = -rc; - } + Polyfill: + __get_tls()->tib_flags |= TIB_FLAG_TIME_CRITICAL; + rc = nsync_futex_polyfill_ (p, expect, timeout); + __get_tls()->tib_flags &= ~TIB_FLAG_TIME_CRITICAL; } STRACE ("futex(%t, %s, %d, %s) → %s", @@ -202,40 +207,40 @@ int nsync_futex_wake_ (int *p, int count, char pshare) { ASSERT (count == 1 || count == INT_MAX); - if (!FUTEX_IS_SUPPORTED) { - nsync_yield_ (); - return 0; - } - op = FUTEX_WAKE; if (pshare == PTHREAD_PROCESS_PRIVATE) { op |= FUTEX_PRIVATE_FLAG_; } - if (NSYNC_FUTEX_WIN32 && IsWindows ()) { - if (pshare) { - nsync_yield_ (); - return 0; - } - if (count == 1) { - WakeByAddressSingle (p); + if (FUTEX_IS_SUPPORTED) { + if (IsWindows ()) { + if (pshare) { + goto Polyfill; + } + if (count == 1) { + WakeByAddressSingle (p); + } else { + WakeByAddressAll (p); + } + rc = 0; + } else if (IsFreebsd ()) { + if (pshare) { + fop = UMTX_OP_WAKE; + } else { + fop = UMTX_OP_WAKE_PRIVATE; + } + rc = sys_umtx_op (p, fop, count, 0, 0); } else { - WakeByAddressAll (p); + rc = wake (p, op, count); } - rc = 0; - } else if (IsFreebsd ()) { - if (pshare) { - fop = UMTX_OP_WAKE; - } else { - fop = UMTX_OP_WAKE_PRIVATE; - } - rc = sys_umtx_op (p, fop, count, 0, 0); } else { - rc = wake (p, op, count); + Polyfill: + sched_yield (); + rc = 0; } - STRACE ("futex(%t, %s, %d) → %s", p, - DescribeFutexOp(op), + STRACE ("futex(%t, %s, %d) → %s", + p, DescribeFutexOp(op), count, DescribeErrnoResult(rc)); return rc; diff --git a/third_party/nsync/testing/heap.h b/third_party/nsync/heap.internal.h similarity index 100% rename from third_party/nsync/testing/heap.h rename to third_party/nsync/heap.internal.h diff --git a/third_party/nsync/testing/array.c b/third_party/nsync/mem/array.c similarity index 98% rename from third_party/nsync/testing/array.c rename to third_party/nsync/mem/array.c index 093920408..b115b6d72 100644 --- a/third_party/nsync/testing/array.c +++ b/third_party/nsync/mem/array.c @@ -17,7 +17,7 @@ ╚─────────────────────────────────────────────────────────────────────────────*/ #include "libc/mem/mem.h" #include "libc/str/str.h" -#include "third_party/nsync/testing/array.h" +#include "third_party/nsync/array.internal.h" // clang-format off void a_ensure_ (void *v, int delta, int sz) { diff --git a/third_party/nsync/mu_semaphore.c b/third_party/nsync/mu_semaphore.c index 6fe6014c6..078bda54c 100644 --- a/third_party/nsync/mu_semaphore.c +++ b/third_party/nsync/mu_semaphore.c @@ -1,56 +1,128 @@ /*-*- mode:c;indent-tabs-mode:t;c-basic-offset:8;tab-width:8;coding:utf-8 -*-│ │vi: set et ft=c ts=8 tw=8 fenc=utf-8 :vi│ ╞══════════════════════════════════════════════════════════════════════════════╡ -│ Copyright 2022 Justine Alexandra Roberts Tunney │ +│ Copyright 2016 Google Inc. │ │ │ -│ 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. │ +│ Licensed under the Apache License, Version 2.0 (the "License"); │ +│ you may not use this file except in compliance with the License. │ +│ You may obtain a copy of the License at │ │ │ -│ 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. │ +│ http://www.apache.org/licenses/LICENSE-2.0 │ +│ │ +│ Unless required by applicable law or agreed to in writing, software │ +│ distributed under the License is distributed on an "AS IS" BASIS, │ +│ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. │ +│ See the License for the specific language governing permissions and │ +│ limitations under the License. │ ╚─────────────────────────────────────────────────────────────────────────────*/ -#include "libc/dce.h" +#include "libc/assert.h" +#include "libc/errno.h" +#include "libc/str/str.h" +#include "libc/thread/thread.h" +#include "third_party/nsync/atomic.h" +#include "third_party/nsync/atomic.internal.h" +#include "third_party/nsync/futex.internal.h" #include "third_party/nsync/mu_semaphore.h" -#include "third_party/nsync/mu_semaphore.internal.h" + +asm(".ident\t\"\\n\\n\ +*NSYNC (Apache 2.0)\\n\ +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)); + +struct futex { + int i; /* lo half=count; hi half=waiter count */ +}; + +static nsync_semaphore *sem_big_enough_for_futex = (nsync_semaphore *) (uintptr_t)(1 / + (sizeof (struct futex) <= sizeof (*sem_big_enough_for_futex))); + /* Initialize *s; the initial value is 0. */ void nsync_mu_semaphore_init (nsync_semaphore *s) { - if (NSYNC_FUTEX_WIN32 || !IsWindows ()) - nsync_mu_semaphore_init_futex (s); - else - nsync_mu_semaphore_init_win32 (s); + struct futex *f = (struct futex *) s; + f->i = 0; } /* Wait until the count of *s exceeds 0, and decrement it. */ void nsync_mu_semaphore_p (nsync_semaphore *s) { - if (NSYNC_FUTEX_WIN32 || !IsWindows ()) - nsync_mu_semaphore_p_futex (s); - else - nsync_mu_semaphore_p_win32 (s); + struct futex *f = (struct futex *) s; + int i; + do { + i = ATM_LOAD ((nsync_atomic_uint32_ *) &f->i); + if (i == 0) { + int futex_result = nsync_futex_wait_ (&f->i, i, PTHREAD_PROCESS_PRIVATE, NULL); + ASSERT (futex_result == 0 || + futex_result == -EINTR || + futex_result == -EWOULDBLOCK); + } + } while (i == 0 || !ATM_CAS_ACQ ((nsync_atomic_uint32_ *) &f->i, i, i-1)); } /* Wait until one of: the count of *s is non-zero, in which case decrement *s and return 0; or abs_deadline expires, in which case return ETIMEDOUT. */ int nsync_mu_semaphore_p_with_deadline (nsync_semaphore *s, nsync_time abs_deadline) { - if (NSYNC_FUTEX_WIN32 || !IsWindows ()) - return nsync_mu_semaphore_p_with_deadline_futex (s, abs_deadline); - else - return nsync_mu_semaphore_p_with_deadline_win32 (s, abs_deadline); + struct futex *f = (struct futex *)s; + int i; + int result = 0; + do { + i = ATM_LOAD ((nsync_atomic_uint32_ *) &f->i); + if (i == 0) { + int futex_result; + struct timespec ts_buf; + const struct timespec *ts = NULL; + if (nsync_time_cmp (abs_deadline, nsync_time_no_deadline) != 0) { + memset (&ts_buf, 0, sizeof (ts_buf)); + if (FUTEX_TIMEOUT_IS_ABSOLUTE) { + ts_buf.tv_sec = NSYNC_TIME_SEC (abs_deadline); + ts_buf.tv_nsec = NSYNC_TIME_NSEC (abs_deadline); + } else { + nsync_time now; + now = nsync_time_now (); + if (nsync_time_cmp (now, abs_deadline) > 0) { + ts_buf.tv_sec = 0; + ts_buf.tv_nsec = 0; + } else { + nsync_time rel_deadline; + rel_deadline = nsync_time_sub (abs_deadline, now); + ts_buf.tv_sec = NSYNC_TIME_SEC (rel_deadline); + ts_buf.tv_nsec = NSYNC_TIME_NSEC (rel_deadline); + } + } + ts = &ts_buf; + } + futex_result = nsync_futex_wait_ (&f->i, i, PTHREAD_PROCESS_PRIVATE, ts); + ASSERT (futex_result == 0 || + futex_result == -EINTR || + futex_result == -ETIMEDOUT || + futex_result == -EWOULDBLOCK); + /* Some systems don't wait as long as they are told. */ + if (futex_result == -ETIMEDOUT && + nsync_time_cmp (abs_deadline, nsync_time_now ()) <= 0) { + result = ETIMEDOUT; + } + } + } while (result == 0 && (i == 0 || !ATM_CAS_ACQ ((nsync_atomic_uint32_ *) &f->i, i, i - 1))); + return (result); } /* Ensure that the count of *s is at least 1. */ void nsync_mu_semaphore_v (nsync_semaphore *s) { - if (NSYNC_FUTEX_WIN32 || !IsWindows ()) - nsync_mu_semaphore_v_futex (s); - else - nsync_mu_semaphore_v_win32 (s); + struct futex *f = (struct futex *) s; + uint32_t old_value; + do { + old_value = ATM_LOAD ((nsync_atomic_uint32_ *) &f->i); + } while (!ATM_CAS_REL ((nsync_atomic_uint32_ *) &f->i, old_value, old_value+1)); + ASSERT (nsync_futex_wake_ (&f->i, 1, PTHREAD_PROCESS_PRIVATE) >= 0); } diff --git a/third_party/nsync/mu_semaphore.internal.h b/third_party/nsync/mu_semaphore.internal.h old mode 100644 new mode 100755 index b636bfc3f..e69de29bb --- a/third_party/nsync/mu_semaphore.internal.h +++ b/third_party/nsync/mu_semaphore.internal.h @@ -1,25 +0,0 @@ -#ifndef NSYNC_MU_SEMAPHORE_INTERNAL_H_ -#define NSYNC_MU_SEMAPHORE_INTERNAL_H_ -#include "third_party/nsync/mu_semaphore.h" -#include "third_party/nsync/time.h" - -#ifndef NSYNC_FUTEX_WIN32 -#define NSYNC_FUTEX_WIN32 1 -#endif - -#if !(__ASSEMBLER__ + __LINKER__ + 0) -COSMOPOLITAN_C_START_ - -void nsync_mu_semaphore_init_futex(nsync_semaphore *); -void nsync_mu_semaphore_p_futex(nsync_semaphore *); -int nsync_mu_semaphore_p_with_deadline_futex(nsync_semaphore *, nsync_time); -void nsync_mu_semaphore_v_futex(nsync_semaphore *); - -void nsync_mu_semaphore_init_win32(nsync_semaphore *); -void nsync_mu_semaphore_p_win32(nsync_semaphore *); -int nsync_mu_semaphore_p_with_deadline_win32(nsync_semaphore *, nsync_time); -void nsync_mu_semaphore_v_win32(nsync_semaphore *); - -COSMOPOLITAN_C_END_ -#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */ -#endif /* NSYNC_MU_SEMAPHORE_INTERNAL_H_ */ diff --git a/third_party/nsync/mu_semaphore_futex.c b/third_party/nsync/mu_semaphore_futex.c deleted file mode 100644 index 4dcbb8c19..000000000 --- a/third_party/nsync/mu_semaphore_futex.c +++ /dev/null @@ -1,129 +0,0 @@ -/*-*- mode:c;indent-tabs-mode:t;c-basic-offset:8;tab-width:8;coding:utf-8 -*-│ -│vi: set et ft=c ts=8 tw=8 fenc=utf-8 :vi│ -╞══════════════════════════════════════════════════════════════════════════════╡ -│ Copyright 2016 Google Inc. │ -│ │ -│ Licensed under the Apache License, Version 2.0 (the "License"); │ -│ you may not use this file except in compliance with the License. │ -│ You may obtain a copy of the License at │ -│ │ -│ http://www.apache.org/licenses/LICENSE-2.0 │ -│ │ -│ Unless required by applicable law or agreed to in writing, software │ -│ distributed under the License is distributed on an "AS IS" BASIS, │ -│ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. │ -│ 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" -#include "third_party/nsync/atomic.h" -#include "third_party/nsync/atomic.internal.h" -#include "third_party/nsync/futex.internal.h" -#include "third_party/nsync/mu_semaphore.h" -#include "third_party/nsync/mu_semaphore.internal.h" - -asm(".ident\t\"\\n\\n\ -*NSYNC (Apache 2.0)\\n\ -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)); - -struct futex { - int i; /* lo half=count; hi half=waiter count */ -}; - -static nsync_semaphore *sem_big_enough_for_futex = (nsync_semaphore *) (uintptr_t)(1 / - (sizeof (struct futex) <= sizeof (*sem_big_enough_for_futex))); - -/* Initialize *s; the initial value is 0. */ -void nsync_mu_semaphore_init_futex (nsync_semaphore *s) { - struct futex *f = (struct futex *) s; - f->i = 0; -} - -/* Wait until the count of *s exceeds 0, and decrement it. */ -void nsync_mu_semaphore_p_futex (nsync_semaphore *s) { - struct futex *f = (struct futex *) s; - int i; - do { - i = ATM_LOAD ((nsync_atomic_uint32_ *) &f->i); - if (i == 0) { - int futex_result = nsync_futex_wait_ (&f->i, i, PTHREAD_PROCESS_PRIVATE, NULL); - ASSERT (futex_result == 0 || - futex_result == -EINTR || - futex_result == -EWOULDBLOCK); - } - } while (i == 0 || !ATM_CAS_ACQ ((nsync_atomic_uint32_ *) &f->i, i, i-1)); -} - -/* Wait until one of: - the count of *s is non-zero, in which case decrement *s and return 0; - or abs_deadline expires, in which case return ETIMEDOUT. */ -int nsync_mu_semaphore_p_with_deadline_futex (nsync_semaphore *s, nsync_time abs_deadline) { - struct futex *f = (struct futex *)s; - int i; - int result = 0; - do { - i = ATM_LOAD ((nsync_atomic_uint32_ *) &f->i); - if (i == 0) { - int futex_result; - struct timespec ts_buf; - const struct timespec *ts = NULL; - if (nsync_time_cmp (abs_deadline, nsync_time_no_deadline) != 0) { - memset (&ts_buf, 0, sizeof (ts_buf)); - if (FUTEX_TIMEOUT_IS_ABSOLUTE) { - ts_buf.tv_sec = NSYNC_TIME_SEC (abs_deadline); - ts_buf.tv_nsec = NSYNC_TIME_NSEC (abs_deadline); - } else { - nsync_time now; - now = nsync_time_now (); - if (nsync_time_cmp (now, abs_deadline) > 0) { - ts_buf.tv_sec = 0; - ts_buf.tv_nsec = 0; - } else { - nsync_time rel_deadline; - rel_deadline = nsync_time_sub (abs_deadline, now); - ts_buf.tv_sec = NSYNC_TIME_SEC (rel_deadline); - ts_buf.tv_nsec = NSYNC_TIME_NSEC (rel_deadline); - } - } - ts = &ts_buf; - } - futex_result = nsync_futex_wait_ (&f->i, i, PTHREAD_PROCESS_PRIVATE, ts); - ASSERT (futex_result == 0 || - futex_result == -EINTR || - futex_result == -ETIMEDOUT || - futex_result == -EWOULDBLOCK); - /* Some systems don't wait as long as they are told. */ - if (futex_result == -ETIMEDOUT && - nsync_time_cmp (abs_deadline, nsync_time_now ()) <= 0) { - result = ETIMEDOUT; - } - } - } while (result == 0 && (i == 0 || !ATM_CAS_ACQ ((nsync_atomic_uint32_ *) &f->i, i, i - 1))); - return (result); -} - -/* Ensure that the count of *s is at least 1. */ -void nsync_mu_semaphore_v_futex (nsync_semaphore *s) { - struct futex *f = (struct futex *) s; - uint32_t old_value; - do { - old_value = ATM_LOAD ((nsync_atomic_uint32_ *) &f->i); - } while (!ATM_CAS_REL ((nsync_atomic_uint32_ *) &f->i, old_value, old_value+1)); - ASSERT (nsync_futex_wake_ (&f->i, 1, PTHREAD_PROCESS_PRIVATE) >= 0); -} diff --git a/third_party/nsync/mu_semaphore_win32.c b/third_party/nsync/mu_semaphore_win32.c deleted file mode 100644 index 3d1cdc2de..000000000 --- a/third_party/nsync/mu_semaphore_win32.c +++ /dev/null @@ -1,85 +0,0 @@ -/*-*- mode:c;indent-tabs-mode:t;c-basic-offset:8;tab-width:8;coding:utf-8 -*-│ -│vi: set et ft=c ts=8 tw=8 fenc=utf-8 :vi│ -╞══════════════════════════════════════════════════════════════════════════════╡ -│ Copyright 2016 Google Inc. │ -│ │ -│ Licensed under the Apache License, Version 2.0 (the "License"); │ -│ you may not use this file except in compliance with the License. │ -│ You may obtain a copy of the License at │ -│ │ -│ http://www.apache.org/licenses/LICENSE-2.0 │ -│ │ -│ Unless required by applicable law or agreed to in writing, software │ -│ distributed under the License is distributed on an "AS IS" BASIS, │ -│ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. │ -│ See the License for the specific language governing permissions and │ -│ limitations under the License. │ -╚─────────────────────────────────────────────────────────────────────────────*/ -#include "libc/calls/state.internal.h" -#include "libc/errno.h" -#include "libc/nt/enum/wait.h" -#include "libc/nt/synchronization.h" -#include "libc/runtime/runtime.h" -#include "third_party/nsync/mu_semaphore.h" -#include "third_party/nsync/mu_semaphore.internal.h" -#include "third_party/nsync/time.h" - -asm(".ident\t\"\\n\\n\ -*NSYNC (Apache 2.0)\\n\ -Copyright 2016 Google, Inc.\\n\ -https://github.com/google/nsync\""); -// clang-format off - -/* Initialize *s; the initial value is 0. */ -void nsync_mu_semaphore_init_win32 (nsync_semaphore *s) { - int64_t *h = (int64_t *) s; - *h = CreateSemaphore (&kNtIsInheritable, 0, 1, NULL); - if (!*h) notpossible; -} - -/* Wait until the count of *s exceeds 0, and decrement it. */ -void nsync_mu_semaphore_p_win32 (nsync_semaphore *s) { - int64_t *h = (int64_t *) s; - WaitForSingleObject (*h, -1u); -} - -/* Wait until one of: - the count of *s is non-zero, in which case decrement *s and return 0; - or abs_deadline expires, in which case return ETIMEDOUT. */ -int nsync_mu_semaphore_p_with_deadline_win32 (nsync_semaphore *s, nsync_time abs_deadline) { - int64_t *h = (int64_t *) s; - int result; - - if (nsync_time_cmp (abs_deadline, nsync_time_no_deadline) == 0) { - result = WaitForSingleObject (*h, -1u); - } else { - nsync_time now; - now = nsync_time_now (); - do { - if (nsync_time_cmp (abs_deadline, now) <= 0) { - result = WaitForSingleObject (*h, 0); - } else { - nsync_time delay; - delay = nsync_time_sub (abs_deadline, now); - if (NSYNC_TIME_SEC (delay) > 1000*1000) { - result = WaitForSingleObject (*h, 1000*1000); - } else { - result = WaitForSingleObject (*h, - (unsigned) (NSYNC_TIME_SEC (delay) * 1000 + - (NSYNC_TIME_NSEC (delay) + 999999) / (1000 * 1000))); - } - } - if (result == kNtWaitTimeout) { - now = nsync_time_now (); - } - } while (result == kNtWaitTimeout && /* Windows generates early wakeups. */ - nsync_time_cmp (abs_deadline, now) > 0); - } - return (result == kNtWaitTimeout ? ETIMEDOUT : 0); -} - -/* Ensure that the count of *s is at least 1. */ -void nsync_mu_semaphore_v_win32 (nsync_semaphore *s) { - int64_t *h = (int64_t *) s; - ReleaseSemaphore(*h, 1, NULL); -} diff --git a/third_party/nsync/testing/cv_mu_timeout_stress_test.c b/third_party/nsync/testing/cv_mu_timeout_stress_test_.c similarity index 100% rename from third_party/nsync/testing/cv_mu_timeout_stress_test.c rename to third_party/nsync/testing/cv_mu_timeout_stress_test_.c diff --git a/third_party/nsync/testing/cv_wait_example_test.c b/third_party/nsync/testing/cv_wait_example_test.c index 8d96ec3d2..8b21471f6 100644 --- a/third_party/nsync/testing/cv_wait_example_test.c +++ b/third_party/nsync/testing/cv_wait_example_test.c @@ -17,11 +17,11 @@ ╚─────────────────────────────────────────────────────────────────────────────*/ #include "libc/fmt/fmt.h" #include "libc/str/str.h" +#include "third_party/nsync/array.internal.h" #include "third_party/nsync/cv.h" +#include "third_party/nsync/heap.internal.h" #include "third_party/nsync/mu.h" -#include "third_party/nsync/testing/array.h" #include "third_party/nsync/testing/closure.h" -#include "third_party/nsync/testing/heap.h" #include "third_party/nsync/testing/smprintf.h" #include "third_party/nsync/testing/testing.h" #include "third_party/nsync/testing/time_extra.h" diff --git a/third_party/nsync/testing/dll_test.c b/third_party/nsync/testing/dll_test.c index f305db0d9..226f1f3b2 100644 --- a/third_party/nsync/testing/dll_test.c +++ b/third_party/nsync/testing/dll_test.c @@ -18,8 +18,8 @@ #include "libc/fmt/fmt.h" #include "libc/mem/mem.h" #include "libc/str/str.h" +#include "third_party/nsync/array.internal.h" #include "third_party/nsync/dll.h" -#include "third_party/nsync/testing/array.h" #include "third_party/nsync/testing/smprintf.h" #include "third_party/nsync/testing/testing.h" // clang-format off diff --git a/third_party/nsync/testing/mu_wait_example_test.c b/third_party/nsync/testing/mu_wait_example_test.c index f1f417007..1b2cef437 100644 --- a/third_party/nsync/testing/mu_wait_example_test.c +++ b/third_party/nsync/testing/mu_wait_example_test.c @@ -17,11 +17,11 @@ ╚─────────────────────────────────────────────────────────────────────────────*/ #include "libc/fmt/fmt.h" #include "libc/str/str.h" +#include "third_party/nsync/array.internal.h" +#include "third_party/nsync/heap.internal.h" #include "third_party/nsync/mu.h" #include "third_party/nsync/mu_wait.h" -#include "third_party/nsync/testing/array.h" #include "third_party/nsync/testing/closure.h" -#include "third_party/nsync/testing/heap.h" #include "third_party/nsync/testing/smprintf.h" #include "third_party/nsync/testing/testing.h" #include "third_party/nsync/testing/time_extra.h" diff --git a/third_party/nsync/testing/testing.mk b/third_party/nsync/testing/testing.mk index c7d2291d6..f215b838b 100644 --- a/third_party/nsync/testing/testing.mk +++ b/third_party/nsync/testing/testing.mk @@ -12,8 +12,8 @@ THIRD_PARTY_NSYNC_TESTING_SRCS_TEST = $(filter %_test.c,$(THIRD_PARTY_NSYNC_TEST THIRD_PARTY_NSYNC_TESTING_OBJS = $(THIRD_PARTY_NSYNC_TESTING_SRCS:%.c=o/$(MODE)/%.o) THIRD_PARTY_NSYNC_TESTING_COMS = $(THIRD_PARTY_NSYNC_TESTING_SRCS_TEST:%.c=o/$(MODE)/%.com) THIRD_PARTY_NSYNC_TESTING_BINS = $(THIRD_PARTY_NSYNC_TESTING_COMS) $(THIRD_PARTY_NSYNC_TESTING_COMS:%=%.dbg) -# THIRD_PARTY_NSYNC_TESTING_TESTS = $(THIRD_PARTY_NSYNC_TESTING_SRCS_TEST:%.c=o/$(MODE)/%.com.ok) -# THIRD_PARTY_NSYNC_TESTING_CHECKS = $(THIRD_PARTY_NSYNC_TESTING_SRCS_TEST:%.c=o/$(MODE)/%.com.runs) +THIRD_PARTY_NSYNC_TESTING_TESTS_ = $(THIRD_PARTY_NSYNC_TESTING_SRCS_TEST:%.c=o/$(MODE)/%.com.ok) +THIRD_PARTY_NSYNC_TESTING_CHECKS_ = $(THIRD_PARTY_NSYNC_TESTING_SRCS_TEST:%.c=o/$(MODE)/%.com.runs) THIRD_PARTY_NSYNC_TESTING_DIRECTDEPS = \ LIBC_CALLS \ @@ -57,10 +57,10 @@ o/$(MODE)/third_party/nsync/testing/mu_test.com.runs: private QUOTA = -C64 .PHONY: o/$(MODE)/third_party/nsync/testing o/$(MODE)/third_party/nsync/testing: \ - $(THIRD_PARTY_NSYNC_TESTING_CHECKS) \ - $(THIRD_PARTY_NSYNC_TESTING_BINS) + $(THIRD_PARTY_NSYNC_TESTING_CHECKS_) \ + $(THIRD_PARTY_NSYNC_TESTING_BINS_) .PHONY: o/$(MODE)/third_party/nsync/test o/$(MODE)/third_party/nsync/test: \ - $(THIRD_PARTY_NSYNC_TESTING_CHECKS) \ - $(THIRD_PARTY_NSYNC_TESTING_TESTS) + $(THIRD_PARTY_NSYNC_TESTING_CHECKS_) \ + $(THIRD_PARTY_NSYNC_TESTING_TESTS_) diff --git a/third_party/nsync/testing/time_extra.c b/third_party/nsync/testing/time_extra.c index d7d43b974..f778b6064 100644 --- a/third_party/nsync/testing/time_extra.c +++ b/third_party/nsync/testing/time_extra.c @@ -41,20 +41,6 @@ char *nsync_time_str (nsync_time t, int decimals) { return (smprintf ("%.*f%s", decimals, s/scale[i].multiplier, scale[i].suffix)); } -int nsync_time_sleep_until (nsync_time abs_deadline) { - int result = 0; - nsync_time now; - now = nsync_time_now (); - if (nsync_time_cmp (abs_deadline, now) > 0) { - nsync_time remaining; - remaining = nsync_time_sleep (nsync_time_sub (abs_deadline, now)); - if (nsync_time_cmp (remaining, nsync_time_zero) > 0) { - result = EINTR; - } - } - return (result); -} - double nsync_time_to_dbl (nsync_time t) { return (((double) NSYNC_TIME_SEC (t)) + ((double) NSYNC_TIME_NSEC (t) * 1e-9)); } diff --git a/third_party/nsync/testing/time_extra.h b/third_party/nsync/testing/time_extra.h index e59be4e4e..ddd12b353 100644 --- a/third_party/nsync/testing/time_extra.h +++ b/third_party/nsync/testing/time_extra.h @@ -6,10 +6,6 @@ "decimals" decimal places. */ char *nsync_time_str(nsync_time t, int decimals); -/* Sleep until the specified time. Returns 0 on success, and EINTR - if the call was interrupted. */ -int nsync_time_sleep_until(nsync_time abs_deadline); - /* Return t as a double. */ double nsync_time_to_dbl(nsync_time t); diff --git a/third_party/nsync/testing/wait_test.c b/third_party/nsync/testing/wait_test.c index af097522e..92e749052 100644 --- a/third_party/nsync/testing/wait_test.c +++ b/third_party/nsync/testing/wait_test.c @@ -16,9 +16,9 @@ │ limitations under the License. │ ╚─────────────────────────────────────────────────────────────────────────────*/ #include "libc/str/str.h" +#include "third_party/nsync/array.internal.h" #include "third_party/nsync/counter.h" #include "third_party/nsync/note.h" -#include "third_party/nsync/testing/array.h" #include "third_party/nsync/testing/closure.h" #include "third_party/nsync/testing/smprintf.h" #include "third_party/nsync/testing/testing.h" diff --git a/third_party/nsync/time.c b/third_party/nsync/time.c deleted file mode 100644 index d401c23cc..000000000 --- a/third_party/nsync/time.c +++ /dev/null @@ -1,54 +0,0 @@ -/*-*- mode:c;indent-tabs-mode:t;c-basic-offset:8;tab-width:8;coding:utf-8 -*-│ -│vi: set et ft=c ts=8 tw=8 fenc=utf-8 :vi│ -╞══════════════════════════════════════════════════════════════════════════════╡ -│ Copyright 2016 Google Inc. │ -│ │ -│ Licensed under the Apache License, Version 2.0 (the "License"); │ -│ you may not use this file except in compliance with the License. │ -│ You may obtain a copy of the License at │ -│ │ -│ http://www.apache.org/licenses/LICENSE-2.0 │ -│ │ -│ Unless required by applicable law or agreed to in writing, software │ -│ distributed under the License is distributed on an "AS IS" BASIS, │ -│ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. │ -│ See the License for the specific language governing permissions and │ -│ limitations under the License. │ -╚─────────────────────────────────────────────────────────────────────────────*/ -#include "libc/calls/struct/timespec.h" -#include "libc/str/str.h" -#include "libc/sysv/consts/clock.h" -#include "third_party/nsync/time.h" - -asm(".ident\t\"\\n\\n\ -*NSYNC (Apache 2.0)\\n\ -Copyright 2016 Google, Inc.\\n\ -https://github.com/google/nsync\""); -// clang-format off - -#define NSYNC_NS_IN_S_ (1000 * 1000 * 1000) - -/* Return the maximum t, assuming it's an integral - type, and the representation is not too strange. */ -#define MAX_INT_TYPE(t) (((t)~(t)0) > 1? /*is t unsigned?*/ \ - (t)~(t)0 : /*unsigned*/ \ - (t) ((((uintmax_t)1) << (sizeof (t) * CHAR_BIT - 1)) - 1)) /*signed*/ - -const nsync_time nsync_time_no_deadline = - NSYNC_TIME_STATIC_INIT (MAX_INT_TYPE (int64_t), NSYNC_NS_IN_S_ - 1); - -const nsync_time nsync_time_zero = NSYNC_TIME_STATIC_INIT (0, 0); - -nsync_time nsync_time_sleep (nsync_time delay) { - struct timespec ts; - struct timespec remain; - memset (&ts, 0, sizeof (ts)); - ts.tv_sec = NSYNC_TIME_SEC (delay); - ts.tv_nsec = NSYNC_TIME_NSEC (delay); - if (nanosleep (&ts, &remain) == 0) { - /* nanosleep() is not required to fill in "remain" - if it returns 0. */ - memset (&remain, 0, sizeof (remain)); - } - return (remain); -} diff --git a/third_party/nsync/time.h b/third_party/nsync/time.h index 2529d5d87..50f2ac92d 100644 --- a/third_party/nsync/time.h +++ b/third_party/nsync/time.h @@ -17,17 +17,21 @@ COSMOPOLITAN_C_START_ typedef struct timespec nsync_time; /* A deadline infinitely far in the future. */ -extern const nsync_time nsync_time_no_deadline; +#define nsync_time_no_deadline _timespec_max /* The zero delay, or an expired deadline. */ -extern const nsync_time nsync_time_zero; +#define nsync_time_zero _timespec_zero /* Return the current time since the epoch. */ #define nsync_time_now() _timespec_real() /* Sleep for the specified delay. Returns the unslept time which may be non-zero if the call was interrupted. */ -nsync_time nsync_time_sleep(nsync_time delay); +#define nsync_time_sleep(a) _timespec_sleep(a) + +/* Sleep until the specified time. Returns 0 on success, and EINTR + if the call was interrupted. */ +#define nsync_time_sleep_until(a) _timespec_sleep_until(a) /* Return a+b */ #define nsync_time_add(a, b) _timespec_add(a, b) @@ -44,6 +48,9 @@ nsync_time nsync_time_sleep(nsync_time delay); /* Return the specified number of microseconds as a time. */ #define nsync_time_us(a) _timespec_frommicros(a) +/* Return the specified number of nanoseconds as a time. */ +#define nsync_time_ns(a) _timespec_fromnanos(a) + /* Return an nsync_time constructed from second and nanosecond components */ #define nsync_time_s_ns(s, ns) ((nsync_time){(int64_t)(s), (unsigned)(ns)})