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;