mirror of
https://github.com/jart/cosmopolitan.git
synced 2025-02-07 06:53:33 +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 │
|
||||
│ 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/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);
|
||||
}
|
||||
|
|
|
@ -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));
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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 │
|
||||
│ 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;
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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_
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
|
|
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_
|
||||
#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_*/
|
8
third_party/nsync/compat.S
vendored
8
third_party/nsync/compat.S
vendored
|
@ -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
|
||||
|
|
145
third_party/nsync/futex.c
vendored
145
third_party/nsync/futex.c
vendored
|
@ -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;
|
||||
|
|
|
@ -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) {
|
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 -*-│
|
||||
│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
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/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"
|
||||
|
|
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/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
|
||||
|
|
|
@ -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"
|
||||
|
|
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_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_)
|
||||
|
|
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));
|
||||
}
|
||||
|
||||
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));
|
||||
}
|
||||
|
|
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. */
|
||||
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);
|
||||
|
||||
|
|
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. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#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"
|
||||
|
|
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;
|
||||
|
||||
/* 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)})
|
||||
|
|
Loading…
Reference in a new issue