Improve redbean

- Improve serialization
- Add Benchmark() API to redbean
- Refactor UNIX API to be assert() friendly
- Make the redbean Lua REPL print data structures
- Fix recent regressions in linenoise reverse search
- Add -i flag so redbean can be a language interpreter
This commit is contained in:
Justine Tunney 2022-04-25 08:30:14 -07:00
parent 2046c0d2ae
commit 451e3f73d9
74 changed files with 1781 additions and 1024 deletions

View file

@ -119,6 +119,9 @@ int fsync(int);
int ftruncate(int, int64_t);
int getdents(unsigned, void *, unsigned, long *);
int getdomainname(char *, size_t);
int getegid(void) nosideeffect;
int geteuid(void) nosideeffect;
int getgid(void) nosideeffect;
int gethostname(char *, size_t);
int getloadavg(double *, int);
int getpgid(int);
@ -130,6 +133,7 @@ int getrlimit(int, struct rlimit *);
int getrusage(int, struct rusage *);
int getsid(int) nosideeffect;
int gettid(void);
int getuid(void) nosideeffect;
int kill(int, int);
int killpg(int, int);
int link(const char *, const char *) dontthrow;
@ -196,6 +200,7 @@ int sysinfo(struct sysinfo *);
int touch(const char *, uint32_t);
int truncate(const char *, uint64_t);
int ttyname_r(int, char *, size_t);
int umask(int);
int uname(struct utsname *);
int unlink(const char *);
int unlink_s(const char **);
@ -226,11 +231,6 @@ ssize_t splice(int, int64_t *, int, int64_t *, size_t, uint32_t);
ssize_t vmsplice(int, const struct iovec *, int64_t, uint32_t);
ssize_t write(int, const void *, size_t);
struct dirent *readdir(DIR *);
uint32_t getegid(void) nosideeffect;
uint32_t geteuid(void) nosideeffect;
uint32_t getgid(void) nosideeffect;
uint32_t getuid(void) nosideeffect;
uint32_t umask(uint32_t);
void rewinddir(DIR *);
void sync(void);

View file

@ -111,6 +111,7 @@ o/$(MODE)/libc/calls/execlp.o \
o/$(MODE)/libc/calls/execve-nt.o \
o/$(MODE)/libc/calls/execve-sysv.o \
o/$(MODE)/libc/calls/readlinkat-nt.o \
o/$(MODE)/libc/calls/describeopenflags.greg.o \
o/$(MODE)/libc/calls/mkntenvblock.o: \
OVERRIDE_CPPFLAGS += \
-DSTACK_FRAME_UNLIMITED

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/fmt/itoa.h"
#include "libc/fmt/magnumstrs.internal.h"
#include "libc/str/str.h"
#include "libc/sysv/consts/sol.h"
/**
* Describes clock_gettime() clock argument.
*/
char *DescribeClockName(int x) {
int i;
char *s;
_Alignas(char) static char buf[32];
if ((s = GetMagnumStr(kClockNames, x))) {
stpcpy(stpcpy(buf, "CLOCK_"), s);
return buf;
} else {
FormatInt32(buf, x);
return buf;
}
}

View file

@ -0,0 +1,41 @@
/*-*- 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/fmt/itoa.h"
#include "libc/fmt/magnumstrs.internal.h"
#include "libc/intrin/describeflags.internal.h"
#include "libc/mem/alloca.h"
#include "libc/sysv/consts/sol.h"
/**
* Describes clock_gettime() clock argument.
*/
char *DescribeOpenFlags(int x) {
char *s;
int i, n;
struct DescribeFlags *d;
_Alignas(char) static char openflags[128];
// TODO(jart): unify DescribeFlags and MagnumStr data structures
for (n = 0; kOpenFlags[n].x != MAGNUM_TERMINATOR;) ++n;
d = alloca(n * sizeof(struct DescribeFlags));
for (i = 0; i < n; ++i) {
d[i].flag = MAGNUM_NUMBER(kOpenFlags, i);
d[i].name = MAGNUM_STRING(kOpenFlags, i);
}
return DescribeFlags(openflags, sizeof(openflags), d, n, "O_", x);
}

View file

@ -28,6 +28,7 @@
*/
int32_t sys_fstatat(int32_t dirfd, const char *path, struct stat *st,
int32_t flags) {
int rc;
void *p;
union metastat ms;
if (IsAsan() && !__asan_is_valid(path, 1)) return efault();

View file

@ -25,7 +25,7 @@
* Returns effective group ID of calling process.
* @return group id
*/
uint32_t getegid(void) {
int getegid(void) {
int rc;
if (!IsWindows()) {
rc = sys_getegid();

View file

@ -24,7 +24,7 @@
* Returns effective user ID of calling process.
* @return user id
*/
uint32_t geteuid(void) {
int geteuid(void) {
int rc;
if (!IsWindows()) {
rc = sys_geteuid();

View file

@ -51,7 +51,7 @@ static textwindows dontinline uint32_t GetUserNameHash(void) {
* @asyncsignalsafe
* @vforksafe
*/
uint32_t getuid(void) {
int getuid(void) {
int rc;
if (!IsWindows()) {
rc = sys_getuid();
@ -71,7 +71,7 @@ uint32_t getuid(void) {
* @asyncsignalsafe
* @vforksafe
*/
uint32_t getgid(void) {
int getgid(void) {
int rc;
if (!IsWindows()) {
rc = sys_getgid();

47
libc/calls/kclocknames.S Normal file
View file

@ -0,0 +1,47 @@
/*-*- mode:unix-assembly; indent-tabs-mode:t; tab-width:8; coding:utf-8 -*-│
vi: set et ft=asm ts=8 tw=8 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/fmt/magnumstrs.internal.h"
#include "libc/macros.internal.h"
.macro .e e s
.long \e - kClockNames
.long 1f - kClockNames
.rodata.str1.1
1: .string "\s"
.previous
.endm
.section .rodata
.align 4
.underrun
kClockNames:
.e CLOCK_REALTIME,"REALTIME"
.e CLOCK_MONOTONIC,"MONOTONIC"
.e CLOCK_MONOTONIC_RAW,"MONOTONIC_RAW"
.e CLOCK_REALTIME_COARSE,"REALTIME_COARSE"
.e CLOCK_MONOTONIC_COARSE,"MONOTONIC_COARSE"
.e CLOCK_PROCESS_CPUTIME_ID,"PROCESS_CPUTIME_ID"
.e CLOCK_TAI,"TAI"
.e CLOCK_PROF,"PROF"
.e CLOCK_BOOTTIME,"BOOTTIME"
.e CLOCK_REALTIME_ALARM,"REALTIME_ALARM"
.e CLOCK_BOOTTIME_ALARM,"BOOTTIME_ALARM"
.long MAGNUM_TERMINATOR
.endobj kClockNames,globl,hidden
.overrun

64
libc/calls/kopenflags.S Normal file
View file

@ -0,0 +1,64 @@
/*-*- mode:unix-assembly; indent-tabs-mode:t; tab-width:8; coding:utf-8 -*-│
vi: set et ft=asm ts=8 tw=8 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/fmt/magnumstrs.internal.h"
#include "libc/macros.internal.h"
.macro .e e s
.long \e - kOpenFlags
.long 1f - kOpenFlags
.rodata.str1.1
1: .string "\s"
.previous
.endm
.section .rodata
.align 4
.underrun
kOpenFlags:
.e O_RDWR,"RDWR" // order matters
.e O_RDONLY,"RDONLY" //
.e O_WRONLY,"WRONLY" //
.e O_ACCMODE,"ACCMODE" // mask of prev three
.e O_CREAT,"CREAT" //
.e O_EXCL,"EXCL" //
.e O_TRUNC,"TRUNC" //
.e O_CLOEXEC,"CLOEXEC" //
.e O_DIRECT,"DIRECT" // no-op on xnu/openbsd
.e O_APPEND,"APPEND" // weird on nt
.e O_TMPFILE,"TMPFILE" // linux, windows
.e O_NOFOLLOW,"NOFOLLOW" // unix
.e O_SYNC,"SYNC" // unix
.e O_ASYNC,"ASYNC" // unix
.e O_NOCTTY,"NOCTTY" // unix
.e O_NOATIME,"NOATIME" // linux
.e O_EXEC,"EXEC" // free/openbsd
.e O_SEARCH,"SEARCH" // free/netbsd
.e O_DSYNC,"DSYNC" // linux/xnu/open/netbsd
.e O_RSYNC,"RSYNC" // linux/open/netbsd
.e O_PATH,"PATH" // linux
.e O_VERIFY,"VERIFY" // freebsd
.e O_SHLOCK,"SHLOCK" // bsd
.e O_EXLOCK,"EXLOCK" // bsd
.e O_RANDOM,"RANDOM" // windows
.e O_SEQUENTIAL,"SEQUENTIAL" // windows
.e O_COMPRESSED,"COMPRESSED" // windows
.e O_INDEXED,"INDEXED" // windows
.long MAGNUM_TERMINATOR
.endobj kOpenFlags,globl,hidden
.overrun

View file

@ -21,6 +21,7 @@
#include "libc/calls/internal.h"
#include "libc/calls/strace.internal.h"
#include "libc/dce.h"
#include "libc/fmt/magnumstrs.internal.h"
#include "libc/intrin/asan.internal.h"
#include "libc/log/log.h"
#include "libc/str/str.h"
@ -74,7 +75,8 @@ int openat(int dirfd, const char *file, int flags, ...) {
} else {
rc = efault();
}
STRACE("openat(%s, %#s, %#x, %#o) → %d% m", __strace_dirfd(buf, dirfd), file,
flags, (flags & (O_CREAT | O_TMPFILE)) ? mode : 0, rc);
STRACE("openat(%s, %#s, %s, %#o) → %d% m", __strace_dirfd(buf, dirfd), file,
DescribeOpenFlags(flags), (flags & (O_CREAT | O_TMPFILE)) ? mode : 0,
rc);
return rc;
}

View file

@ -27,8 +27,8 @@
* @return previous mask
* @note always succeeds
*/
unsigned umask(unsigned newmask) {
unsigned oldmask;
int umask(int newmask) {
int oldmask;
if (!IsWindows()) {
oldmask = sys_umask(newmask);
} else {

View file

@ -16,6 +16,7 @@
TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE.
*/
#include "libc/fmt/magnumstrs.internal.h"
#include "libc/macros.internal.h"
.macro .e e s
@ -115,6 +116,6 @@ kErrnoDocs:
.e ENOTRECOVERABLE,"State not recoverable"
.e ENONET,"Machine is not on the network"
.e ERESTART,"Interrupted system call should be restarted"
.long -123
.long MAGNUM_TERMINATOR
.endobj kErrnoDocs,globl,hidden
.overrun

View file

@ -16,6 +16,7 @@
TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE.
*/
#include "libc/fmt/magnumstrs.internal.h"
#include "libc/macros.internal.h"
.macro .e e
@ -27,7 +28,7 @@
.endm
.section .rodata
.align 4
.align 4
.underrun
kErrnoNames:
.e EINVAL
@ -116,6 +117,6 @@ kErrnoNames:
.e ENONET
.e ERESTART
.e ENODATA
.long -123
.long MAGNUM_TERMINATOR
.endobj kErrnoNames,globl,hidden
.overrun

View file

@ -1,22 +1,35 @@
#ifndef COSMOPOLITAN_LIBC_FMT_MAGNUMSTRS_H_
#define COSMOPOLITAN_LIBC_FMT_MAGNUMSTRS_H_
#define MAGNUM_TERMINATOR -123
#if !(__ASSEMBLER__ + __LINKER__ + 0)
COSMOPOLITAN_C_START_
#define MAGNUM_NUMBER(TABLE, INDEX) \
*(const int *)((uintptr_t)TABLE + TABLE[INDEX].x)
#define MAGNUM_STRING(TABLE, INDEX) \
(const char *)((uintptr_t)TABLE + TABLE[INDEX].s)
struct MagnumStr {
int x, s;
};
extern const struct MagnumStr kErrnoDocs[];
extern const struct MagnumStr kErrnoNames[];
extern const struct MagnumStr kIpOptnames[];
extern const struct MagnumStr kSignalNames[];
extern const struct MagnumStr kSockOptnames[];
extern const struct MagnumStr kTcpOptnames[];
hidden extern const struct MagnumStr kClockNames[];
hidden extern const struct MagnumStr kErrnoDocs[];
hidden extern const struct MagnumStr kErrnoNames[];
hidden extern const struct MagnumStr kIpOptnames[];
hidden extern const struct MagnumStr kOpenFlags[];
hidden extern const struct MagnumStr kSignalNames[];
hidden extern const struct MagnumStr kSockOptnames[];
hidden extern const struct MagnumStr kTcpOptnames[];
const char *DescribeSockLevel(int);
const char *DescribeSockOptname(int, int);
const char *GetMagnumStr(const struct MagnumStr *, int);
char *DescribeClockName(int) hidden;
char *DescribeOpenFlags(int) hidden;
char *DescribeSockLevel(int) hidden;
char *DescribeSockOptname(int, int) hidden;
char *GetMagnumStr(const struct MagnumStr *, int) hidden;
COSMOPOLITAN_C_END_
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */

View file

@ -23,7 +23,7 @@
* Converts errno value to descriptive sentence.
* @return non-null rodata string or null if not found
*/
const char *strerdoc(int x) {
char *strerdoc(int x) {
if (x) {
return GetMagnumStr(kErrnoDocs, x);
} else {

View file

@ -23,7 +23,7 @@
* Converts errno value to symbolic name.
* @return non-null rodata string or null if not found
*/
const char *strerrno(int x) {
char *strerrno(int x) {
if (x) {
return GetMagnumStr(kErrnoNames, x);
} else {

View file

@ -23,7 +23,7 @@
#include "libc/sysv/consts/prot.h"
const char *DescribeMapFlags(int x) {
static char mapflags[256];
_Alignas(char) static char mapflags[256];
const struct DescribeFlags kMapFlags[] = {
{MAP_ANONYMOUS, "ANONYMOUS"}, //
{MAP_PRIVATE, "PRIVATE"}, //

View file

@ -34,7 +34,7 @@ static const struct DescribeFlags kConsoleModeInputFlags[] = {
};
const char *DescribeNtConsoleModeInputFlags(uint32_t x) {
static char consolemodeinputflags[256];
_Alignas(char) static char consolemodeinputflags[256];
return DescribeFlags(consolemodeinputflags, sizeof(consolemodeinputflags),
kConsoleModeInputFlags, ARRAYLEN(kConsoleModeInputFlags),
"kNtEnable", x);

View file

@ -29,7 +29,7 @@ static const struct DescribeFlags kConsoleModeOutputFlags[] = {
};
const char *DescribeNtConsoleModeOutputFlags(uint32_t x) {
static char consolemodeoutputflags[128];
_Alignas(char) static char consolemodeoutputflags[128];
return DescribeFlags(consolemodeoutputflags, sizeof(consolemodeoutputflags),
kConsoleModeOutputFlags,
ARRAYLEN(kConsoleModeOutputFlags), "kNt", x);

View file

@ -64,7 +64,7 @@ static const struct DescribeFlags kFileAccessflags[] = {
};
const char *DescribeNtFileAccessFlags(uint32_t x) {
static char ntfileaccessflags[512];
_Alignas(char) static char ntfileaccessflags[512];
return DescribeFlags(ntfileaccessflags, sizeof(ntfileaccessflags),
kFileAccessflags, ARRAYLEN(kFileAccessflags), "kNt", x);
}

View file

@ -52,7 +52,7 @@ static const struct DescribeFlags kFileFlags[] = {
};
const char *DescribeNtFileFlagsAndAttributes(uint32_t x) {
static char ntfileflags[256];
_Alignas(char) static char ntfileflags[256];
if (x == -1u) return "-1u";
return DescribeFlags(ntfileflags, sizeof(ntfileflags), kFileFlags,
ARRAYLEN(kFileFlags), "kNtFile", x);

View file

@ -31,7 +31,7 @@ static const struct DescribeFlags kFileMapFlags[] = {
};
const char *DescribeNtFileMapFlags(uint32_t x) {
static char filemapflags[64];
_Alignas(char) static char filemapflags[64];
return DescribeFlags(filemapflags, sizeof(filemapflags), kFileMapFlags,
ARRAYLEN(kFileMapFlags), "kNtFileMap", x);
}

View file

@ -27,7 +27,7 @@ static const struct DescribeFlags kFileShareflags[] = {
};
const char *DescribeNtFileShareFlags(uint32_t x) {
static char ntfileshareflags[64];
_Alignas(char) static char ntfileshareflags[64];
return DescribeFlags(ntfileshareflags, sizeof(ntfileshareflags),
kFileShareflags, ARRAYLEN(kFileShareflags),
"kNtFileShare", x);

View file

@ -29,7 +29,7 @@ static const struct DescribeFlags kFiletypeFlags[] = {
};
const char *DescribeNtFiletypeFlags(uint32_t x) {
static char filetypeflags[64];
_Alignas(char) static char filetypeflags[64];
return DescribeFlags(filetypeflags, sizeof(filetypeflags), kFiletypeFlags,
ARRAYLEN(kFiletypeFlags), "kNtFileType", x);
}

View file

@ -30,7 +30,7 @@ static const struct DescribeFlags kMoveFileInputFlags[] = {
};
const char *DescribeNtMoveFileInputFlags(uint32_t x) {
static char movefileflags[256];
_Alignas(char) static char movefileflags[256];
return DescribeFlags(movefileflags, sizeof(movefileflags),
kMoveFileInputFlags, ARRAYLEN(kMoveFileInputFlags),
"kNtMovefile", x);

View file

@ -42,7 +42,7 @@ static const struct DescribeFlags kPageFlags[] = {
};
const char *DescribeNtPageFlags(uint32_t x) {
static char pageflags[64];
_Alignas(char) static char pageflags[64];
return DescribeFlags(pageflags, sizeof(pageflags), kPageFlags,
ARRAYLEN(kPageFlags), "kNt", x);
}

View file

@ -33,7 +33,7 @@ static const struct DescribeFlags kPipeModeFlags[] = {
};
const char *DescribeNtPipeModeFlags(uint32_t x) {
static char pipemodeflags[64];
_Alignas(char) static char pipemodeflags[64];
return DescribeFlags(pipemodeflags, sizeof(pipemodeflags), kPipeModeFlags,
ARRAYLEN(kPipeModeFlags), "kNtPipe", x);
}

View file

@ -28,7 +28,7 @@ static const struct DescribeFlags kPipeOpenFlags[] = {
};
const char *DescribeNtPipeOpenFlags(uint32_t x) {
static char pipeopenflags[64];
_Alignas(char) static char pipeopenflags[64];
return DescribeFlags(pipeopenflags, sizeof(pipeopenflags), kPipeOpenFlags,
ARRAYLEN(kPipeOpenFlags), "kNtPipeAccess", x);
}

View file

@ -38,7 +38,7 @@ static const struct DescribeFlags kProcessAccessflags[] = {
};
const char *DescribeNtProcessAccessFlags(uint32_t x) {
static char ntprocessaccessflags[256];
_Alignas(char) static char ntprocessaccessflags[256];
return DescribeFlags(ntprocessaccessflags, sizeof(ntprocessaccessflags),
kProcessAccessflags, ARRAYLEN(kProcessAccessflags),
"kNtProcess", x);

View file

@ -39,7 +39,7 @@ static const struct DescribeFlags kNtStartFlags[] = {
};
const char *DescribeNtStartFlags(uint32_t x) {
static char startflags[128];
_Alignas(char) static char startflags[128];
return DescribeFlags(startflags, sizeof(startflags), kNtStartFlags,
ARRAYLEN(kNtStartFlags), "kNtStartf", x);
}

View file

@ -26,7 +26,7 @@ static const struct DescribeFlags kSymbolicLinkflags[] = {
};
const char *DescribeNtSymbolicLinkFlags(uint32_t x) {
static char ntsymboliclinkflags[64];
_Alignas(char) static char ntsymboliclinkflags[64];
return DescribeFlags(ntsymboliclinkflags, sizeof(ntsymboliclinkflags),
kSymbolicLinkflags, ARRAYLEN(kSymbolicLinkflags),
"kNtSymbolicLinkFlag", x);

View file

@ -27,7 +27,7 @@ static const struct DescribeFlags kProtFlags[] = {
};
const char *DescribeProtFlags(int x) {
static char protflags[64];
_Alignas(char) static char protflags[64];
return DescribeFlags(protflags, sizeof(protflags), kProtFlags,
ARRAYLEN(kProtFlags), "PROT_", x);
}

View file

@ -26,7 +26,7 @@ static const struct DescribeFlags kRemapFlags[] = {
};
const char *DescribeRemapFlags(int x) {
static char remapflags[64];
_Alignas(char) static char remapflags[64];
return DescribeFlags(remapflags, sizeof(remapflags), kRemapFlags,
ARRAYLEN(kRemapFlags), "MREMAP_", x);
}

View file

@ -18,11 +18,11 @@
*/
#include "libc/fmt/magnumstrs.internal.h"
const char *GetMagnumStr(const struct MagnumStr *ms, int x) {
char *GetMagnumStr(const struct MagnumStr *ms, int x) {
int i;
for (i = 0; ms[i].x != -123; ++i) {
if (x == *(const int *)((uintptr_t)ms + ms[i].x)) {
return (const char *)((uintptr_t)ms + ms[i].s);
for (i = 0; ms[i].x != MAGNUM_TERMINATOR; ++i) {
if (x == MAGNUM_NUMBER(ms, i)) {
return MAGNUM_STRING(ms, i);
}
}
return 0;

View file

@ -28,6 +28,8 @@
STATIC_YOINK("__get_symbol_by_addr");
#define MAXLEAKS 1000
static bool once;
static bool hasleaks;
@ -46,15 +48,18 @@ static noasan void CheckLeak(void *x, void *y, size_t n, void *a) {
static noasan void OnMemory(void *x, void *y, size_t n, void *a) {
static int i;
if (n) {
if (++i < 20) {
kprintf("%p %,lu bytes [dlmalloc]", x, n);
if (IsAsan()) {
__asan_print_trace(x);
if (MAXLEAKS) {
if (i < MAXLEAKS) {
++i;
kprintf("%p %,lu bytes [dlmalloc]", x, n);
if (IsAsan()) {
__asan_print_trace(x);
}
kprintf("\n");
} else if (i == MAXLEAKS) {
++i;
kprintf("etc. etc.\n");
}
kprintf("\n");
}
if (i == 20) {
kprintf("etc. etc.\n");
}
}
}

13
libc/nt/struct/linger.h Normal file
View file

@ -0,0 +1,13 @@
#ifndef COSMOPOLITAN_LIBC_NT_STRUCT_LINGER_H_
#define COSMOPOLITAN_LIBC_NT_STRUCT_LINGER_H_
#if !(__ASSEMBLER__ + __LINKER__ + 0)
COSMOPOLITAN_C_START_
struct linger_nt {
uint16_t l_onoff; /* on/off */
uint16_t l_linger; /* seconds */
};
COSMOPOLITAN_C_END_
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
#endif /* COSMOPOLITAN_LIBC_NT_STRUCT_LINGER_H_ */

View file

@ -22,7 +22,7 @@
/**
* Describes setsockopt() level arguments.
*/
const char *DescribeSockLevel(int x) {
char *DescribeSockLevel(int x) {
static char buf[12];
if (x == SOL_IP) return "SOL_IP";
if (x == SOL_TCP) return "SOL_TCP";

View file

@ -18,26 +18,32 @@
*/
#include "libc/fmt/itoa.h"
#include "libc/fmt/magnumstrs.internal.h"
#include "libc/str/str.h"
#include "libc/sysv/consts/sol.h"
/**
* Describes setsockopt() optname arguments.
*/
const char *DescribeSockOptname(int l, int x) {
char *DescribeSockOptname(int l, int x) {
int i;
static char buf[12], *s;
char *ps, *s;
const struct MagnumStr *ms = 0;
_Alignas(char) static char buf[32];
if (x) {
if (l == SOL_SOCKET) {
ps = "SO_";
ms = kSockOptnames;
} else if (l == SOL_TCP) {
ps = "TCP_";
ms = kTcpOptnames;
} else if (l == SOL_IP) {
ps = "IP_";
ms = kIpOptnames;
}
}
if (ms && (s = GetMagnumStr(ms, x))) {
return s;
stpcpy(stpcpy(buf, ps), s);
return buf;
} else {
FormatInt32(buf, x);
return buf;

View file

@ -20,8 +20,10 @@
#include "libc/bits/bits.h"
#include "libc/calls/internal.h"
#include "libc/calls/struct/timeval.h"
#include "libc/nt/struct/linger.h"
#include "libc/nt/winsock.h"
#include "libc/sock/internal.h"
#include "libc/sock/sock.h"
#include "libc/sock/yoink.inc"
#include "libc/str/str.h"
#include "libc/sysv/consts/so.h"
@ -33,6 +35,7 @@ textwindows int sys_getsockopt_nt(struct Fd *fd, int level, int optname,
uint32_t *inout_optlen) {
uint64_t ms;
uint32_t in_optlen;
struct linger_nt linger;
assert(fd->kind == kFdSocket);
if (out_opt_optval && inout_optlen) {
@ -55,6 +58,11 @@ textwindows int sys_getsockopt_nt(struct Fd *fd, int level, int optname,
((struct timeval *)out_opt_optval)->tv_sec = ms / 1000;
((struct timeval *)out_opt_optval)->tv_usec = ms % 1000 * 1000;
*inout_optlen = sizeof(struct timeval);
} else if (optname == SO_LINGER && in_optlen == sizeof(struct linger)) {
linger = *(struct linger_nt *)out_opt_optval;
((struct linger *)out_opt_optval)->l_onoff = !!linger.l_onoff;
((struct linger *)out_opt_optval)->l_linger = linger.l_linger;
*inout_optlen = sizeof(struct linger);
}
}

View file

@ -16,24 +16,25 @@
TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE.
*/
#include "libc/fmt/magnumstrs.internal.h"
#include "libc/macros.internal.h"
.macro .e e
.macro .e e s
.long \e - kIpOptnames
.long 1f - kIpOptnames
.rodata.str1.1
1: .string "\e"
1: .string "\s"
.previous
.endm
.section .rodata
.align 4
.align 4
.underrun
kIpOptnames:
.e IP_TOS # int
.e IP_MTU # int
.e IP_TTL # int
.e IP_HDRINCL # bool32
.long -123
.e IP_TOS,"TOS" # int
.e IP_MTU,"MTU" # int
.e IP_TTL,"TTL" # int
.e IP_HDRINCL,"HDRINCL" # bool32
.long MAGNUM_TERMINATOR
.endobj kIpOptnames,globl,hidden
.overrun

View file

@ -16,13 +16,14 @@
TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE.
*/
#include "libc/fmt/magnumstrs.internal.h"
#include "libc/macros.internal.h"
.macro .e e
.macro .e e s
.long \e - kSockOptnames
.long 1f - kSockOptnames
.rodata.str1.1
1: .string "\e"
1: .string "\s"
.previous
.endm
@ -30,20 +31,22 @@
.align 4
.underrun
kSockOptnames:
.e SO_DEBUG # bool32
.e SO_BROADCAST # bool32
.e SO_REUSEADDR # bool32
.e SO_REUSEPORT # bool32
.e SO_KEEPALIVE # bool32
.e SO_DONTROUTE # bool32
.e SO_RCVTIMEO # timeval
.e SO_SNDTIMEO # timeval
.e SO_LINGER # linger
.e SO_SNDBUF # int
.e SO_RCVBUF # int
.e SO_RCVLOWAT # int
.e SO_SNDLOWAT # int
.e SO_ERROR # int
.long -123
.e SO_DEBUG,"DEBUG" # bool32
.e SO_ACCEPTCONN,"ACCEPTCONN" # bool32
.e SO_BROADCAST,"BROADCAST" # bool32
.e SO_REUSEADDR,"REUSEADDR" # bool32
.e SO_REUSEPORT,"REUSEPORT" # bool32
.e SO_KEEPALIVE,"KEEPALIVE" # bool32
.e SO_DONTROUTE,"DONTROUTE" # bool32
.e SO_RCVTIMEO,"RCVTIMEO" # timeval
.e SO_SNDTIMEO,"SNDTIMEO" # timeval
.e SO_LINGER,"LINGER" # linger
.e SO_TYPE,"TYPE" # int
.e SO_SNDBUF,"SNDBUF" # int
.e SO_RCVBUF,"RCVBUF" # int
.e SO_RCVLOWAT,"RCVLOWAT" # int
.e SO_SNDLOWAT,"SNDLOWAT" # int
.e SO_ERROR,"ERROR" # int
.long MAGNUM_TERMINATOR
.endobj kSockOptnames,globl,hidden
.overrun

View file

@ -16,33 +16,34 @@
TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE.
*/
#include "libc/fmt/magnumstrs.internal.h"
#include "libc/macros.internal.h"
.macro .e e
.macro .e e s
.long \e - kTcpOptnames
.long 1f - kTcpOptnames
.rodata.str1.1
1: .string "\e"
1: .string "\s"
.previous
.endm
.section .rodata
.align 4
.align 4
.underrun
kTcpOptnames:
.e TCP_NODELAY # bool32
.e TCP_CORK # bool32
.e TCP_QUICKACK # bool32
.e TCP_FASTOPEN_CONNECT # bool32
.e TCP_DEFER_ACCEPT # bool32
.e TCP_KEEPIDLE # int (seconds)
.e TCP_KEEPINTVL # int (seconds)
.e TCP_FASTOPEN # int
.e TCP_KEEPCNT # int
.e TCP_MAXSEG # int
.e TCP_SYNCNT # int
.e TCP_NOTSENT_LOWAT # int
.e TCP_WINDOW_CLAMP # int
.long -123
.e TCP_NODELAY,"NODELAY" # bool32
.e TCP_CORK,"CORK" # bool32
.e TCP_QUICKACK,"QUICKACK" # bool32
.e TCP_FASTOPEN_CONNECT,"FASTOPEN_CONNECT" # bool32
.e TCP_DEFER_ACCEPT,"DEFER_ACCEPT" # bool32
.e TCP_KEEPIDLE,"KEEPIDLE" # int (seconds)
.e TCP_KEEPINTVL,"KEEPINTVL" # int (seconds)
.e TCP_FASTOPEN,"FASTOPEN" # int
.e TCP_KEEPCNT,"KEEPCNT" # int
.e TCP_MAXSEG,"MAXSEG" # int
.e TCP_SYNCNT,"SYNCNT" # int
.e TCP_NOTSENT_LOWAT,"NOTSENT_LOWAT" # int
.e TCP_WINDOW_CLAMP,"WINDOW_CLAMP" # int
.long MAGNUM_TERMINATOR
.endobj kTcpOptnames,globl,hidden
.overrun

View file

@ -19,16 +19,12 @@
#include "libc/calls/struct/timeval.h"
#include "libc/limits.h"
#include "libc/macros.internal.h"
#include "libc/nt/struct/linger.h"
#include "libc/sock/internal.h"
#include "libc/sysv/consts/so.h"
#include "libc/sysv/consts/sol.h"
#include "libc/sysv/errfuns.h"
struct linger_nt { /* Linux+XNU+BSD ABI */
uint16_t l_onoff; /* on/off */
uint16_t l_linger; /* seconds */
};
textwindows int sys_setsockopt_nt(struct Fd *fd, int level, int optname,
const void *optval, uint32_t optlen) {
int64_t ms;

View file

@ -22,6 +22,7 @@
#include "libc/calls/struct/sigaction.h"
#include "libc/dce.h"
#include "libc/errno.h"
#include "libc/log/log.h"
#include "libc/paths.h"
#include "libc/runtime/runtime.h"
#include "libc/stdio/stdio.h"

View file

@ -16,6 +16,7 @@
TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE.
*/
#include "libc/fmt/magnumstrs.internal.h"
#include "libc/macros.internal.h"
.macro .e e s
@ -65,6 +66,6 @@ kSignalNames:
.e SIGRTMIN,"RTMIN"
.e SIGEMT,"EMT"
.e SIGPWR,"PWR"
.long -123
.long MAGNUM_TERMINATOR
.endobj kSignalNames,globl,hidden
.overrun

View file

@ -262,8 +262,8 @@ wint_t towctrans(wint_t, wctrans_t);
char *strsignal(int) returnsnonnull libcesque;
char *strerror(int) returnsnonnull dontthrow nocallback;
const char *strerrno(int) nosideeffect libcesque;
const char *strerdoc(int) nosideeffect libcesque;
char *strerrno(int) nosideeffect libcesque;
char *strerdoc(int) nosideeffect libcesque;
int strerror_r(int, char *, size_t) dontthrow nocallback;
int strerror_wr(int, uint32_t, char *, size_t) dontthrow nocallback;

View file

@ -620,7 +620,7 @@ syscon clock CLOCK_MONOTONIC_RAW 4 4 0x4000 0x4000 0x4000 4 # actu
syscon clock CLOCK_REALTIME_COARSE 5 -1 -1 -1 -1 -1 # Linux 2.6.32+; bsd consensus; not available on RHEL5
syscon clock CLOCK_MONOTONIC_COARSE 6 -1 -1 -1 -1 -1 # Linux 2.6.32+; bsd consensus; not available on RHEL5
syscon clock CLOCK_PROF -1 -1 2 -1 2 -1 #
syscon clock CLOCK_BOOTTIME 7 -1 -1 6 6 -1 #
syscon clock CLOCK_BOOTTIME 7 -1 -1 6 -1 -1 #
syscon clock CLOCK_REALTIME_ALARM 8 -1 -1 -1 -1 -1 #
syscon clock CLOCK_BOOTTIME_ALARM 9 -1 -1 -1 -1 -1 #
syscon clock CLOCK_TAI 11 -1 -1 -1 -1 -1 #
@ -669,16 +669,19 @@ syscon epoll EPOLLET 0x80000000 0x80000000 0x80000000 0x80000000 0x80000
# * -1 we define as no-op
#
# group name GNU/Systemd XNU's Not UNIX! FreeBSD OpenBSD NetBSD The New Technology Commentary
syscon so SO_DEBUG 1 1 1 1 1 1 # debugging is enabled; consensus
syscon so SO_TYPE 3 0x1008 0x1008 0x1008 0x1008 0x1008 # bsd consensus
syscon so SO_ERROR 4 0x1007 0x1007 0x1007 0x1007 0x1007 # takes int pointer and stores/clears the pending error code; bsd consensus
syscon so SO_ACCEPTCONN 30 2 2 2 2 2 # takes int pointer and stores boolean indicating if listen() was called on fd; bsd consensus
syscon so SO_REUSEPORT 15 0x0200 0x0200 0x0200 0x0200 4 # bsd consensus (NT calls it SO_REUSEADDR)
syscon so SO_REUSEADDR 2 4 4 4 4 0 # bsd consensus (default behavior on NT)
syscon so SO_REUSEADDR 2 4 4 4 4 4 # bsd consensus (default behavior on NT)
syscon so SO_EXCLUSIVEADDRUSE 0 0 0 0 0 ~4 # bsd consensus (default behavior on NT)
syscon so SO_KEEPALIVE 9 8 8 8 8 8 # bsd consensus
syscon so SO_DONTROUTE 5 0x10 0x10 0x10 0x10 0x10 # bsd consensus
syscon so SO_BROADCAST 6 0x20 0x20 0x20 0x20 0x20 # bsd consensus
syscon so SO_BROADCAST 6 0x20 0x20 0x20 0x20 0x20 # socket is configured for broadcast messages; bsd consensus
syscon so SO_USELOOPBACK 0 0x40 0x40 0x40 0x40 0x40 # bsd consensus
syscon so SO_LINGER 13 0x80 0x80 0x80 0x80 0x80 # takes struct linger; causes close() return value to actually mean something; bsd consensus
syscon so SO_DEBUG 1 1 1 1 1 1 # consensus
syscon so SO_ACCEPTCONN 30 2 2 2 2 2 # takes int pointer and stores boolean indicating if listen() was called on fd; bsd consensus
syscon so SO_ERROR 4 0x1007 0x1007 0x1007 0x1007 0x1007 # takes int pointer and stores/clears the pending error code; bsd consensus
syscon so SO_DONTLINGER 0 0 0 0 0 ~0x80 # disables so_linger on windows
syscon so SO_OOBINLINE 10 0x0100 0x0100 0x0100 0x0100 0x0100 # bsd consensus
syscon so SO_SNDBUF 7 0x1001 0x1001 0x1001 0x1001 0x1001 # bsd consensus
syscon so SO_RCVBUF 8 0x1002 0x1002 0x1002 0x1002 0x1002 # bsd consensus
@ -686,7 +689,6 @@ syscon so SO_RCVTIMEO 20 0x1006 0x1006 0x1006 0x100c 0x1006 # rec
syscon so SO_SNDTIMEO 21 0x1005 0x1005 0x1005 0x100b 0x1005 # send timeout; takes struct timeval; bsd consensus
syscon so SO_RCVLOWAT 18 0x1004 0x1004 0x1004 0x1004 0x1004 # bsd consensus
syscon so SO_SNDLOWAT 19 0x1003 0x1003 0x1003 0x1003 0x1003 # bsd consensus
syscon so SO_TYPE 3 0x1008 0x1008 0x1008 0x1008 0x1008 # bsd consensus
syscon so SO_TIMESTAMP 29 0x0400 0x0400 0x0800 0x2000 0
syscon so SO_SETFIB 0 0 0x1014 0 0 0
syscon so SO_DOMAIN 39 0 0x1019 0x1024 0 0

View file

@ -1,2 +1,2 @@
#include "libc/sysv/consts/syscon.internal.h"
.syscon clock,CLOCK_BOOTTIME,7,-1,-1,6,6,-1
.syscon clock,CLOCK_BOOTTIME,7,-1,-1,6,-1,-1

View file

@ -0,0 +1,2 @@
#include "libc/sysv/consts/syscon.internal.h"
.syscon so,SO_DONTLINGER,0,0,0,0,0,~0x80

View file

@ -1,2 +1,2 @@
#include "libc/sysv/consts/syscon.internal.h"
.syscon so,SO_REUSEADDR,2,4,4,4,4,0
.syscon so,SO_REUSEADDR,2,4,4,4,4,4

View file

@ -1,6 +1,7 @@
#ifndef COSMOPOLITAN_LIBC_TESTLIB_EZBENCH_H_
#define COSMOPOLITAN_LIBC_TESTLIB_EZBENCH_H_
#include "libc/macros.internal.h"
#include "libc/nexgen32e/bench.h"
#include "libc/nexgen32e/x86feature.h"
#include "libc/sysv/consts/clock.h"
#include "libc/testlib/bench.h"
@ -9,151 +10,162 @@
#if !(__ASSEMBLER__ + __LINKER__ + 0)
COSMOPOLITAN_C_START_
#define EZBENCH_COUNT 128
#define EZBENCH_TRIES 10
#define EZBENCH(INIT, EXPR) EZBENCH2(#EXPR, INIT, EXPR)
#define EZBENCH2(NAME, INIT, EXPR) \
do { \
int Core, Tries, Interrupts; \
int64_t Speculative, MemoryStrict; \
Tries = 0; \
do { \
__testlib_yield(); \
Core = __testlib_getcore(); \
Interrupts = __testlib_getinterrupts(); \
INIT; \
EXPR; \
Speculative = BENCHLOOP(__startbench, __endbench, 128, ({ \
INIT; \
polluteregisters(); \
}), \
(EXPR)); \
} while (++Tries < 10 && (__testlib_getcore() != Core && \
__testlib_getinterrupts() > Interrupts)); \
if (Tries == 10) __testlib_ezbenchwarn(" speculative"); \
Tries = 0; \
do { \
__testlib_yield(); \
Core = __testlib_getcore(); \
Interrupts = __testlib_getinterrupts(); \
INIT; \
EXPR; \
MemoryStrict = BENCHLOOP(__startbench_m, __endbench_m, 32, ({ \
INIT; \
thrashcodecache(); \
polluteregisters(); \
}), \
(EXPR)); \
} while (++Tries < 10 && (__testlib_getcore() != Core && \
__testlib_getinterrupts() > Interrupts)); \
if (Tries == 10) __testlib_ezbenchwarn(" memory strict"); \
__testlib_ezbenchreport( \
NAME, MAX(0, Speculative - __testlib_ezbenchcontrol()), \
MAX(0, MemoryStrict - __testlib_ezbenchcontrol())); \
#define EZBENCH2(NAME, INIT, EXPR) \
do { \
int Core, Tries, Interrupts; \
int64_t Speculative, MemoryStrict; \
Tries = 0; \
do { \
__testlib_yield(); \
Core = __testlib_getcore(); \
Interrupts = __testlib_getinterrupts(); \
INIT; \
EXPR; \
Speculative = BENCHLOOP(__startbench, __endbench, EZBENCH_COUNT, ({ \
INIT; \
__polluteregisters(); \
}), \
(EXPR)); \
} while (++Tries < EZBENCH_TRIES && \
(__testlib_getcore() != Core && \
__testlib_getinterrupts() > Interrupts)); \
if (Tries == EZBENCH_TRIES) __testlib_ezbenchwarn(" speculative"); \
Tries = 0; \
do { \
__testlib_yield(); \
Core = __testlib_getcore(); \
Interrupts = __testlib_getinterrupts(); \
INIT; \
EXPR; \
MemoryStrict = BENCHLOOP(__startbench_m, __endbench_m, 32, ({ \
INIT; \
thrashcodecache(); \
__polluteregisters(); \
}), \
(EXPR)); \
} while (++Tries < EZBENCH_TRIES && \
(__testlib_getcore() != Core && \
__testlib_getinterrupts() > Interrupts)); \
if (Tries == EZBENCH_TRIES) __testlib_ezbenchwarn(" memory strict"); \
__testlib_ezbenchreport( \
NAME, MAX(0, Speculative - __testlib_ezbenchcontrol()), \
MAX(0, MemoryStrict - __testlib_ezbenchcontrol())); \
} while (0)
#define EZBENCH3(NAME, NUM, INIT, EXPR) \
do { \
int Core, Tries, Interrupts; \
int64_t Speculative, MemoryStrict; \
Tries = 0; \
do { \
__testlib_yield(); \
Core = __testlib_getcore(); \
Interrupts = __testlib_getinterrupts(); \
INIT; \
EXPR; \
Speculative = BENCHLOOP(__startbench, __endbench, NUM, ({ \
INIT; \
polluteregisters(); \
}), \
(EXPR)); \
} while (++Tries < 10 && (__testlib_getcore() != Core && \
__testlib_getinterrupts() > Interrupts)); \
if (Tries == 10) __testlib_ezbenchwarn(" speculative"); \
Tries = 0; \
do { \
__testlib_yield(); \
Core = __testlib_getcore(); \
Interrupts = __testlib_getinterrupts(); \
INIT; \
EXPR; \
MemoryStrict = BENCHLOOP(__startbench_m, __endbench_m, NUM, ({ \
INIT; \
thrashcodecache(); \
polluteregisters(); \
}), \
(EXPR)); \
} while (++Tries < 10 && (__testlib_getcore() != Core && \
__testlib_getinterrupts() > Interrupts)); \
if (Tries == 10) __testlib_ezbenchwarn(" memory strict"); \
__testlib_ezbenchreport( \
NAME, MAX(0, Speculative - __testlib_ezbenchcontrol()), \
MAX(0, MemoryStrict - __testlib_ezbenchcontrol())); \
#define EZBENCH3(NAME, NUM, INIT, EXPR) \
do { \
int Core, Tries, Interrupts; \
int64_t Speculative, MemoryStrict; \
Tries = 0; \
do { \
__testlib_yield(); \
Core = __testlib_getcore(); \
Interrupts = __testlib_getinterrupts(); \
INIT; \
EXPR; \
Speculative = BENCHLOOP(__startbench, __endbench, NUM, ({ \
INIT; \
__polluteregisters(); \
}), \
(EXPR)); \
} while (++Tries < EZBENCH_TRIES && \
(__testlib_getcore() != Core && \
__testlib_getinterrupts() > Interrupts)); \
if (Tries == EZBENCH_TRIES) __testlib_ezbenchwarn(" speculative"); \
Tries = 0; \
do { \
__testlib_yield(); \
Core = __testlib_getcore(); \
Interrupts = __testlib_getinterrupts(); \
INIT; \
EXPR; \
MemoryStrict = BENCHLOOP(__startbench_m, __endbench_m, NUM, ({ \
INIT; \
thrashcodecache(); \
__polluteregisters(); \
}), \
(EXPR)); \
} while (++Tries < EZBENCH_TRIES && \
(__testlib_getcore() != Core && \
__testlib_getinterrupts() > Interrupts)); \
if (Tries == EZBENCH_TRIES) __testlib_ezbenchwarn(" memory strict"); \
__testlib_ezbenchreport( \
NAME, MAX(0, Speculative - __testlib_ezbenchcontrol()), \
MAX(0, MemoryStrict - __testlib_ezbenchcontrol())); \
} while (0)
#define EZBENCH_C(NAME, CONTROL, EXPR) \
do { \
int Core, Tries, Interrupts; \
int64_t Control, Speculative, MemoryStrict; \
Tries = 0; \
do { \
__testlib_yield(); \
Core = __testlib_getcore(); \
Interrupts = __testlib_getinterrupts(); \
Control = BENCHLOOP(__startbench_m, __endbench_m, 128, ({ \
thrashcodecache(); \
polluteregisters(); \
}), \
(CONTROL)); \
} while (++Tries < 10 && (__testlib_getcore() != Core && \
__testlib_getinterrupts() > Interrupts)); \
if (Tries == 10) __testlib_ezbenchwarn(" control"); \
Tries = 0; \
do { \
__testlib_yield(); \
Core = __testlib_getcore(); \
Interrupts = __testlib_getinterrupts(); \
EXPR; \
Speculative = BENCHLOOP(__startbench, __endbench, 128, \
polluteregisters(), (EXPR)); \
} while (++Tries < 10 && (__testlib_getcore() != Core && \
__testlib_getinterrupts() > Interrupts)); \
if (Tries == 10) __testlib_ezbenchwarn(" speculative"); \
Tries = 0; \
do { \
__testlib_yield(); \
Core = __testlib_getcore(); \
Interrupts = __testlib_getinterrupts(); \
EXPR; \
MemoryStrict = BENCHLOOP(__startbench_m, __endbench_m, 8, ({ \
thrashcodecache(); \
polluteregisters(); \
}), \
(EXPR)); \
} while (++Tries < 10 && (__testlib_getcore() != Core && \
__testlib_getinterrupts() > Interrupts)); \
if (Tries == 10) __testlib_ezbenchwarn(" memory strict"); \
__testlib_ezbenchreport(NAME, MAX(0, Speculative - Control), \
MAX(0, MemoryStrict - Control)); \
#define EZBENCH_C(NAME, CONTROL, EXPR) \
do { \
int Core, Tries, Interrupts; \
int64_t Control, Speculative, MemoryStrict; \
Tries = 0; \
do { \
__testlib_yield(); \
Core = __testlib_getcore(); \
Interrupts = __testlib_getinterrupts(); \
Control = BENCHLOOP(__startbench_m, __endbench_m, EZBENCH_COUNT, ({ \
thrashcodecache(); \
__polluteregisters(); \
}), \
(CONTROL)); \
} while (++Tries < EZBENCH_TRIES && \
(__testlib_getcore() != Core && \
__testlib_getinterrupts() > Interrupts)); \
if (Tries == EZBENCH_TRIES) __testlib_ezbenchwarn(" control"); \
Tries = 0; \
do { \
__testlib_yield(); \
Core = __testlib_getcore(); \
Interrupts = __testlib_getinterrupts(); \
EXPR; \
Speculative = BENCHLOOP(__startbench, __endbench, EZBENCH_COUNT, \
__polluteregisters(), (EXPR)); \
} while (++Tries < EZBENCH_TRIES && \
(__testlib_getcore() != Core && \
__testlib_getinterrupts() > Interrupts)); \
if (Tries == EZBENCH_TRIES) __testlib_ezbenchwarn(" speculative"); \
Tries = 0; \
do { \
__testlib_yield(); \
Core = __testlib_getcore(); \
Interrupts = __testlib_getinterrupts(); \
EXPR; \
MemoryStrict = BENCHLOOP(__startbench_m, __endbench_m, 8, ({ \
thrashcodecache(); \
__polluteregisters(); \
}), \
(EXPR)); \
} while (++Tries < EZBENCH_TRIES && \
(__testlib_getcore() != Core && \
__testlib_getinterrupts() > Interrupts)); \
if (Tries == EZBENCH_TRIES) __testlib_ezbenchwarn(" memory strict"); \
__testlib_ezbenchreport(NAME, MAX(0, Speculative - Control), \
MAX(0, MemoryStrict - Control)); \
} while (0)
#define EZBENCH_N(NAME, N, EXPR) \
do { \
int64_t Speculative, Toto; \
int Core, Tries, Interrupts; \
Tries = 0; \
do { \
__testlib_yield(); \
Core = __testlib_getcore(); \
Interrupts = __testlib_getinterrupts(); \
EXPR; \
Speculative = \
BENCHLOOP(__startbench, __endbench, 32, polluteregisters(), (EXPR)); \
} while (++Tries < 10 && (__testlib_getcore() != Core && \
__testlib_getinterrupts() > Interrupts)); \
if (Tries == 10) __testlib_ezbenchwarn(""); \
__testlib_ezbenchreport_n( \
NAME, 'n', N, MAX(0, Speculative - __testlib_ezbenchcontrol())); \
#define EZBENCH_N(NAME, N, EXPR) \
do { \
int64_t Speculative, Toto; \
int Core, Tries, Interrupts; \
Tries = 0; \
do { \
__testlib_yield(); \
Core = __testlib_getcore(); \
Interrupts = __testlib_getinterrupts(); \
EXPR; \
Speculative = BENCHLOOP(__startbench, __endbench, 32, \
__polluteregisters(), (EXPR)); \
} while (++Tries < EZBENCH_TRIES && \
(__testlib_getcore() != Core && \
__testlib_getinterrupts() > Interrupts)); \
if (Tries == EZBENCH_TRIES) __testlib_ezbenchwarn(""); \
__testlib_ezbenchreport_n( \
NAME, 'n', N, MAX(0, Speculative - __testlib_ezbenchcontrol())); \
} while (0)
#define EZBENCH_K(NAME, K, EXPR) \
@ -164,14 +176,14 @@ COSMOPOLITAN_C_START_
__testlib_yield(); \
Core = __testlib_getcore(); \
EXPR; \
Speculative = \
BENCHLOOP(__startbench, __endbench, 128, donothing, (EXPR)); \
Speculative = BENCHLOOP(__startbench, __endbench, EZBENCH_COUNT, \
donothing, (EXPR)); \
} while (Core != __testlib_getcore()); \
__testlib_ezbenchreport_n( \
NAME, 'k', K, MAX(0, Speculative - __testlib_ezbenchcontrol())); \
} while (0)
void polluteregisters(void);
void __polluteregisters(void);
void __testlib_yield(void);
int __testlib_getcore(void);
int64_t __testlib_getinterrupts(void);

View file

@ -19,15 +19,15 @@
#include "libc/nexgen32e/x86feature.h"
#include "libc/macros.internal.h"
polluteregisters:
__polluteregisters:
.leafprologue
xor %eax,%eax
mov %ecx,%ecx
mov %edx,%edx
mov %r8d,%r8d
mov %r9d,%r9d
mov %r10d,%r10d
mov %r11d,%r11d
xor %ecx,%ecx
xor %edx,%edx
xor %r8d,%r8d
xor %r9d,%r9d
xor %r10d,%r10d
xor %r11d,%r11d
testb X86_HAVE(AVX)+kCpuids(%rip)
jz .Lsse
vpxor %xmm0,%xmm0,%xmm0
@ -48,13 +48,13 @@ polluteregisters:
xorps %xmm6,%xmm6
xorps %xmm7,%xmm7
.leafepilogue
.endfn polluteregisters,globl
.endfn __polluteregisters,globl
.end
// Fill registers with junk data to create false dependencies.
// Which shall create the problem that happens w/o vzeroupper.
// Or the Core Architecture errata regarding BSR/BSF w/ 64bit.
polluteregisters:
__polluteregisters:
.leafprologue
mov $-1,%rax
mov %rax,%rcx
@ -92,4 +92,4 @@ polluteregisters:
punpcklqdq %xmm0,%xmm6
punpcklqdq %xmm0,%xmm7
.leafepilogue
.endfn polluteregisters,globl
.endfn __polluteregisters,globl