Clean up some sleep code

This commit is contained in:
Justine Tunney 2022-10-08 02:40:44 -07:00
parent 9849b4c7ba
commit 672ccda37c
No known key found for this signature in database
GPG key ID: BE714B4575D6E328
35 changed files with 310 additions and 598 deletions

View 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;
}
}

View file

@ -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;
}

View file

@ -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);
}

View file

@ -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));

View file

@ -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

View file

@ -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;
}

View file

@ -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;
}
}
}

View file

@ -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;
}

View file

@ -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;
}

View file

@ -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;
}

View file

@ -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;

View file

@ -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_

View file

@ -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;
}

View file

@ -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

View file

@ -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

View file

@ -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;

View file

@ -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_*/

View file

@ -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

View file

@ -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;

View file

@ -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) {

View file

@ -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);
}

25
third_party/nsync/mu_semaphore.internal.h vendored Normal file → Executable file
View 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_ */

View file

@ -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);
}

View file

@ -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);
}

View file

@ -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"

View file

@ -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

View file

@ -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"

View file

@ -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_)

View file

@ -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));
}

View file

@ -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);

View file

@ -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"

View file

@ -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);
}

View file

@ -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)})