mirror of
https://github.com/jart/cosmopolitan.git
synced 2025-06-28 07:18:30 +00:00
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:
parent
8dc11afcf6
commit
c3440d040c
132 changed files with 539 additions and 587 deletions
|
@ -33,7 +33,6 @@
|
|||
#include "libc/sysv/consts/sig.h"
|
||||
#include "libc/sysv/errfuns.h"
|
||||
#include "libc/thread/tls.h"
|
||||
|
||||
#ifdef __x86_64__
|
||||
|
||||
/**
|
||||
|
|
|
@ -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_
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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
50
libc/calls/copy.c
Normal 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;
|
||||
}
|
|
@ -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"
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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) */
|
||||
|
|
|
@ -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_
|
||||
|
|
|
@ -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_
|
||||
|
|
|
@ -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_ */
|
||||
|
|
|
@ -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
31
libc/calls/timeval_real.c
Normal 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
30
libc/calls/timeval_subz.c
Normal 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;
|
||||
}
|
||||
}
|
|
@ -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"
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue