Make improvements

- More timspec_*() and timeval_*() APIs have been introduced.
- The copyfd() function is now simplified thanks to POSIX rules.
- More Cosmo-specific APIs have been moved behind the COSMO define.
- The setitimer() polyfill for Windows NT is now much higher quality.
- Fixed build error for MODE=aarch64 due to -mstringop-strategy=loop.
- This change introduces `make MODE=nox87 toolchain` which makes it
  possible to build programs using your cosmocc toolchain that don't
  have legacy fpu instructions. This is useful, for example, if you
  want to have a ~22kb tinier blink virtual machine.
This commit is contained in:
Justine Tunney 2023-06-15 13:50:42 -07:00
parent 8dc11afcf6
commit c3440d040c
No known key found for this signature in database
GPG key ID: BE714B4575D6E328
132 changed files with 539 additions and 587 deletions

View file

@ -33,7 +33,6 @@
#include "libc/sysv/consts/sig.h"
#include "libc/sysv/errfuns.h"
#include "libc/thread/tls.h"
#ifdef __x86_64__
/**

View file

@ -42,14 +42,6 @@
#define MAP_FAILED ((void *)-1)
#define ARCH_SET_GS 0x1001
#define ARCH_SET_FS 0x1002
#define ARCH_GET_FS 0x1003
#define ARCH_GET_GS 0x1004
#define MAP_HUGE_2MB (21 << MAP_HUGE_SHIFT)
#define MAP_HUGE_1GB (30 << MAP_HUGE_SHIFT)
#define WCOREDUMP(s) (128 & (s))
#define WEXITSTATUS(s) ((0xff00 & (s)) >> 8)
#define WIFCONTINUED(s) ((s) == 0xffff)
@ -69,11 +61,9 @@ COSMOPOLITAN_C_START_
typedef int sig_atomic_t;
bool32 isatty(int) nosideeffect;
char *commandv(const char *, char *, size_t);
char *get_current_dir_name(void) dontdiscard;
char *getcwd(char *, size_t);
char *realpath(const char *, char *);
char *replaceuser(const char *) dontdiscard;
char *ttyname(int);
int access(const char *, int) dontthrow;
int chdir(const char *);
@ -122,7 +112,6 @@ int getpriority(int, unsigned);
int getresgid(unsigned *, unsigned *, unsigned *);
int getresuid(unsigned *, unsigned *, unsigned *);
int getsid(int) nosideeffect libcesque;
int gettid(void) libcesque;
int ioprio_get(int, int);
int ioprio_set(int, int, int);
int issetugid(void);
@ -133,8 +122,6 @@ int lchown(const char *, unsigned, unsigned);
int link(const char *, const char *) dontthrow;
int linkat(int, const char *, int, const char *, int);
int madvise(void *, uint64_t, int);
int makedirs(const char *, unsigned);
int memfd_create(const char *, unsigned int);
int mincore(void *, size_t, unsigned char *);
int mkdir(const char *, unsigned);
int mkdirat(int, const char *, unsigned);
@ -146,14 +133,10 @@ int nice(int);
int open(const char *, int, ...);
int openat(int, const char *, int, ...);
int pause(void);
int personality(uint64_t);
int pipe(int[hasatleast 2]);
int pipe2(int[hasatleast 2], int);
int pivot_root(const char *, const char *);
int pledge(const char *, const char *);
int posix_fadvise(int, int64_t, int64_t, int);
int posix_madvise(void *, uint64_t, int);
int prctl(int, ...);
int raise(int);
int reboot(int);
int remove(const char *);
@ -161,7 +144,6 @@ int rename(const char *, const char *);
int renameat(int, const char *, int, const char *);
int rmdir(const char *);
int sched_yield(void);
int seccomp(unsigned, unsigned, void *);
int setegid(unsigned);
int seteuid(unsigned);
int setfsgid(unsigned);
@ -182,37 +164,21 @@ int siginterrupt(int, int);
int symlink(const char *, const char *);
int symlinkat(const char *, int, const char *);
int sync_file_range(int, int64_t, int64_t, unsigned);
int sys_iopl(int);
int sys_mlock(const void *, size_t);
int sys_mlock2(const void *, size_t, int);
int sys_mlockall(int);
int sys_munlock(const void *, size_t);
int sys_munlockall(void);
int sys_ptrace(int, ...);
int sys_sysctl(const int *, unsigned, void *, size_t *, void *, size_t);
int tcgetpgrp(int);
int tcsetpgrp(int, int);
int tgkill(int, int, int);
int tkill(int, int);
int tmpfd(void);
int touch(const char *, unsigned);
int truncate(const char *, int64_t);
int ttyname_r(int, char *, size_t);
int unlink(const char *);
int unlink_s(const char **);
int unlinkat(int, const char *, int);
int unveil(const char *, const char *);
int usleep(unsigned);
int vfork(void) returnstwice;
int wait(int *);
int waitpid(int, int *, int);
long ptrace(int, ...);
ssize_t copy_file_range(int, long *, int, long *, size_t, unsigned);
ssize_t lseek(int, int64_t, int);
ssize_t pread(int, void *, size_t, int64_t);
ssize_t pwrite(int, const void *, size_t, int64_t);
ssize_t read(int, void *, size_t);
ssize_t readansi(int, char *, size_t);
ssize_t readlink(const char *, char *, size_t);
ssize_t readlinkat(int, const char *, char *, size_t);
ssize_t splice(int, int64_t *, int, int64_t *, size_t, unsigned);
@ -225,20 +191,38 @@ unsigned umask(unsigned);
void sync(void);
#ifdef COSMO
#define fileexists __fileexists
#define isdirectory __isdirectory
#define isexecutable __isexecutable
#define isregularfile __isregularfile
#define issymlink __issymlink
#define ischardev __ischardev
#define copyfd __copyfd
bool fileexists(const char *);
bool isdirectory(const char *);
bool isexecutable(const char *);
bool isregularfile(const char *);
bool issymlink(const char *);
bool32 ischardev(int) nosideeffect;
ssize_t copyfd(int, int64_t *, int, int64_t *, size_t, unsigned);
bool32 ischardev(int);
char *commandv(const char *, char *, size_t);
char *replaceuser(const char *) dontdiscard;
int gettid(void) libcesque;
int makedirs(const char *, unsigned);
int memfd_create(const char *, unsigned int);
int personality(uint64_t);
int pivot_root(const char *, const char *);
int pledge(const char *, const char *);
int prctl(int, ...);
int seccomp(unsigned, unsigned, void *);
int sys_iopl(int);
int sys_mlock(const void *, size_t);
int sys_mlock2(const void *, size_t, int);
int sys_mlockall(int);
int sys_munlock(const void *, size_t);
int sys_munlockall(void);
int sys_ptrace(int, ...);
int sys_sysctl(const int *, unsigned, void *, size_t *, void *, size_t);
int tgkill(int, int, int);
int tkill(int, int);
int tmpfd(void);
int touch(const char *, unsigned);
int unveil(const char *, const char *);
long ptrace(int, ...);
ssize_t copyfd(int, int, size_t);
ssize_t readansi(int, char *, size_t);
#endif
COSMOPOLITAN_C_END_

View file

@ -103,6 +103,7 @@ o/$(MODE)/libc/calls/ntcontext2linux.o: private \
COPTS += \
-fno-sanitize=all
ifneq ($(ARCH), aarch64)
# we always want -O3 because:
# it makes the code size smaller too
# we need -mstringop-strategy=loop because:
@ -116,6 +117,7 @@ o/$(MODE)/libc/calls/ntcontext2linux.o: private \
COPTS += \
-O3 \
-mstringop-strategy=loop
endif
# we must disable static stack safety because:
# these functions use alloca(n)

View file

@ -42,7 +42,6 @@
* time. Among the more popular is CLOCK_MONOTONIC. This function has a
* zero syscall implementation of that on modern x86.
*
* nowl l: 45𝑐 15𝑛𝑠
* rdtsc l: 13𝑐 4𝑛𝑠
* gettimeofday l: 44𝑐 14𝑛𝑠
* clock_gettime l: 40𝑐 13𝑛𝑠

50
libc/calls/copy.c Normal file
View file

@ -0,0 +1,50 @@
/*-*- 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/calls/calls.h"
#include "libc/macros.internal.h"
/**
* Copies data between file descriptors the old fashioned way.
*
* This function is intended for simple programs without signals. If
* signals are in play, then `SA_RESTART` needs to be used.
*
* @param in is input file descriptor
* @param out is input file descriptor
* @param n is number of bytes to exchange, or -1 for until eof
* @return bytes successfully exchanged, or -1 w/ errno
*/
ssize_t copyfd(int in, int out, size_t n) {
size_t i;
char buf[512];
ssize_t dr, dw;
for (i = 0; i < n; i += dr) {
dr = read(in, buf, MIN(n - i, sizeof(buf)));
if (dr == -1) return -1;
if (!dr) break;
dw = write(out, buf, dr);
if (dw == -1) return -1;
if (dw != dr) {
// POSIX requires atomic IO up to PIPE_BUF
// The minimum permissible PIPE_BUF is 512
__builtin_trap();
}
}
return i;
}

View file

@ -17,10 +17,10 @@
PERFORMANCE OF THIS SOFTWARE.
*/
#include "libc/calls/asan.internal.h"
#include "libc/calls/struct/itimerval.internal.h"
#include "libc/calls/struct/timespec.h"
#include "libc/calls/struct/timespec.internal.h"
#include "libc/calls/struct/timeval.h"
#include "libc/calls/struct/timeval.internal.h"
#include "libc/dce.h"
#include "libc/intrin/strace.internal.h"
#include "libc/sysv/errfuns.h"

View file

@ -21,6 +21,7 @@
#include "libc/calls/struct/itimerval.internal.h"
#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"
@ -41,12 +42,7 @@ int getitimer(int which, struct itimerval *curvalue) {
} else {
rc = sys_setitimer_nt(which, 0, curvalue);
}
if (curvalue) {
STRACE("getitimer(%d, [{{%'ld, %'ld}, {%'ld, %'ld}}]) → %d% m", which,
curvalue->it_interval.tv_sec, curvalue->it_interval.tv_usec,
curvalue->it_value.tv_sec, curvalue->it_value.tv_usec, rc);
} else {
STRACE("getitimer(%d, 0) → %d% m", which, rc);
}
STRACE("getitimer(%s, [%s]) → %d% m", DescribeItimer(which),
DescribeItimerval(rc, curvalue), rc);
return rc;
}

View file

@ -38,13 +38,13 @@ static gettimeofday_f *__gettimeofday = __gettimeofday_init;
* Returns system wall time in microseconds, e.g.
*
* int64_t t;
* char p[30];
* char p[20];
* struct tm tm;
* struct timeval tv;
* gettimeofday(&tv, 0);
* t = tv.tv_sec;
* gmtime_r(&t, &tm);
* FormatHttpDateTime(p, &tm);
* iso8601(p, &tm);
* printf("%s\n", p);
*
* @param tv points to timeval that receives result if non-NULL

View file

@ -16,120 +16,49 @@
TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE.
*/
#include "libc/assert.h"
#include "libc/calls/calls.h"
#include "libc/calls/sig.internal.h"
#include "libc/calls/struct/itimerval.h"
#include "libc/calls/struct/siginfo.h"
#include "libc/dce.h"
#include "libc/errno.h"
#include "libc/fmt/conv.h"
#include "libc/intrin/bits.h"
#include "libc/intrin/strace.internal.h"
#include "libc/log/check.h"
#include "libc/math.h"
#include "libc/nexgen32e/nexgen32e.h"
#include "libc/nexgen32e/nt2sysv.h"
#include "libc/nt/files.h"
#include "libc/nt/runtime.h"
#include "libc/nt/synchronization.h"
#include "libc/nt/thread.h"
#include "libc/str/str.h"
#include "libc/calls/struct/timeval.h"
#include "libc/sysv/consts/itimer.h"
#include "libc/sysv/consts/sicode.h"
#include "libc/sysv/consts/sig.h"
#include "libc/sysv/errfuns.h"
#include "libc/time/time.h"
#ifdef __x86_64__
/**
* @fileoverview Heartbreaking polyfill for SIGALRM on NT.
*
* Threads are used to trigger the SIGALRM handler, which should
* hopefully be an unfancy function like this:
*
* void OnAlarm(int sig, struct siginfo *si, struct ucontext *uc) {
* g_alarmed = true;
* }
*
* This is needed because WIN32 provides no obvious solutions for
* interrupting i/o operations on the standard input handle.
*/
static bool __hastimer;
static bool __singleshot;
static long double __lastalrm;
static long double __interval;
static struct itimerval g_setitimer;
textwindows void _check_sigalrm(void) {
// TODO(jart): use a different timing source
// TODO(jart): synchronize across intervals?
long double now, elapsed;
if (!__hastimer) return;
now = nowl();
elapsed = now - __lastalrm;
if (elapsed > __interval) {
__sig_add(0, SIGALRM, SI_TIMER);
if (__singleshot) {
__hastimer = false;
} else {
__lastalrm = now;
}
struct timeval now;
if (timeval_iszero(g_setitimer.it_value)) return;
now = timeval_real();
if (timeval_cmp(now, g_setitimer.it_value) < 0) return;
if (timeval_iszero(g_setitimer.it_interval)) {
g_setitimer.it_value = timeval_zero;
} else {
do {
g_setitimer.it_value =
timeval_add(g_setitimer.it_value, g_setitimer.it_interval);
} while (timeval_cmp(now, g_setitimer.it_value) > 0);
}
__sig_add(0, SIGALRM, SI_TIMER);
}
textwindows int sys_setitimer_nt(int which, const struct itimerval *newvalue,
struct itimerval *out_opt_oldvalue) {
long double elapsed, untilnext;
if (which != ITIMER_REAL ||
(newvalue && (!(0 <= newvalue->it_value.tv_usec &&
newvalue->it_value.tv_usec < 1000000) ||
!(0 <= newvalue->it_interval.tv_usec &&
newvalue->it_interval.tv_usec < 1000000)))) {
textwindows int sys_setitimer_nt(int which, const struct itimerval *neu,
struct itimerval *old) {
if (which != ITIMER_REAL || (neu && (!timeval_isvalid(neu->it_value) ||
!timeval_isvalid(neu->it_interval)))) {
return einval();
}
if (out_opt_oldvalue) {
if (__hastimer) {
elapsed = nowl() - __lastalrm;
if (elapsed > __interval) {
untilnext = 0;
} else {
untilnext = __interval - elapsed;
}
out_opt_oldvalue->it_interval.tv_sec = __interval;
out_opt_oldvalue->it_interval.tv_usec = 1 / 1e6 * fmodl(__interval, 1);
out_opt_oldvalue->it_value.tv_sec = untilnext;
out_opt_oldvalue->it_value.tv_usec = 1 / 1e6 * fmodl(untilnext, 1);
} else {
out_opt_oldvalue->it_interval.tv_sec = 0;
out_opt_oldvalue->it_interval.tv_usec = 0;
out_opt_oldvalue->it_value.tv_sec = 0;
out_opt_oldvalue->it_value.tv_usec = 0;
}
if (old) {
old->it_interval = g_setitimer.it_interval;
old->it_value = timeval_subz(g_setitimer.it_value, timeval_real());
}
if (newvalue) {
if (newvalue->it_interval.tv_sec || newvalue->it_interval.tv_usec ||
newvalue->it_value.tv_sec || newvalue->it_value.tv_usec) {
__hastimer = true;
if (newvalue->it_interval.tv_sec || newvalue->it_interval.tv_usec) {
__singleshot = false;
__interval = newvalue->it_interval.tv_sec +
1 / 1e6 * newvalue->it_interval.tv_usec;
} else {
__singleshot = true;
__interval =
newvalue->it_value.tv_sec + 1 / 1e6 * newvalue->it_value.tv_usec;
}
__lastalrm = nowl();
} else {
__hastimer = false;
}
if (neu) {
g_setitimer.it_interval = neu->it_interval;
g_setitimer.it_value = timeval_iszero(neu->it_value)
? timeval_zero
: timeval_add(timeval_real(), neu->it_value);
}
return 0;
}

View file

@ -20,6 +20,7 @@
#include "libc/calls/struct/itimerval.internal.h"
#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/time/time.h"
@ -66,7 +67,6 @@
int setitimer(int which, const struct itimerval *newvalue,
struct itimerval *oldvalue) {
int rc;
if (IsAsan() &&
((newvalue && !__asan_is_valid(newvalue, sizeof(*newvalue))) ||
(oldvalue && !__asan_is_valid(oldvalue, sizeof(*oldvalue))))) {
@ -80,28 +80,7 @@ int setitimer(int which, const struct itimerval *newvalue,
} else {
rc = sys_setitimer_nt(which, newvalue, oldvalue);
}
#ifdef SYSDEBUG
if (newvalue && oldvalue) {
STRACE("setitimer(%d, "
"{{%'ld, %'ld}, {%'ld, %'ld}}, "
"[{{%'ld, %'ld}, {%'ld, %'ld}}]) → %d% m",
which, newvalue->it_interval.tv_sec, newvalue->it_interval.tv_usec,
newvalue->it_value.tv_sec, newvalue->it_value.tv_usec,
oldvalue->it_interval.tv_sec, oldvalue->it_interval.tv_usec,
oldvalue->it_value.tv_sec, oldvalue->it_value.tv_usec, rc);
} else if (newvalue) {
STRACE("setitimer(%d, {{%'ld, %'ld}, {%'ld, %'ld}}, NULL) → %d% m", which,
newvalue->it_interval.tv_sec, newvalue->it_interval.tv_usec,
newvalue->it_value.tv_sec, newvalue->it_value.tv_usec, rc);
} else if (oldvalue) {
STRACE("setitimer(%d, NULL, [{{%'ld, %'ld}, {%'ld, %'ld}}]) → %d% m", which,
oldvalue->it_interval.tv_sec, oldvalue->it_interval.tv_usec,
oldvalue->it_value.tv_sec, oldvalue->it_value.tv_usec, rc);
} else {
STRACE("setitimer(%d, NULL, NULL) → %d% m", which, rc);
}
#endif
STRACE("setitimer(%s, %s, [%s]) → %d% m", DescribeItimer(which),
DescribeItimerval(0, newvalue), DescribeItimerval(rc, oldvalue), rc);
return rc;
}

View file

@ -9,8 +9,8 @@ int sys_getitimer(int, struct itimerval *) _Hide;
int sys_setitimer(int, const struct itimerval *, struct itimerval *) _Hide;
int sys_setitimer_nt(int, const struct itimerval *, struct itimerval *) _Hide;
const char *DescribeTimeval(char[45], int, const struct timeval *);
#define DescribeTimeval(rc, ts) DescribeTimeval(alloca(45), rc, ts)
const char *DescribeItimerval(char[90], int, const struct itimerval *);
#define DescribeItimerval(rc, ts) DescribeItimerval(alloca(90), rc, ts)
COSMOPOLITAN_C_END_
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */

View file

@ -14,14 +14,14 @@ int clock_nanosleep(int, int, const struct timespec *, struct timespec *);
int futimens(int, const struct timespec[2]);
int nanosleep(const struct timespec *, struct timespec *);
int utimensat(int, const char *, const struct timespec[2], int);
int timespec_getres(struct timespec *, int);
int timespec_get(struct timespec *, int);
#ifdef COSMO
/* cosmopolitan libc's non-posix timespec library
removed by default due to emacs codebase clash */
#define timespec_zero ((struct timespec){0})
#define timespec_max ((struct timespec){0x7fffffffffffffff, 999999999})
int timespec_get(struct timespec *, int);
int timespec_getres(struct timespec *, int);
int timespec_cmp(struct timespec, struct timespec) pureconst;
int64_t timespec_tomicros(struct timespec) pureconst;
int64_t timespec_tomillis(struct timespec) pureconst;
@ -35,7 +35,14 @@ struct timespec timespec_mono(void);
struct timespec timespec_sleep(struct timespec);
int timespec_sleep_until(struct timespec);
struct timespec timespec_sub(struct timespec, struct timespec) pureconst;
struct timespec timespec_subz(struct timespec, struct timespec) pureconst;
int sys_futex(int *, int, int, const struct timespec *, int *);
static inline bool timespec_iszero(struct timespec __ts) {
return !(__ts.tv_sec | __ts.tv_nsec);
}
static inline bool timespec_isvalid(struct timespec __ts) {
return __ts.tv_sec >= 0 && __ts.tv_nsec < 1000000000ull;
}
#endif /* COSMO */
COSMOPOLITAN_C_END_

View file

@ -19,13 +19,23 @@ int utimes(const char *, const struct timeval[2]);
#ifdef COSMO
/* cosmopolitan libc's non-posix timevals library
removed by default due to emacs codebase clash */
#define timeval_zero ((struct timeval){0})
#define timeval_max ((struct timeval){0x7fffffffffffffff, 999999})
int timeval_cmp(struct timeval, struct timeval) pureconst;
struct timeval timeval_real(void);
struct timeval timeval_frommicros(int64_t) pureconst;
struct timeval timeval_frommillis(int64_t) pureconst;
struct timeval timeval_add(struct timeval, struct timeval) pureconst;
struct timeval timeval_sub(struct timeval, struct timeval) pureconst;
struct timeval timeval_subz(struct timeval, struct timeval) pureconst;
struct timeval timespec_totimeval(struct timespec) pureconst;
struct timespec timeval_totimespec(struct timeval) pureconst;
static inline bool timeval_iszero(struct timeval __tv) {
return !(__tv.tv_sec | __tv.tv_usec);
}
static inline bool timeval_isvalid(struct timeval __tv) {
return __tv.tv_sec >= 0 && __tv.tv_usec < 1000000ull;
}
#endif /* COSMO */
COSMOPOLITAN_C_END_

View file

@ -1,6 +1,7 @@
#ifndef COSMOPOLITAN_LIBC_CALLS_STRUCT_TIMEVAL_INTERNAL_H_
#define COSMOPOLITAN_LIBC_CALLS_STRUCT_TIMEVAL_INTERNAL_H_
#include "libc/calls/struct/timeval.h"
#include "libc/mem/alloca.h"
#include "libc/time/struct/timezone.h"
#if !(__ASSEMBLER__ + __LINKER__ + 0)
COSMOPOLITAN_C_START_
@ -15,6 +16,9 @@ axdx_t sys_gettimeofday_nt(struct timeval *, struct timezone *, void *) _Hide;
int sys_utimes_nt(const char *, const struct timeval[2]) _Hide;
axdx_t sys_gettimeofday_metal(struct timeval *, struct timezone *, void *);
const char *DescribeTimeval(char[45], int, const struct timeval *);
#define DescribeTimeval(rc, ts) DescribeTimeval(alloca(45), rc, ts)
COSMOPOLITAN_C_END_
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
#endif /* COSMOPOLITAN_LIBC_CALLS_STRUCT_TIMEVAL_INTERNAL_H_ */

View file

@ -1,7 +1,7 @@
/*-*- mode:unix-assembly; indent-tabs-mode:t; tab-width:8; coding:utf-8 -*-│
vi: set et ft=asm ts=8 sw=8 fenc=utf-8 :vi
/*-*- 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 2020 Justine Alexandra Roberts Tunney
Copyright 2023 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
@ -16,30 +16,17 @@
TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE.
*/
#include "libc/runtime/pc.internal.h"
#include "libc/macros.internal.h"
#include "libc/calls/struct/timespec.h"
// fmod [sic] does (𝑥 rem 𝑦) w/ round()-style rounding.
//
// @param 𝑥 is an 80-bit long double passed on stack in 16-bytes
// @param 𝑦 is the power, also pushed on stack, in reverse order
// @return remainder ∈ (-|𝑦|,|𝑦|) in %st
// @define 𝑥-truncl(𝑥/𝑦)*𝑦
// @see emod()
.ftrace1
fmodl: .ftrace2
push %rbp
mov %rsp,%rbp
fldt 32(%rbp)
fldt 16(%rbp)
1: fprem
fnstsw
test $FPU_C2>>8,%ah
jnz 1b
fstp %st(1)
pop %rbp
ret
1: int3
pop %rbp
ret
.endfn fmodl,globl
/**
* Subtracts two nanosecond timestamps.
*
* Unlike `timespec_sub()` this function will return zero if `x < y`.
*/
struct timespec timespec_subz(struct timespec x, struct timespec y) {
if (timespec_cmp(x, y) > 0) {
return timespec_sub(x, y);
} else {
return timespec_zero;
}
}

31
libc/calls/timeval_real.c Normal file
View file

@ -0,0 +1,31 @@
/*-*- 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 2023 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/timeval.h"
/**
* Returns current time w/ microsecond precision.
*
* @see timespec_real()
*/
struct timeval timeval_real(void) {
struct timeval tv;
_npassert(!gettimeofday(&tv, 0));
return tv;
}

30
libc/calls/timeval_subz.c Normal file
View file

@ -0,0 +1,30 @@
/*-*- 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/calls/struct/timeval.h"
/**
* Subtracts two nanosecond timestamps.
*/
struct timeval timeval_subz(struct timeval x, struct timeval y) {
if (timeval_cmp(x, y) > 0) {
return timeval_sub(x, y);
} else {
return timeval_zero;
}
}

View file

@ -16,10 +16,10 @@
TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE.
*/
#include "libc/calls/struct/itimerval.internal.h"
#include "libc/calls/struct/timespec.h"
#include "libc/calls/struct/timespec.internal.h"
#include "libc/calls/struct/timeval.h"
#include "libc/calls/struct/timeval.internal.h"
#include "libc/intrin/strace.internal.h"
#include "libc/sysv/consts/at.h"