mirror of
https://github.com/jart/cosmopolitan.git
synced 2025-02-12 01:08:00 +00:00
Clean up some sleep code
This commit is contained in:
parent
9849b4c7ba
commit
672ccda37c
35 changed files with 310 additions and 598 deletions
38
libc/calls/_timespec_sleep.c
Normal file
38
libc/calls/_timespec_sleep.c
Normal file
|
@ -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;
|
||||||
|
}
|
||||||
|
}
|
|
@ -16,5 +16,20 @@
|
||||||
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
||||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
│ 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;
|
||||||
|
}
|
|
@ -33,6 +33,7 @@
|
||||||
#include "libc/mem/alloca.h"
|
#include "libc/mem/alloca.h"
|
||||||
#include "libc/nt/synchronization.h"
|
#include "libc/nt/synchronization.h"
|
||||||
#include "libc/sysv/errfuns.h"
|
#include "libc/sysv/errfuns.h"
|
||||||
|
#include "libc/thread/tls.h"
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns nanosecond time.
|
* Returns nanosecond time.
|
||||||
|
@ -83,7 +84,7 @@ int clock_gettime(int clock, struct timespec *ts) {
|
||||||
rc = __clock_gettime(clock, ts);
|
rc = __clock_gettime(clock, ts);
|
||||||
}
|
}
|
||||||
#if SYSDEBUG
|
#if SYSDEBUG
|
||||||
if (!__time_critical) {
|
if (!(__get_tls()->tib_flags & TIB_FLAG_TIME_CRITICAL)) {
|
||||||
STRACE("clock_gettime(%s, [%s]) → %d% m", DescribeClockName(clock),
|
STRACE("clock_gettime(%s, [%s]) → %d% m", DescribeClockName(clock),
|
||||||
DescribeTimespec(rc, ts), rc);
|
DescribeTimespec(rc, ts), rc);
|
||||||
}
|
}
|
||||||
|
|
|
@ -29,6 +29,7 @@
|
||||||
#include "libc/sysv/consts/clock.h"
|
#include "libc/sysv/consts/clock.h"
|
||||||
#include "libc/sysv/consts/timer.h"
|
#include "libc/sysv/consts/timer.h"
|
||||||
#include "libc/sysv/errfuns.h"
|
#include "libc/sysv/errfuns.h"
|
||||||
|
#include "libc/thread/tls.h"
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sleeps for particular amount of time.
|
* 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 SYSDEBUG
|
||||||
if (!__time_critical) {
|
if (!(__get_tls()->tib_flags & TIB_FLAG_TIME_CRITICAL)) {
|
||||||
STRACE("clock_nanosleep(%s, %s, %s, [%s]) → %s", DescribeClockName(clock),
|
STRACE("clock_nanosleep(%s, %s, %s, [%s]) → %s", DescribeClockName(clock),
|
||||||
DescribeSleepFlags(flags), DescribeTimespec(0, req),
|
DescribeSleepFlags(flags), DescribeTimespec(0, req),
|
||||||
DescribeTimespec(rc, rem), DescribeErrnoResult(rc));
|
DescribeTimespec(rc, rem), DescribeErrnoResult(rc));
|
||||||
|
|
|
@ -18,7 +18,6 @@
|
||||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||||
#include "libc/assert.h"
|
#include "libc/assert.h"
|
||||||
#include "libc/calls/state.internal.h"
|
#include "libc/calls/state.internal.h"
|
||||||
#include "libc/intrin/strace.internal.h"
|
|
||||||
#include "libc/calls/struct/itimerval.internal.h"
|
#include "libc/calls/struct/itimerval.internal.h"
|
||||||
#include "libc/calls/struct/timeval.h"
|
#include "libc/calls/struct/timeval.h"
|
||||||
#include "libc/calls/struct/timeval.internal.h"
|
#include "libc/calls/struct/timeval.internal.h"
|
||||||
|
@ -26,7 +25,9 @@
|
||||||
#include "libc/dce.h"
|
#include "libc/dce.h"
|
||||||
#include "libc/intrin/asan.internal.h"
|
#include "libc/intrin/asan.internal.h"
|
||||||
#include "libc/intrin/describeflags.internal.h"
|
#include "libc/intrin/describeflags.internal.h"
|
||||||
|
#include "libc/intrin/strace.internal.h"
|
||||||
#include "libc/sysv/errfuns.h"
|
#include "libc/sysv/errfuns.h"
|
||||||
|
#include "libc/thread/tls.h"
|
||||||
#include "libc/time/struct/timezone.h"
|
#include "libc/time/struct/timezone.h"
|
||||||
|
|
||||||
typedef axdx_t gettimeofday_f(struct timeval *, struct timezone *, void *);
|
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;
|
rc = __gettimeofday(tv, tz, 0).ax;
|
||||||
}
|
}
|
||||||
#if SYSDEBUG
|
#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);
|
STRACE("gettimeofday([%s], %p) → %d% m", DescribeTimeval(rc, tv), tz, rc);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -31,11 +31,12 @@
|
||||||
|
|
||||||
textwindows bool _check_interrupts(bool restartable, struct Fd *fd) {
|
textwindows bool _check_interrupts(bool restartable, struct Fd *fd) {
|
||||||
bool res;
|
bool res;
|
||||||
if (__time_critical) return false;
|
|
||||||
if (__threaded && __threaded != gettid()) return false;
|
if (__threaded && __threaded != gettid()) return false;
|
||||||
if (_weaken(_check_sigalrm)) _weaken(_check_sigalrm)();
|
if (_weaken(_check_sigalrm)) _weaken(_check_sigalrm)();
|
||||||
if (_weaken(_check_sigchld)) _weaken(_check_sigchld)();
|
if (!(__get_tls()->tib_flags & TIB_FLAG_TIME_CRITICAL)) {
|
||||||
if (fd && _weaken(_check_sigwinch)) _weaken(_check_sigwinch)(fd);
|
if (_weaken(_check_sigchld)) _weaken(_check_sigchld)();
|
||||||
|
if (fd && _weaken(_check_sigwinch)) _weaken(_check_sigwinch)(fd);
|
||||||
|
}
|
||||||
res = _weaken(__sig_check) && _weaken(__sig_check)(restartable);
|
res = _weaken(__sig_check) && _weaken(__sig_check)(restartable);
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
|
@ -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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -16,18 +16,9 @@
|
||||||
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
||||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||||
#include "libc/calls/asan.internal.h"
|
#include "libc/calls/struct/timespec.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/errno.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/consts/clock.h"
|
||||||
#include "libc/sysv/errfuns.h"
|
|
||||||
|
|
||||||
// TODO(jart): Just delegate to clock_nanosleep()
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sleeps for relative amount of time.
|
* Sleeps for relative amount of time.
|
||||||
|
@ -45,32 +36,10 @@
|
||||||
*/
|
*/
|
||||||
int nanosleep(const struct timespec *req, struct timespec *rem) {
|
int nanosleep(const struct timespec *req, struct timespec *rem) {
|
||||||
int rc;
|
int rc;
|
||||||
|
if (!(rc = clock_nanosleep(CLOCK_REALTIME, 0, req, rem))) {
|
||||||
if (!req || (IsAsan() && (!__asan_is_valid_timespec(req) ||
|
return 0;
|
||||||
(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();
|
|
||||||
} else {
|
} 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;
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -17,20 +17,21 @@
|
||||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||||
#include "libc/assert.h"
|
#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/calls.h"
|
||||||
#include "libc/calls/clock_gettime.internal.h"
|
#include "libc/calls/clock_gettime.internal.h"
|
||||||
#include "libc/calls/state.internal.h"
|
#include "libc/calls/state.internal.h"
|
||||||
#include "libc/intrin/strace.internal.h"
|
|
||||||
#include "libc/calls/syscall_support-sysv.internal.h"
|
#include "libc/calls/syscall_support-sysv.internal.h"
|
||||||
#include "libc/dce.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/macros.internal.h"
|
||||||
#include "libc/nexgen32e/rdtsc.h"
|
#include "libc/nexgen32e/rdtsc.h"
|
||||||
#include "libc/nexgen32e/x86feature.h"
|
#include "libc/nexgen32e/x86feature.h"
|
||||||
#include "libc/str/str.h"
|
#include "libc/str/str.h"
|
||||||
#include "libc/sysv/consts/clock.h"
|
#include "libc/sysv/consts/clock.h"
|
||||||
|
#include "libc/thread/tls.h"
|
||||||
#include "libc/time/time.h"
|
#include "libc/time/time.h"
|
||||||
|
|
||||||
static clock_gettime_f *__gettime;
|
static clock_gettime_f *__gettime;
|
||||||
|
@ -53,11 +54,9 @@ static long double GetTimeSample(void) {
|
||||||
}
|
}
|
||||||
|
|
||||||
static long double MeasureNanosPerCycle(void) {
|
static long double MeasureNanosPerCycle(void) {
|
||||||
bool tc;
|
|
||||||
int i, n;
|
int i, n;
|
||||||
long double avg, samp;
|
long double avg, samp;
|
||||||
tc = __time_critical;
|
__get_tls()->tib_flags |= TIB_FLAG_TIME_CRITICAL;
|
||||||
__time_critical = true;
|
|
||||||
if (IsWindows()) {
|
if (IsWindows()) {
|
||||||
n = 10;
|
n = 10;
|
||||||
} else {
|
} else {
|
||||||
|
@ -67,7 +66,7 @@ static long double MeasureNanosPerCycle(void) {
|
||||||
samp = GetTimeSample();
|
samp = GetTimeSample();
|
||||||
avg += (samp - avg) / i;
|
avg += (samp - avg) / i;
|
||||||
}
|
}
|
||||||
__time_critical = tc;
|
__get_tls()->tib_flags &= ~TIB_FLAG_TIME_CRITICAL;
|
||||||
STRACE("MeasureNanosPerCycle cpn*1000=%d", (long)(avg * 1000));
|
STRACE("MeasureNanosPerCycle cpn*1000=%d", (long)(avg * 1000));
|
||||||
return avg;
|
return avg;
|
||||||
}
|
}
|
||||||
|
|
|
@ -18,17 +18,18 @@
|
||||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||||
#include "libc/calls/calls.h"
|
#include "libc/calls/calls.h"
|
||||||
#include "libc/calls/state.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.h"
|
||||||
#include "libc/dce.h"
|
#include "libc/dce.h"
|
||||||
#include "libc/intrin/bits.h"
|
#include "libc/intrin/bits.h"
|
||||||
#include "libc/intrin/initializer.internal.h"
|
#include "libc/intrin/initializer.internal.h"
|
||||||
#include "libc/intrin/safemacros.internal.h"
|
#include "libc/intrin/safemacros.internal.h"
|
||||||
|
#include "libc/intrin/strace.internal.h"
|
||||||
#include "libc/macros.internal.h"
|
#include "libc/macros.internal.h"
|
||||||
#include "libc/nexgen32e/rdtsc.h"
|
#include "libc/nexgen32e/rdtsc.h"
|
||||||
#include "libc/nexgen32e/x86feature.h"
|
#include "libc/nexgen32e/x86feature.h"
|
||||||
#include "libc/str/str.h"
|
#include "libc/str/str.h"
|
||||||
#include "libc/sysv/consts/clock.h"
|
#include "libc/sysv/consts/clock.h"
|
||||||
|
#include "libc/thread/tls.h"
|
||||||
#include "libc/time/time.h"
|
#include "libc/time/time.h"
|
||||||
|
|
||||||
static struct Now {
|
static struct Now {
|
||||||
|
@ -50,11 +51,9 @@ static long double GetTimeSample(void) {
|
||||||
}
|
}
|
||||||
|
|
||||||
static long double MeasureNanosPerCycle(void) {
|
static long double MeasureNanosPerCycle(void) {
|
||||||
bool tc;
|
|
||||||
int i, n;
|
int i, n;
|
||||||
long double avg, samp;
|
long double avg, samp;
|
||||||
tc = __time_critical;
|
__get_tls()->tib_flags |= TIB_FLAG_TIME_CRITICAL;
|
||||||
__time_critical = true;
|
|
||||||
if (IsWindows()) {
|
if (IsWindows()) {
|
||||||
n = 30;
|
n = 30;
|
||||||
} else {
|
} else {
|
||||||
|
@ -64,7 +63,7 @@ static long double MeasureNanosPerCycle(void) {
|
||||||
samp = GetTimeSample();
|
samp = GetTimeSample();
|
||||||
avg += (samp - avg) / i;
|
avg += (samp - avg) / i;
|
||||||
}
|
}
|
||||||
__time_critical = tc;
|
__get_tls()->tib_flags &= ~TIB_FLAG_TIME_CRITICAL;
|
||||||
STRACE("MeasureNanosPerCycle cpn*1000=%d", (long)(avg * 1000));
|
STRACE("MeasureNanosPerCycle cpn*1000=%d", (long)(avg * 1000));
|
||||||
return avg;
|
return avg;
|
||||||
}
|
}
|
||||||
|
|
|
@ -17,8 +17,8 @@
|
||||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||||
#include "libc/calls/struct/timespec.h"
|
#include "libc/calls/struct/timespec.h"
|
||||||
#include "libc/errno.h"
|
|
||||||
#include "libc/limits.h"
|
#include "libc/limits.h"
|
||||||
|
#include "libc/sysv/consts/clock.h"
|
||||||
#include "libc/time/time.h"
|
#include "libc/time/time.h"
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -33,12 +33,9 @@
|
||||||
* @norestart
|
* @norestart
|
||||||
*/
|
*/
|
||||||
unsigned sleep(unsigned seconds) {
|
unsigned sleep(unsigned seconds) {
|
||||||
int err;
|
|
||||||
unsigned unslept;
|
unsigned unslept;
|
||||||
struct timespec tv = {seconds};
|
struct timespec tv = {seconds};
|
||||||
err = errno;
|
if (!clock_nanosleep(CLOCK_REALTIME, 0, &tv, &tv)) return 0;
|
||||||
nanosleep(&tv, &tv);
|
|
||||||
errno = err;
|
|
||||||
unslept = tv.tv_sec;
|
unslept = tv.tv_sec;
|
||||||
if (tv.tv_nsec && unslept < UINT_MAX) {
|
if (tv.tv_nsec && unslept < UINT_MAX) {
|
||||||
++unslept;
|
++unslept;
|
||||||
|
|
|
@ -3,6 +3,9 @@
|
||||||
#if !(__ASSEMBLER__ + __LINKER__ + 0)
|
#if !(__ASSEMBLER__ + __LINKER__ + 0)
|
||||||
COSMOPOLITAN_C_START_
|
COSMOPOLITAN_C_START_
|
||||||
|
|
||||||
|
#define _timespec_zero ((struct timespec){0})
|
||||||
|
#define _timespec_max ((struct timespec){0x7fffffffffffffff, 999999999})
|
||||||
|
|
||||||
struct timespec {
|
struct timespec {
|
||||||
int64_t tv_sec;
|
int64_t tv_sec;
|
||||||
int64_t tv_nsec; /* nanoseconds */
|
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_fromnanos(int64_t) pureconst;
|
||||||
struct timespec _timespec_frommicros(int64_t) pureconst;
|
struct timespec _timespec_frommicros(int64_t) pureconst;
|
||||||
struct timespec _timespec_frommillis(int64_t) pureconst;
|
struct timespec _timespec_frommillis(int64_t) pureconst;
|
||||||
struct timespec _timespec_mono(void);
|
|
||||||
struct timespec _timespec_real(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;
|
struct timespec _timespec_sub(struct timespec, struct timespec) pureconst;
|
||||||
|
|
||||||
COSMOPOLITAN_C_END_
|
COSMOPOLITAN_C_END_
|
||||||
|
|
|
@ -17,6 +17,8 @@
|
||||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||||
#include "libc/calls/struct/timespec.h"
|
#include "libc/calls/struct/timespec.h"
|
||||||
|
#include "libc/sysv/consts/clock.h"
|
||||||
|
#include "libc/sysv/errfuns.h"
|
||||||
#include "libc/time/time.h"
|
#include "libc/time/time.h"
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -28,7 +30,7 @@
|
||||||
* @norestart
|
* @norestart
|
||||||
*/
|
*/
|
||||||
int usleep(uint32_t micros) {
|
int usleep(uint32_t micros) {
|
||||||
struct timespec ts;
|
struct timespec ts = _timespec_frommicros(micros);
|
||||||
ts = _timespec_frommicros(micros);
|
if (clock_nanosleep(CLOCK_REALTIME, 0, &ts, 0)) return eintr();
|
||||||
return nanosleep(&ts, 0);
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
|
@ -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
|
# 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_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_REQUEUE 3 0 0 3 0 0
|
||||||
syscon futex FUTEX_PRIVATE_FLAG 128 0 128 128 0 0
|
syscon futex FUTEX_PRIVATE_FLAG 128 0 128 128 0 0
|
||||||
|
|
||||||
|
|
|
@ -1,2 +1,2 @@
|
||||||
.include "o/libc/sysv/consts/syscon.internal.inc"
|
.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
|
||||||
|
|
|
@ -4,6 +4,8 @@
|
||||||
|
|
||||||
#define TLS_ALIGNMENT 64
|
#define TLS_ALIGNMENT 64
|
||||||
|
|
||||||
|
#define TIB_FLAG_TIME_CRITICAL 1
|
||||||
|
|
||||||
#if !(__ASSEMBLER__ + __LINKER__ + 0)
|
#if !(__ASSEMBLER__ + __LINKER__ + 0)
|
||||||
COSMOPOLITAN_C_START_
|
COSMOPOLITAN_C_START_
|
||||||
|
|
||||||
|
@ -24,7 +26,7 @@ struct CosmoTib {
|
||||||
_Atomic(int32_t) tib_tid; /* 0x38 */
|
_Atomic(int32_t) tib_tid; /* 0x38 */
|
||||||
int32_t tib_errno; /* 0x3c */
|
int32_t tib_errno; /* 0x3c */
|
||||||
void *tib_nsync;
|
void *tib_nsync;
|
||||||
void *tib_reserved1;
|
uint64_t tib_flags;
|
||||||
void *tib_reserved2;
|
void *tib_reserved2;
|
||||||
void *tib_reserved3;
|
void *tib_reserved3;
|
||||||
void *tib_reserved4;
|
void *tib_reserved4;
|
||||||
|
|
6
third_party/nsync/testing/array.h → third_party/nsync/array.internal.h
vendored
Normal file → Executable file
6
third_party/nsync/testing/array.h → third_party/nsync/array.internal.h
vendored
Normal file → Executable file
|
@ -1,5 +1,5 @@
|
||||||
#ifndef NSYNC_TESTING_ARRAY_H_
|
#ifndef NSYNC_ARRAY_H_
|
||||||
#define NSYNC_TESTING_ARRAY_H_
|
#define NSYNC_ARRAY_H_
|
||||||
/* clang-format off */
|
/* clang-format off */
|
||||||
|
|
||||||
/* Return the number of elements in a C array a.
|
/* 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; \
|
(a)->a_ = NULL; (a)->h_.max_ = 0; (a)->h_.len_ = 0; \
|
||||||
} while (0)
|
} while (0)
|
||||||
|
|
||||||
#endif /*NSYNC_TESTING_ARRAY_H_*/
|
#endif /*NSYNC_ARRAY_H_*/
|
8
third_party/nsync/compat.S
vendored
8
third_party/nsync/compat.S
vendored
|
@ -41,3 +41,11 @@ nsync_time_ms:
|
||||||
nsync_time_us:
|
nsync_time_us:
|
||||||
jmp _timespec_frommicros
|
jmp _timespec_frommicros
|
||||||
.endfn nsync_time_us,globl
|
.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
|
||||||
|
|
145
third_party/nsync/futex.c
vendored
145
third_party/nsync/futex.c
vendored
|
@ -17,7 +17,9 @@
|
||||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||||
#include "libc/atomic.h"
|
#include "libc/atomic.h"
|
||||||
|
#include "libc/calls/calls.h"
|
||||||
#include "libc/calls/sig.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.h"
|
||||||
#include "libc/calls/struct/timespec.internal.h"
|
#include "libc/calls/struct/timespec.internal.h"
|
||||||
#include "libc/dce.h"
|
#include "libc/dce.h"
|
||||||
|
@ -33,8 +35,10 @@
|
||||||
#include "libc/sysv/consts/timer.h"
|
#include "libc/sysv/consts/timer.h"
|
||||||
#include "libc/thread/freebsd.internal.h"
|
#include "libc/thread/freebsd.internal.h"
|
||||||
#include "libc/thread/thread.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/common.internal.h"
|
||||||
#include "third_party/nsync/mu_semaphore.internal.h"
|
#include "third_party/nsync/time.h"
|
||||||
// clang-format off
|
// clang-format off
|
||||||
|
|
||||||
/* futex() polyfill w/ sched_yield() fallback */
|
/* futex() polyfill w/ sched_yield() fallback */
|
||||||
|
@ -51,15 +55,15 @@ bool FUTEX_TIMEOUT_IS_ABSOLUTE;
|
||||||
__attribute__((__constructor__)) static void nsync_futex_init_ (void) {
|
__attribute__((__constructor__)) static void nsync_futex_init_ (void) {
|
||||||
int x = 0;
|
int x = 0;
|
||||||
|
|
||||||
if (NSYNC_FUTEX_WIN32 && IsWindows ()) {
|
FUTEX_WAIT_ = FUTEX_WAIT;
|
||||||
|
|
||||||
|
if (IsWindows ()) {
|
||||||
FUTEX_IS_SUPPORTED = true;
|
FUTEX_IS_SUPPORTED = true;
|
||||||
FUTEX_WAIT_ = FUTEX_WAIT;
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (IsFreebsd ()) {
|
if (IsFreebsd ()) {
|
||||||
FUTEX_IS_SUPPORTED = true;
|
FUTEX_IS_SUPPORTED = true;
|
||||||
FUTEX_WAIT_ = FUTEX_WAIT;
|
|
||||||
FUTEX_TIMEOUT_IS_ABSOLUTE = true;
|
FUTEX_TIMEOUT_IS_ABSOLUTE = true;
|
||||||
FUTEX_PRIVATE_FLAG_ = FUTEX_PRIVATE_FLAG;
|
FUTEX_PRIVATE_FLAG_ = FUTEX_PRIVATE_FLAG;
|
||||||
return;
|
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) {
|
static int nsync_futex_polyfill_ (int *p, int expect, struct timespec *timeout) {
|
||||||
int rc;
|
int64_t nanos, maxnanos;
|
||||||
atomic_int *w;
|
nsync_atomic_uint32_ *w;
|
||||||
int64_t max, nanos;
|
|
||||||
struct timespec ts, deadline;
|
struct timespec ts, deadline;
|
||||||
|
|
||||||
w = (atomic_int *)p;
|
w = (nsync_atomic_uint32_ *)p;
|
||||||
if (atomic_load_explicit (p, memory_order_relaxed) != expect) {
|
if (ATM_LOAD (p) != expect) {
|
||||||
return -EAGAIN;
|
return -EAGAIN;
|
||||||
}
|
}
|
||||||
|
|
||||||
ts = _timespec_real ();
|
ts = nsync_time_now ();
|
||||||
if (!timeout) {
|
if (!timeout) {
|
||||||
deadline = nsync_time_no_deadline;
|
deadline = nsync_time_no_deadline;
|
||||||
} else if (FUTEX_TIMEOUT_IS_ABSOLUTE) {
|
} else if (FUTEX_TIMEOUT_IS_ABSOLUTE) {
|
||||||
deadline = *timeout;
|
deadline = *timeout;
|
||||||
} else {
|
} else {
|
||||||
deadline = _timespec_add (ts, *timeout);
|
deadline = nsync_time_add (ts, *timeout);
|
||||||
}
|
}
|
||||||
|
|
||||||
nanos = 100;
|
nanos = 100;
|
||||||
max = __SIG_POLLING_INTERVAL_MS * 1000L * 1000;
|
maxnanos = __SIG_POLLING_INTERVAL_MS * 1000L * 1000;
|
||||||
while (_timespec_gt (deadline, ts)) {
|
while (nsync_time_cmp (deadline, ts) > 0) {
|
||||||
if (atomic_load_explicit (p, memory_order_relaxed) != expect) {
|
if (ATM_LOAD (p) != expect) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
ts = _timespec_add (ts, _timespec_fromnanos (nanos));
|
ts = nsync_time_add (ts, _timespec_fromnanos (nanos));
|
||||||
if (_timespec_gt (ts, deadline)) {
|
if (nsync_time_cmp (ts, deadline) > 0) {
|
||||||
ts = deadline;
|
ts = deadline;
|
||||||
}
|
}
|
||||||
rc = clock_nanosleep (CLOCK_REALTIME, TIMER_ABSTIME, &ts, 0);
|
if (nsync_time_sleep_until (ts)) {
|
||||||
if (rc) {
|
|
||||||
ASSERT (rc == EINTR);
|
|
||||||
return -EINTR;
|
return -EINTR;
|
||||||
}
|
}
|
||||||
if (nanos < max) {
|
if (nanos < maxnanos) {
|
||||||
nanos <<= 1;
|
nanos <<= 1;
|
||||||
if (nanos > max) {
|
if (nanos > maxnanos) {
|
||||||
nanos = max;
|
nanos = maxnanos;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -154,38 +155,42 @@ int nsync_futex_wait_ (int *p, int expect, char pshare, struct timespec *timeout
|
||||||
uint32_t ms;
|
uint32_t ms;
|
||||||
int rc, op, fop;
|
int rc, op, fop;
|
||||||
|
|
||||||
if (!FUTEX_IS_SUPPORTED) {
|
|
||||||
return nsync_futex_polyfill_ (p, expect, timeout);
|
|
||||||
}
|
|
||||||
|
|
||||||
op = FUTEX_WAIT_;
|
op = FUTEX_WAIT_;
|
||||||
if (pshare == PTHREAD_PROCESS_PRIVATE) {
|
if (pshare == PTHREAD_PROCESS_PRIVATE) {
|
||||||
op |= FUTEX_PRIVATE_FLAG_;
|
op |= FUTEX_PRIVATE_FLAG_;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (NSYNC_FUTEX_WIN32 && IsWindows ()) {
|
if (FUTEX_IS_SUPPORTED) {
|
||||||
// Windows 8 futexes don't support multiple processes :(
|
if (IsWindows ()) {
|
||||||
if (pshare) {
|
// Windows 8 futexes don't support multiple processes :(
|
||||||
return nsync_futex_polyfill_ (p, expect, timeout);
|
if (pshare) {
|
||||||
}
|
goto Polyfill;
|
||||||
if (timeout) {
|
}
|
||||||
ms = _timespec_tomillis (*timeout);
|
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 {
|
} 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 {
|
} else {
|
||||||
rc = _futex (p, op, expect, timeout, 0, FUTEX_WAIT_BITS_);
|
Polyfill:
|
||||||
if (IsOpenbsd() && rc > 0) {
|
__get_tls()->tib_flags |= TIB_FLAG_TIME_CRITICAL;
|
||||||
// [jart] openbsd does this without setting carry flag
|
rc = nsync_futex_polyfill_ (p, expect, timeout);
|
||||||
rc = -rc;
|
__get_tls()->tib_flags &= ~TIB_FLAG_TIME_CRITICAL;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
STRACE ("futex(%t, %s, %d, %s) → %s",
|
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);
|
ASSERT (count == 1 || count == INT_MAX);
|
||||||
|
|
||||||
if (!FUTEX_IS_SUPPORTED) {
|
|
||||||
nsync_yield_ ();
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
op = FUTEX_WAKE;
|
op = FUTEX_WAKE;
|
||||||
if (pshare == PTHREAD_PROCESS_PRIVATE) {
|
if (pshare == PTHREAD_PROCESS_PRIVATE) {
|
||||||
op |= FUTEX_PRIVATE_FLAG_;
|
op |= FUTEX_PRIVATE_FLAG_;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (NSYNC_FUTEX_WIN32 && IsWindows ()) {
|
if (FUTEX_IS_SUPPORTED) {
|
||||||
if (pshare) {
|
if (IsWindows ()) {
|
||||||
nsync_yield_ ();
|
if (pshare) {
|
||||||
return 0;
|
goto Polyfill;
|
||||||
}
|
}
|
||||||
if (count == 1) {
|
if (count == 1) {
|
||||||
WakeByAddressSingle (p);
|
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 {
|
} 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 {
|
} else {
|
||||||
rc = wake (p, op, count);
|
Polyfill:
|
||||||
|
sched_yield ();
|
||||||
|
rc = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
STRACE ("futex(%t, %s, %d) → %s", p,
|
STRACE ("futex(%t, %s, %d) → %s",
|
||||||
DescribeFutexOp(op),
|
p, DescribeFutexOp(op),
|
||||||
count, DescribeErrnoResult(rc));
|
count, DescribeErrnoResult(rc));
|
||||||
|
|
||||||
return rc;
|
return rc;
|
||||||
|
|
|
@ -17,7 +17,7 @@
|
||||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||||
#include "libc/mem/mem.h"
|
#include "libc/mem/mem.h"
|
||||||
#include "libc/str/str.h"
|
#include "libc/str/str.h"
|
||||||
#include "third_party/nsync/testing/array.h"
|
#include "third_party/nsync/array.internal.h"
|
||||||
// clang-format off
|
// clang-format off
|
||||||
|
|
||||||
void a_ensure_ (void *v, int delta, int sz) {
|
void a_ensure_ (void *v, int delta, int sz) {
|
132
third_party/nsync/mu_semaphore.c
vendored
132
third_party/nsync/mu_semaphore.c
vendored
|
@ -1,56 +1,128 @@
|
||||||
/*-*- mode:c;indent-tabs-mode:t;c-basic-offset:8;tab-width:8;coding:utf-8 -*-│
|
/*-*- 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│
|
│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 │
|
│ Licensed under the Apache License, Version 2.0 (the "License"); │
|
||||||
│ any purpose with or without fee is hereby granted, provided that the │
|
│ you may not use this file except in compliance with the License. │
|
||||||
│ above copyright notice and this permission notice appear in all copies. │
|
│ You may obtain a copy of the License at │
|
||||||
│ │
|
│ │
|
||||||
│ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL │
|
│ http://www.apache.org/licenses/LICENSE-2.0 │
|
||||||
│ WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED │
|
│ │
|
||||||
│ WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE │
|
│ Unless required by applicable law or agreed to in writing, software │
|
||||||
│ AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL │
|
│ distributed under the License is distributed on an "AS IS" BASIS, │
|
||||||
│ DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR │
|
│ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. │
|
||||||
│ PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER │
|
│ See the License for the specific language governing permissions and │
|
||||||
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
│ limitations under the License. │
|
||||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
|
||||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||||
#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.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
|
// 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. */
|
/* Initialize *s; the initial value is 0. */
|
||||||
void nsync_mu_semaphore_init (nsync_semaphore *s) {
|
void nsync_mu_semaphore_init (nsync_semaphore *s) {
|
||||||
if (NSYNC_FUTEX_WIN32 || !IsWindows ())
|
struct futex *f = (struct futex *) s;
|
||||||
nsync_mu_semaphore_init_futex (s);
|
f->i = 0;
|
||||||
else
|
|
||||||
nsync_mu_semaphore_init_win32 (s);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Wait until the count of *s exceeds 0, and decrement it. */
|
/* Wait until the count of *s exceeds 0, and decrement it. */
|
||||||
void nsync_mu_semaphore_p (nsync_semaphore *s) {
|
void nsync_mu_semaphore_p (nsync_semaphore *s) {
|
||||||
if (NSYNC_FUTEX_WIN32 || !IsWindows ())
|
struct futex *f = (struct futex *) s;
|
||||||
nsync_mu_semaphore_p_futex (s);
|
int i;
|
||||||
else
|
do {
|
||||||
nsync_mu_semaphore_p_win32 (s);
|
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:
|
/* Wait until one of:
|
||||||
the count of *s is non-zero, in which case decrement *s and return 0;
|
the count of *s is non-zero, in which case decrement *s and return 0;
|
||||||
or abs_deadline expires, in which case return ETIMEDOUT. */
|
or abs_deadline expires, in which case return ETIMEDOUT. */
|
||||||
int nsync_mu_semaphore_p_with_deadline (nsync_semaphore *s, nsync_time abs_deadline) {
|
int nsync_mu_semaphore_p_with_deadline (nsync_semaphore *s, nsync_time abs_deadline) {
|
||||||
if (NSYNC_FUTEX_WIN32 || !IsWindows ())
|
struct futex *f = (struct futex *)s;
|
||||||
return nsync_mu_semaphore_p_with_deadline_futex (s, abs_deadline);
|
int i;
|
||||||
else
|
int result = 0;
|
||||||
return nsync_mu_semaphore_p_with_deadline_win32 (s, abs_deadline);
|
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. */
|
/* Ensure that the count of *s is at least 1. */
|
||||||
void nsync_mu_semaphore_v (nsync_semaphore *s) {
|
void nsync_mu_semaphore_v (nsync_semaphore *s) {
|
||||||
if (NSYNC_FUTEX_WIN32 || !IsWindows ())
|
struct futex *f = (struct futex *) s;
|
||||||
nsync_mu_semaphore_v_futex (s);
|
uint32_t old_value;
|
||||||
else
|
do {
|
||||||
nsync_mu_semaphore_v_win32 (s);
|
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);
|
||||||
}
|
}
|
||||||
|
|
25
third_party/nsync/mu_semaphore.internal.h
vendored
Normal file → Executable file
25
third_party/nsync/mu_semaphore.internal.h
vendored
Normal file → Executable file
|
@ -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_ */
|
|
129
third_party/nsync/mu_semaphore_futex.c
vendored
129
third_party/nsync/mu_semaphore_futex.c
vendored
|
@ -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);
|
|
||||||
}
|
|
85
third_party/nsync/mu_semaphore_win32.c
vendored
85
third_party/nsync/mu_semaphore_win32.c
vendored
|
@ -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);
|
|
||||||
}
|
|
|
@ -17,11 +17,11 @@
|
||||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||||
#include "libc/fmt/fmt.h"
|
#include "libc/fmt/fmt.h"
|
||||||
#include "libc/str/str.h"
|
#include "libc/str/str.h"
|
||||||
|
#include "third_party/nsync/array.internal.h"
|
||||||
#include "third_party/nsync/cv.h"
|
#include "third_party/nsync/cv.h"
|
||||||
|
#include "third_party/nsync/heap.internal.h"
|
||||||
#include "third_party/nsync/mu.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/closure.h"
|
||||||
#include "third_party/nsync/testing/heap.h"
|
|
||||||
#include "third_party/nsync/testing/smprintf.h"
|
#include "third_party/nsync/testing/smprintf.h"
|
||||||
#include "third_party/nsync/testing/testing.h"
|
#include "third_party/nsync/testing/testing.h"
|
||||||
#include "third_party/nsync/testing/time_extra.h"
|
#include "third_party/nsync/testing/time_extra.h"
|
||||||
|
|
2
third_party/nsync/testing/dll_test.c
vendored
2
third_party/nsync/testing/dll_test.c
vendored
|
@ -18,8 +18,8 @@
|
||||||
#include "libc/fmt/fmt.h"
|
#include "libc/fmt/fmt.h"
|
||||||
#include "libc/mem/mem.h"
|
#include "libc/mem/mem.h"
|
||||||
#include "libc/str/str.h"
|
#include "libc/str/str.h"
|
||||||
|
#include "third_party/nsync/array.internal.h"
|
||||||
#include "third_party/nsync/dll.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/smprintf.h"
|
||||||
#include "third_party/nsync/testing/testing.h"
|
#include "third_party/nsync/testing/testing.h"
|
||||||
// clang-format off
|
// clang-format off
|
||||||
|
|
|
@ -17,11 +17,11 @@
|
||||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||||
#include "libc/fmt/fmt.h"
|
#include "libc/fmt/fmt.h"
|
||||||
#include "libc/str/str.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.h"
|
||||||
#include "third_party/nsync/mu_wait.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/closure.h"
|
||||||
#include "third_party/nsync/testing/heap.h"
|
|
||||||
#include "third_party/nsync/testing/smprintf.h"
|
#include "third_party/nsync/testing/smprintf.h"
|
||||||
#include "third_party/nsync/testing/testing.h"
|
#include "third_party/nsync/testing/testing.h"
|
||||||
#include "third_party/nsync/testing/time_extra.h"
|
#include "third_party/nsync/testing/time_extra.h"
|
||||||
|
|
12
third_party/nsync/testing/testing.mk
vendored
12
third_party/nsync/testing/testing.mk
vendored
|
@ -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_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_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_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_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_CHECKS_ = $(THIRD_PARTY_NSYNC_TESTING_SRCS_TEST:%.c=o/$(MODE)/%.com.runs)
|
||||||
|
|
||||||
THIRD_PARTY_NSYNC_TESTING_DIRECTDEPS = \
|
THIRD_PARTY_NSYNC_TESTING_DIRECTDEPS = \
|
||||||
LIBC_CALLS \
|
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
|
.PHONY: o/$(MODE)/third_party/nsync/testing
|
||||||
o/$(MODE)/third_party/nsync/testing: \
|
o/$(MODE)/third_party/nsync/testing: \
|
||||||
$(THIRD_PARTY_NSYNC_TESTING_CHECKS) \
|
$(THIRD_PARTY_NSYNC_TESTING_CHECKS_) \
|
||||||
$(THIRD_PARTY_NSYNC_TESTING_BINS)
|
$(THIRD_PARTY_NSYNC_TESTING_BINS_)
|
||||||
|
|
||||||
.PHONY: o/$(MODE)/third_party/nsync/test
|
.PHONY: o/$(MODE)/third_party/nsync/test
|
||||||
o/$(MODE)/third_party/nsync/test: \
|
o/$(MODE)/third_party/nsync/test: \
|
||||||
$(THIRD_PARTY_NSYNC_TESTING_CHECKS) \
|
$(THIRD_PARTY_NSYNC_TESTING_CHECKS_) \
|
||||||
$(THIRD_PARTY_NSYNC_TESTING_TESTS)
|
$(THIRD_PARTY_NSYNC_TESTING_TESTS_)
|
||||||
|
|
14
third_party/nsync/testing/time_extra.c
vendored
14
third_party/nsync/testing/time_extra.c
vendored
|
@ -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));
|
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) {
|
double nsync_time_to_dbl (nsync_time t) {
|
||||||
return (((double) NSYNC_TIME_SEC (t)) + ((double) NSYNC_TIME_NSEC (t) * 1e-9));
|
return (((double) NSYNC_TIME_SEC (t)) + ((double) NSYNC_TIME_NSEC (t) * 1e-9));
|
||||||
}
|
}
|
||||||
|
|
4
third_party/nsync/testing/time_extra.h
vendored
4
third_party/nsync/testing/time_extra.h
vendored
|
@ -6,10 +6,6 @@
|
||||||
"decimals" decimal places. */
|
"decimals" decimal places. */
|
||||||
char *nsync_time_str(nsync_time t, int decimals);
|
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. */
|
/* Return t as a double. */
|
||||||
double nsync_time_to_dbl(nsync_time t);
|
double nsync_time_to_dbl(nsync_time t);
|
||||||
|
|
||||||
|
|
2
third_party/nsync/testing/wait_test.c
vendored
2
third_party/nsync/testing/wait_test.c
vendored
|
@ -16,9 +16,9 @@
|
||||||
│ limitations under the License. │
|
│ limitations under the License. │
|
||||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||||
#include "libc/str/str.h"
|
#include "libc/str/str.h"
|
||||||
|
#include "third_party/nsync/array.internal.h"
|
||||||
#include "third_party/nsync/counter.h"
|
#include "third_party/nsync/counter.h"
|
||||||
#include "third_party/nsync/note.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/closure.h"
|
||||||
#include "third_party/nsync/testing/smprintf.h"
|
#include "third_party/nsync/testing/smprintf.h"
|
||||||
#include "third_party/nsync/testing/testing.h"
|
#include "third_party/nsync/testing/testing.h"
|
||||||
|
|
54
third_party/nsync/time.c
vendored
54
third_party/nsync/time.c
vendored
|
@ -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);
|
|
||||||
}
|
|
13
third_party/nsync/time.h
vendored
13
third_party/nsync/time.h
vendored
|
@ -17,17 +17,21 @@ COSMOPOLITAN_C_START_
|
||||||
typedef struct timespec nsync_time;
|
typedef struct timespec nsync_time;
|
||||||
|
|
||||||
/* A deadline infinitely far in the future. */
|
/* 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. */
|
/* 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. */
|
/* Return the current time since the epoch. */
|
||||||
#define nsync_time_now() _timespec_real()
|
#define nsync_time_now() _timespec_real()
|
||||||
|
|
||||||
/* Sleep for the specified delay. Returns the unslept time which may be
|
/* Sleep for the specified delay. Returns the unslept time which may be
|
||||||
non-zero if the call was interrupted. */
|
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 */
|
/* Return a+b */
|
||||||
#define nsync_time_add(a, b) _timespec_add(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. */
|
/* Return the specified number of microseconds as a time. */
|
||||||
#define nsync_time_us(a) _timespec_frommicros(a)
|
#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
|
/* Return an nsync_time constructed from second and nanosecond
|
||||||
components */
|
components */
|
||||||
#define nsync_time_s_ns(s, ns) ((nsync_time){(int64_t)(s), (unsigned)(ns)})
|
#define nsync_time_s_ns(s, ns) ((nsync_time){(int64_t)(s), (unsigned)(ns)})
|
||||||
|
|
Loading…
Reference in a new issue