mirror of
https://github.com/jart/cosmopolitan.git
synced 2025-05-23 13:52:28 +00:00
Improve performance of printf functions
This commit is contained in:
parent
b107d2709f
commit
dc6d11a031
39 changed files with 577 additions and 650 deletions
|
@ -8,9 +8,10 @@
|
||||||
╚─────────────────────────────────────────────────────────────────*/
|
╚─────────────────────────────────────────────────────────────────*/
|
||||||
#endif
|
#endif
|
||||||
#include "libc/errno.h"
|
#include "libc/errno.h"
|
||||||
|
#include "libc/fmt/fmt.h"
|
||||||
#include "libc/stdio/stdio.h"
|
#include "libc/stdio/stdio.h"
|
||||||
|
|
||||||
int main() {
|
int main() {
|
||||||
printf("%s \n", "hello world");
|
printf("%`'s\n", "hello\1\2world→→");
|
||||||
return errno;
|
return errno;
|
||||||
}
|
}
|
||||||
|
|
|
@ -228,6 +228,7 @@ int gethostname_bsd(char *, size_t) hidden;
|
||||||
int gethostname_nt(char *, size_t) hidden;
|
int gethostname_nt(char *, size_t) hidden;
|
||||||
size_t __iovec_size(const struct iovec *, size_t) hidden;
|
size_t __iovec_size(const struct iovec *, size_t) hidden;
|
||||||
void __rusage2linux(struct rusage *) hidden;
|
void __rusage2linux(struct rusage *) hidden;
|
||||||
|
ssize_t WritevUninterruptible(int, struct iovec *, int);
|
||||||
|
|
||||||
/*───────────────────────────────────────────────────────────────────────────│─╗
|
/*───────────────────────────────────────────────────────────────────────────│─╗
|
||||||
│ cosmopolitan § syscalls » windows nt » veneers ─╬─│┼
|
│ cosmopolitan § syscalls » windows nt » veneers ─╬─│┼
|
||||||
|
|
|
@ -70,10 +70,6 @@ long double ConvertTicksToNanos(uint64_t ticks) {
|
||||||
return ticks * g_now.cpn; /* pico scale */
|
return ticks * g_now.cpn; /* pico scale */
|
||||||
}
|
}
|
||||||
|
|
||||||
static long double ConvertTicksToSeconds(uint64_t ticks) {
|
|
||||||
return 1 / 1e9 * ConvertTicksToNanos(ticks);
|
|
||||||
}
|
|
||||||
|
|
||||||
long double nowl_sys(void) {
|
long double nowl_sys(void) {
|
||||||
return dtime(CLOCK_REALTIME);
|
return dtime(CLOCK_REALTIME);
|
||||||
}
|
}
|
||||||
|
@ -82,5 +78,5 @@ long double nowl_art(void) {
|
||||||
uint64_t ticks;
|
uint64_t ticks;
|
||||||
if (!g_now.once) RefreshTime();
|
if (!g_now.once) RefreshTime();
|
||||||
ticks = unsignedsubtract(rdtsc(), g_now.k0);
|
ticks = unsignedsubtract(rdtsc(), g_now.k0);
|
||||||
return g_now.r0 + ConvertTicksToSeconds(ticks);
|
return g_now.r0 + (1 / 1e9L * (ticks * g_now.cpn));
|
||||||
}
|
}
|
||||||
|
|
|
@ -22,43 +22,55 @@
|
||||||
#include "libc/limits.h"
|
#include "libc/limits.h"
|
||||||
#include "libc/macros.internal.h"
|
#include "libc/macros.internal.h"
|
||||||
#include "libc/nt/files.h"
|
#include "libc/nt/files.h"
|
||||||
|
#include "libc/sock/sock.h"
|
||||||
|
#include "libc/str/str.h"
|
||||||
#include "libc/sysv/errfuns.h"
|
#include "libc/sysv/errfuns.h"
|
||||||
|
|
||||||
struct VdprintfState {
|
struct VdprintfState {
|
||||||
int n;
|
int n, t, fd;
|
||||||
int fd;
|
char b[1024];
|
||||||
unsigned char buf[1024];
|
|
||||||
};
|
};
|
||||||
|
|
||||||
static int vdprintf_flush(struct VdprintfState *df, int n) {
|
static int vdprintf_putc(const char *s, struct VdprintfState *t, size_t n) {
|
||||||
int i, rc;
|
struct iovec iov[2];
|
||||||
for (i = 0; i < n; i += rc) {
|
if (n) {
|
||||||
if ((rc = write(df->fd, df->buf + i, n - i)) == -1) {
|
if (t->n + n < sizeof(t->b)) {
|
||||||
|
memcpy(t->b + t->n, s, n);
|
||||||
|
t->n += n;
|
||||||
|
} else {
|
||||||
|
iov[0].iov_base = t->b;
|
||||||
|
iov[0].iov_len = t->n;
|
||||||
|
iov[1].iov_base = s;
|
||||||
|
iov[1].iov_len = n;
|
||||||
|
if (WritevUninterruptible(t->fd, iov, 2) == -1) {
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
t->t += t->n;
|
||||||
|
t->n = 0;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int vdprintf_putc(int c, struct VdprintfState *df) {
|
|
||||||
df->buf[df->n++ & (ARRAYLEN(df->buf) - 1)] = c & 0xff;
|
|
||||||
if ((df->n & (ARRAYLEN(df->buf) - 1))) {
|
|
||||||
return 0;
|
|
||||||
} else {
|
|
||||||
return vdprintf_flush(df, ARRAYLEN(df->buf));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Formats string directly to system i/o device.
|
* Formats string directly to system i/o device.
|
||||||
* @asyncsignalsafe
|
* @asyncsignalsafe
|
||||||
* @vforksafe
|
* @vforksafe
|
||||||
*/
|
*/
|
||||||
int(vdprintf)(int fd, const char *fmt, va_list va) {
|
int(vdprintf)(int fd, const char *fmt, va_list va) {
|
||||||
struct VdprintfState df;
|
struct iovec iov[1];
|
||||||
df.n = 0;
|
struct VdprintfState t;
|
||||||
df.fd = fd;
|
t.n = 0;
|
||||||
if (__fmt(vdprintf_putc, &df, fmt, va) == -1) return -1;
|
t.t = 0;
|
||||||
if (vdprintf_flush(&df, df.n & (ARRAYLEN(df.buf) - 1)) == -1) return -1;
|
t.fd = fd;
|
||||||
return df.n;
|
if (__fmt(vdprintf_putc, &t, fmt, va) == -1) return -1;
|
||||||
|
if (t.n) {
|
||||||
|
iov[0].iov_base = t.b;
|
||||||
|
iov[0].iov_len = t.n;
|
||||||
|
if (WritevUninterruptible(t.fd, iov, 1) == -1) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
t.t += t.n;
|
||||||
|
}
|
||||||
|
return t.t;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
/*-*- mode:unix-assembly; indent-tabs-mode:t; tab-width:8; coding:utf-8 -*-│
|
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
|
||||||
│vi: set et ft=asm ts=8 tw=8 fenc=utf-8 :vi│
|
│vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi│
|
||||||
╞══════════════════════════════════════════════════════════════════════════════╡
|
╞══════════════════════════════════════════════════════════════════════════════╡
|
||||||
│ Copyright 2020 Justine Alexandra Roberts Tunney │
|
│ Copyright 2021 Justine Alexandra Roberts Tunney │
|
||||||
│ │
|
│ │
|
||||||
│ Permission to use, copy, modify, and/or distribute this software for │
|
│ Permission to use, copy, modify, and/or distribute this software for │
|
||||||
│ any purpose with or without fee is hereby granted, provided that the │
|
│ any purpose with or without fee is hereby granted, provided that the │
|
||||||
|
@ -16,28 +16,30 @@
|
||||||
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
||||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||||
#include "libc/dce.h"
|
#include "libc/calls/internal.h"
|
||||||
#include "libc/macros.internal.h"
|
#include "libc/errno.h"
|
||||||
#include "libc/nexgen32e/x86feature.h"
|
#include "libc/sock/sock.h"
|
||||||
#include "libc/notice.inc"
|
|
||||||
|
|
||||||
// Computes 32-bit Castagnoli Cyclic Redundancy Check.
|
ssize_t WritevUninterruptible(int fd, struct iovec *iov, int iovlen) {
|
||||||
//
|
ssize_t rc;
|
||||||
// @param edi is the initial hash value (0 is fine)
|
size_t wrote;
|
||||||
// @param rsi points to the data
|
do {
|
||||||
// @param rdx is the byte size of data
|
if ((rc = writev(fd, iov, iovlen)) != -1) {
|
||||||
// @return eax is the new hash value
|
wrote = rc;
|
||||||
// @note Used by ISCSI, TensorFlow, etc.
|
do {
|
||||||
.initbss 300,_init_crc32c
|
if (wrote >= iov->iov_len) {
|
||||||
crc32c: .quad 0
|
wrote -= iov->iov_len;
|
||||||
.endobj crc32c,globl
|
++iov;
|
||||||
.previous
|
--iovlen;
|
||||||
|
} else {
|
||||||
.init.start 300,_init_crc32c
|
iov->iov_base = (char *)iov->iov_base + wrote;
|
||||||
ezlea crc32c_pure,ax
|
iov->iov_len -= wrote;
|
||||||
ezlea crc32c_sse42,cx
|
wrote = 0;
|
||||||
testb X86_HAVE(SSE4_2)+kCpuids(%rip)
|
}
|
||||||
cmovnz %rcx,%rax
|
} while (wrote);
|
||||||
stosq
|
} else if (errno != EINTR) {
|
||||||
.init.end 300,_init_crc32c
|
return -1;
|
||||||
.source __FILE__
|
}
|
||||||
|
} while (iovlen);
|
||||||
|
return 0;
|
||||||
|
}
|
|
@ -23,6 +23,7 @@
|
||||||
#include "libc/fmt/fmt.h"
|
#include "libc/fmt/fmt.h"
|
||||||
#include "libc/fmt/fmts.h"
|
#include "libc/fmt/fmts.h"
|
||||||
#include "libc/fmt/internal.h"
|
#include "libc/fmt/internal.h"
|
||||||
|
#include "libc/fmt/itoa.h"
|
||||||
#include "libc/macros.internal.h"
|
#include "libc/macros.internal.h"
|
||||||
#include "libc/mem/mem.h"
|
#include "libc/mem/mem.h"
|
||||||
#include "libc/nexgen32e/bsr.h"
|
#include "libc/nexgen32e/bsr.h"
|
||||||
|
@ -33,7 +34,8 @@
|
||||||
|
|
||||||
#define PUT(C) \
|
#define PUT(C) \
|
||||||
do { \
|
do { \
|
||||||
if (out(C, arg) == -1) { \
|
char Buf[1] = {C}; \
|
||||||
|
if (out(Buf, arg, 1) == -1) { \
|
||||||
return -1; \
|
return -1; \
|
||||||
} \
|
} \
|
||||||
} while (0)
|
} while (0)
|
||||||
|
@ -121,14 +123,18 @@ hidden int __fmt(void *fn, void *arg, const char *format, va_list va) {
|
||||||
uint32_t u[2];
|
uint32_t u[2];
|
||||||
uint64_t q;
|
uint64_t q;
|
||||||
} pun;
|
} pun;
|
||||||
|
long ld;
|
||||||
void *p;
|
void *p;
|
||||||
|
unsigned u;
|
||||||
|
char ibuf[21];
|
||||||
bool longdouble;
|
bool longdouble;
|
||||||
long double ldbl;
|
long double ldbl;
|
||||||
|
unsigned long lu;
|
||||||
wchar_t charbuf[1];
|
wchar_t charbuf[1];
|
||||||
const char *alphabet;
|
const char *alphabet;
|
||||||
int (*out)(long, void *);
|
int (*out)(const char *, void *, size_t);
|
||||||
unsigned char signbit, log2base;
|
unsigned char signbit, log2base;
|
||||||
int c, d, k, w, i1, ui, bw, bex;
|
int c, d, k, w, n, i1, ui, bw, bex;
|
||||||
char *s, *q, *se, qchar, special[8];
|
char *s, *q, *se, qchar, special[8];
|
||||||
int sgn, alt, sign, prec, prec1, flags, width, decpt, lasterr;
|
int sgn, alt, sign, prec, prec1, flags, width, decpt, lasterr;
|
||||||
|
|
||||||
|
@ -136,18 +142,64 @@ hidden int __fmt(void *fn, void *arg, const char *format, va_list va) {
|
||||||
out = fn ? fn : (void *)missingno;
|
out = fn ? fn : (void *)missingno;
|
||||||
|
|
||||||
while (*format) {
|
while (*format) {
|
||||||
/* %[flags][width][.prec][length] */
|
|
||||||
if (*format != '%') {
|
if (*format != '%') {
|
||||||
/* no */
|
for (n = 1; format[n]; ++n) {
|
||||||
PUT(*format);
|
if (format[n] == '%') break;
|
||||||
format++;
|
}
|
||||||
|
if (out(format, arg, n) == -1) return -1;
|
||||||
|
format += n;
|
||||||
continue;
|
continue;
|
||||||
} else {
|
|
||||||
/* yes, evaluate it */
|
|
||||||
format++;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* evaluate flags */
|
if (!IsTiny()) {
|
||||||
|
if (format[1] == 's') { /* FAST PATH: PLAIN STRING */
|
||||||
|
s = va_arg(va, char *);
|
||||||
|
if (!s) s = "(null)";
|
||||||
|
if (out(s, arg, strlen(s)) == -1) return -1;
|
||||||
|
format += 2;
|
||||||
|
continue;
|
||||||
|
} else if (format[1] == 'd') { /* FAST PATH: PLAIN INTEGER */
|
||||||
|
d = va_arg(va, int);
|
||||||
|
if (out(ibuf, arg, int64toarray_radix10(d, ibuf)) == -1) return -1;
|
||||||
|
format += 2;
|
||||||
|
continue;
|
||||||
|
} else if (format[1] == 'u') { /* FAST PATH: PLAIN UNSIGNED */
|
||||||
|
u = va_arg(va, unsigned);
|
||||||
|
if (out(ibuf, arg, uint64toarray_radix10(u, ibuf)) == -1) return -1;
|
||||||
|
format += 2;
|
||||||
|
continue;
|
||||||
|
} else if (format[1] == 'x') { /* FAST PATH: PLAIN HEX */
|
||||||
|
u = va_arg(va, unsigned);
|
||||||
|
if (out(ibuf, arg, uint64toarray_radix16(u, ibuf)) == -1) return -1;
|
||||||
|
format += 2;
|
||||||
|
continue;
|
||||||
|
} else if (format[1] == 'l' && format[2] == 'x') {
|
||||||
|
lu = va_arg(va, unsigned long); /* FAST PATH: PLAIN LONG HEX */
|
||||||
|
if (out(ibuf, arg, uint64toarray_radix16(lu, ibuf)) == -1) return -1;
|
||||||
|
format += 3;
|
||||||
|
continue;
|
||||||
|
} else if (format[1] == 'l' && format[2] == 'd') {
|
||||||
|
ld = va_arg(va, long); /* FAST PATH: PLAIN LONG */
|
||||||
|
if (out(ibuf, arg, int64toarray_radix10(ld, ibuf)) == -1) return -1;
|
||||||
|
format += 3;
|
||||||
|
continue;
|
||||||
|
} else if (format[1] == 'l' && format[2] == 'u') {
|
||||||
|
lu = va_arg(va, unsigned long); /* FAST PATH: PLAIN UNSIGNED LONG */
|
||||||
|
if (out(ibuf, arg, int64toarray_radix10(lu, ibuf)) == -1) return -1;
|
||||||
|
format += 3;
|
||||||
|
continue;
|
||||||
|
} else if (format[1] == '.' && format[2] == '*' && format[3] == 's') {
|
||||||
|
n = va_arg(va, unsigned); /* FAST PATH: PRECISION STRING */
|
||||||
|
s = va_arg(va, const char *);
|
||||||
|
if (!s) s = "(null)", n = MIN(6, n);
|
||||||
|
if (out(s, arg, n) == -1) return -1;
|
||||||
|
format += 4;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* GENERAL PATH */
|
||||||
|
format++;
|
||||||
sign = 0;
|
sign = 0;
|
||||||
flags = 0;
|
flags = 0;
|
||||||
getflag:
|
getflag:
|
||||||
|
|
|
@ -6,13 +6,14 @@
|
||||||
#if !(__ASSEMBLER__ + __LINKER__ + 0)
|
#if !(__ASSEMBLER__ + __LINKER__ + 0)
|
||||||
COSMOPOLITAN_C_START_
|
COSMOPOLITAN_C_START_
|
||||||
|
|
||||||
int __fmt_pad(int (*)(long, void *), void *, unsigned long) hidden;
|
int __fmt_pad(int (*)(const char *, void *, size_t), void *,
|
||||||
int __fmt_stoa(int (*)(long, void *), void *, void *, unsigned long,
|
unsigned long) hidden;
|
||||||
unsigned long, unsigned long, unsigned char,
|
int __fmt_stoa(int (*)(const char *, void *, size_t), void *, void *,
|
||||||
unsigned char) hidden;
|
|
||||||
int __fmt_ntoa(int (*)(long, void *), void *, va_list, unsigned char,
|
|
||||||
unsigned long, unsigned long, unsigned long, unsigned char,
|
unsigned long, unsigned long, unsigned long, unsigned char,
|
||||||
const char *) hidden;
|
unsigned char) hidden;
|
||||||
|
int __fmt_ntoa(int (*)(const char *, void *, size_t), void *, va_list,
|
||||||
|
unsigned char, unsigned long, unsigned long, unsigned long,
|
||||||
|
unsigned char, const char *) hidden;
|
||||||
char *__fmt_dtoa(double, int, int, int *, int *, char **) hidden;
|
char *__fmt_dtoa(double, int, int, int *, int *, char **) hidden;
|
||||||
|
|
||||||
COSMOPOLITAN_C_END_
|
COSMOPOLITAN_C_END_
|
||||||
|
|
|
@ -16,6 +16,7 @@
|
||||||
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
||||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||||
|
#include "libc/alg/reverse.internal.h"
|
||||||
#include "libc/assert.h"
|
#include "libc/assert.h"
|
||||||
#include "libc/fmt/conv.h"
|
#include "libc/fmt/conv.h"
|
||||||
#include "libc/fmt/fmts.h"
|
#include "libc/fmt/fmts.h"
|
||||||
|
@ -25,12 +26,11 @@
|
||||||
|
|
||||||
uintmax_t __udivmodti4(uintmax_t, uintmax_t, uintmax_t *);
|
uintmax_t __udivmodti4(uintmax_t, uintmax_t, uintmax_t *);
|
||||||
|
|
||||||
static int __fmt_ntoa_format(int out(long, void *), void *arg, char *buf,
|
static int __fmt_ntoa_format(int out(const char *, void *, size_t), void *arg,
|
||||||
unsigned len, bool negative, unsigned log2base,
|
char *buf, unsigned len, bool negative,
|
||||||
unsigned prec, unsigned width,
|
unsigned log2base, unsigned prec, unsigned width,
|
||||||
unsigned char flags) {
|
unsigned char flags) {
|
||||||
unsigned i, idx;
|
unsigned i;
|
||||||
idx = 0;
|
|
||||||
|
|
||||||
/* pad leading zeros */
|
/* pad leading zeros */
|
||||||
if (!(flags & FLAGS_LEFT)) {
|
if (!(flags & FLAGS_LEFT)) {
|
||||||
|
@ -82,24 +82,21 @@ static int __fmt_ntoa_format(int out(long, void *), void *arg, char *buf,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* reverse string */
|
reverse(buf, len);
|
||||||
for (i = 0U; i < len; i++) {
|
if (out(buf, arg, len) == -1) return -1;
|
||||||
if (out(buf[len - i - 1], arg) == -1) return -1;
|
|
||||||
idx++;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* append pad spaces up to given width */
|
/* append pad spaces up to given width */
|
||||||
if (flags & FLAGS_LEFT) {
|
if (flags & FLAGS_LEFT) {
|
||||||
if (idx < width) {
|
if (len < width) {
|
||||||
if (__fmt_pad(out, arg, width - idx) == -1) return -1;
|
if (__fmt_pad(out, arg, width - len) == -1) return -1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int __fmt_ntoa2(int out(long, void *), void *arg, uintmax_t value, bool neg,
|
int __fmt_ntoa2(int out(const char *, void *, size_t), void *arg,
|
||||||
unsigned log2base, unsigned prec, unsigned width,
|
uintmax_t value, bool neg, unsigned log2base, unsigned prec,
|
||||||
unsigned flags, const char *alphabet) {
|
unsigned width, unsigned flags, const char *alphabet) {
|
||||||
uintmax_t remainder;
|
uintmax_t remainder;
|
||||||
unsigned len, count, digit;
|
unsigned len, count, digit;
|
||||||
char buf[BUFFER_SIZE];
|
char buf[BUFFER_SIZE];
|
||||||
|
@ -130,7 +127,7 @@ int __fmt_ntoa2(int out(long, void *), void *arg, uintmax_t value, bool neg,
|
||||||
flags);
|
flags);
|
||||||
}
|
}
|
||||||
|
|
||||||
int __fmt_ntoa(int out(long, void *), void *arg, va_list va,
|
int __fmt_ntoa(int out(const char *, void *, size_t), void *arg, va_list va,
|
||||||
unsigned char signbit, unsigned long log2base,
|
unsigned char signbit, unsigned long log2base,
|
||||||
unsigned long prec, unsigned long width, unsigned char flags,
|
unsigned long prec, unsigned long width, unsigned char flags,
|
||||||
const char *lang) {
|
const char *lang) {
|
||||||
|
|
|
@ -18,8 +18,9 @@
|
||||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||||
#include "libc/fmt/fmts.h"
|
#include "libc/fmt/fmts.h"
|
||||||
|
|
||||||
int __fmt_pad(int out(long, void *), void *arg, unsigned long n) {
|
int __fmt_pad(int out(const char *, void *, size_t), void *arg,
|
||||||
|
unsigned long n) {
|
||||||
int i, rc;
|
int i, rc;
|
||||||
for (rc = i = 0; i < n; ++i) rc |= out(' ', arg);
|
for (rc = i = 0; i < n; ++i) rc |= out(" ", arg, 1);
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
|
@ -16,9 +16,12 @@
|
||||||
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
||||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||||
|
#include "libc/bits/bits.h"
|
||||||
|
#include "libc/bits/safemacros.internal.h"
|
||||||
#include "libc/bits/weaken.h"
|
#include "libc/bits/weaken.h"
|
||||||
#include "libc/fmt/fmts.h"
|
#include "libc/fmt/fmts.h"
|
||||||
#include "libc/fmt/internal.h"
|
#include "libc/fmt/internal.h"
|
||||||
|
#include "libc/nexgen32e/bsr.h"
|
||||||
#include "libc/nexgen32e/tinystrlen.internal.h"
|
#include "libc/nexgen32e/tinystrlen.internal.h"
|
||||||
#include "libc/str/str.h"
|
#include "libc/str/str.h"
|
||||||
#include "libc/str/thompike.h"
|
#include "libc/str/thompike.h"
|
||||||
|
@ -26,56 +29,50 @@
|
||||||
#include "libc/str/utf16.h"
|
#include "libc/str/utf16.h"
|
||||||
#include "libc/unicode/unicode.h"
|
#include "libc/unicode/unicode.h"
|
||||||
|
|
||||||
typedef int (*emit_f)(int (*)(long, void *), void *, wint_t);
|
typedef int (*out_f)(const char *, void *, size_t);
|
||||||
|
typedef int (*emit_f)(out_f, void *, uint64_t);
|
||||||
|
|
||||||
static noinstrument int __fmt_stoa_byte(int f(long, void *), void *a,
|
static int __fmt_stoa_byte(out_f out, void *a, uint64_t c) {
|
||||||
wint_t c) {
|
char buf[1] = {c};
|
||||||
return f(c, a);
|
return out(buf, a, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
static noinstrument int __fmt_stoa_word(int f(long, void *), void *a,
|
static int __fmt_stoa_wide(out_f out, void *a, uint64_t w) {
|
||||||
uint64_t w) {
|
char buf[8];
|
||||||
do {
|
if (!isascii(w)) w = tpenc(w);
|
||||||
if (f(w & 0xff, a) == -1) {
|
WRITE64LE(buf, w);
|
||||||
return -1;
|
return out(buf, a, w ? (bsr(w) >> 3) + 1 : 1);
|
||||||
}
|
|
||||||
} while ((w >>= 8));
|
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static noinstrument int __fmt_stoa_wide(int f(long, void *), void *a,
|
static int __fmt_stoa_bing(out_f out, void *a, uint64_t w) {
|
||||||
wint_t c) {
|
char buf[8];
|
||||||
if (isascii(c)) {
|
w = tpenc((*weaken(kCp437))[w & 0xFF]);
|
||||||
return f(c, a);
|
WRITE64LE(buf, w);
|
||||||
|
return out(buf, a, w ? (bsr(w) >> 3) + 1 : 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int __fmt_stoa_quoted(out_f out, void *a, uint64_t w) {
|
||||||
|
char buf[8];
|
||||||
|
if (w <= 0x7F) {
|
||||||
|
if (w < 0x20 || w == 0x7F) {
|
||||||
|
w = cescapec(w);
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
return __fmt_stoa_word(f, a, tpenc(c));
|
w = tpenc(w);
|
||||||
}
|
}
|
||||||
|
WRITE64LE(buf, w);
|
||||||
|
return out(buf, a, w ? (bsr(w) >> 3) + 1 : 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
static noinstrument int __fmt_stoa_bing(int f(long, void *), void *a,
|
static int __fmt_stoa_quote(out_f out, void *arg, unsigned flags, char ch,
|
||||||
wint_t c) {
|
|
||||||
return __fmt_stoa_wide(f, a, (*weaken(kCp437))[c]);
|
|
||||||
}
|
|
||||||
|
|
||||||
static noinstrument int __fmt_stoa_quoted(int f(long, void *), void *a,
|
|
||||||
wint_t c) {
|
|
||||||
if (isascii(c)) {
|
|
||||||
return __fmt_stoa_word(f, a, cescapec(c));
|
|
||||||
} else {
|
|
||||||
return __fmt_stoa_word(f, a, tpenc(c));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static noinstrument int __fmt_stoa_quote(int out(long, void *), void *arg,
|
|
||||||
unsigned flags, char ch,
|
|
||||||
unsigned char signbit) {
|
unsigned char signbit) {
|
||||||
if (flags & FLAGS_REPR) {
|
if (flags & FLAGS_REPR) {
|
||||||
if (signbit == 63) {
|
if (signbit == 63) {
|
||||||
if (out('L', arg) == -1) return -1;
|
if (out("L", arg, 1) == -1) return -1;
|
||||||
} else if (signbit == 15) {
|
} else if (signbit == 15) {
|
||||||
if (out('u', arg) == -1) return -1;
|
if (out("u", arg, 1) == -1) return -1;
|
||||||
}
|
}
|
||||||
if (out(ch, arg) == -1) return -1;
|
if (out(&ch, arg, 1) == -1) return -1;
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -89,23 +86,25 @@ static noinstrument int __fmt_stoa_quote(int out(long, void *), void *arg,
|
||||||
*
|
*
|
||||||
* @see __fmt()
|
* @see __fmt()
|
||||||
*/
|
*/
|
||||||
int __fmt_stoa(int out(long, void *), void *arg, void *data,
|
int __fmt_stoa(int out(const char *, void *, size_t), void *arg, void *data,
|
||||||
unsigned long flags, unsigned long precision,
|
unsigned long flags, unsigned long precision,
|
||||||
unsigned long width, unsigned char signbit,
|
unsigned long width, unsigned char signbit,
|
||||||
unsigned char qchar) {
|
unsigned char qchar) {
|
||||||
char *p;
|
|
||||||
wint_t wc;
|
wint_t wc;
|
||||||
unsigned n;
|
unsigned n;
|
||||||
emit_f emit;
|
emit_f emit;
|
||||||
|
char *p, buf[1];
|
||||||
unsigned w, c, pad;
|
unsigned w, c, pad;
|
||||||
bool justdobytes, ignorenul;
|
bool justdobytes, ignorenul;
|
||||||
|
|
||||||
p = data;
|
p = data;
|
||||||
if (!p) {
|
if (!p) {
|
||||||
p = ((flags & FLAGS_REPR) ? "NULL" : "(null)");
|
p = ((flags & FLAGS_REPR) ? "NULL" : "(null)");
|
||||||
flags &= ~FLAGS_PRECISION;
|
|
||||||
flags |= FLAGS_NOQUOTE;
|
|
||||||
signbit = 0;
|
signbit = 0;
|
||||||
|
flags |= FLAGS_NOQUOTE;
|
||||||
|
if (flags & FLAGS_PRECISION) {
|
||||||
|
precision = min(strlen(p), precision);
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
if (__fmt_stoa_quote(out, arg, flags, qchar, signbit) == -1) return -1;
|
if (__fmt_stoa_quote(out, arg, flags, qchar, signbit) == -1) return -1;
|
||||||
}
|
}
|
||||||
|
@ -215,7 +214,8 @@ int __fmt_stoa(int out(long, void *), void *arg, void *data,
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!(flags & FLAGS_NOQUOTE) && (flags & FLAGS_REPR)) {
|
if (!(flags & FLAGS_NOQUOTE) && (flags & FLAGS_REPR)) {
|
||||||
if (out(qchar, arg) == -1) return -1;
|
buf[0] = qchar;
|
||||||
|
if (out(buf, arg, 1) == -1) return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|
|
@ -16,10 +16,10 @@
|
||||||
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
||||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||||
#include "libc/bits/safemacros.internal.h"
|
|
||||||
#include "libc/dce.h"
|
#include "libc/dce.h"
|
||||||
#include "libc/fmt/fmt.h"
|
#include "libc/fmt/fmt.h"
|
||||||
#include "libc/limits.h"
|
#include "libc/limits.h"
|
||||||
|
#include "libc/macros.internal.h"
|
||||||
#include "libc/runtime/runtime.h"
|
#include "libc/runtime/runtime.h"
|
||||||
|
|
||||||
struct SprintfStr {
|
struct SprintfStr {
|
||||||
|
@ -28,10 +28,13 @@ struct SprintfStr {
|
||||||
size_t n;
|
size_t n;
|
||||||
};
|
};
|
||||||
|
|
||||||
static noinstrument int vsnprintfputchar(unsigned char c,
|
static int vsnprintfputchar(const char *s, struct SprintfStr *t, size_t n) {
|
||||||
struct SprintfStr *str) {
|
if (t->i + n <= t->n) {
|
||||||
if (str->i < str->n) str->p[str->i] = c;
|
memcpy(t->p + t->i, s, n);
|
||||||
str->i++;
|
} else if (t->i < t->n) {
|
||||||
|
memcpy(t->p + t->i, s, t->n - t->i);
|
||||||
|
}
|
||||||
|
t->i += n;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -51,6 +54,6 @@ static noinstrument int vsnprintfputchar(unsigned char c,
|
||||||
int(vsnprintf)(char *buf, size_t size, const char *fmt, va_list va) {
|
int(vsnprintf)(char *buf, size_t size, const char *fmt, va_list va) {
|
||||||
struct SprintfStr str = {buf, 0, size};
|
struct SprintfStr str = {buf, 0, size};
|
||||||
__fmt(vsnprintfputchar, &str, fmt, va);
|
__fmt(vsnprintfputchar, &str, fmt, va);
|
||||||
if (str.n) str.p[min(str.i, str.n - 1)] = '\0';
|
if (str.n) str.p[MIN(str.i, str.n - 1)] = '\0';
|
||||||
return str.i;
|
return str.i;
|
||||||
}
|
}
|
||||||
|
|
|
@ -16,7 +16,10 @@
|
||||||
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
||||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||||
|
#include "libc/bits/safemacros.internal.h"
|
||||||
#include "libc/dce.h"
|
#include "libc/dce.h"
|
||||||
|
#include "libc/log/color.internal.h"
|
||||||
|
#include "libc/log/log.h"
|
||||||
#include "libc/runtime/runtime.h"
|
#include "libc/runtime/runtime.h"
|
||||||
#include "libc/str/str.h"
|
#include "libc/str/str.h"
|
||||||
|
|
||||||
|
@ -43,17 +46,8 @@
|
||||||
bool cancolor(void) {
|
bool cancolor(void) {
|
||||||
static bool once;
|
static bool once;
|
||||||
static bool result;
|
static bool result;
|
||||||
const char *term;
|
|
||||||
if (!once) {
|
if (!once) {
|
||||||
if (!result) {
|
result = !!strcmp(nulltoempty(getenv("DONTANSIMEBRO")), "1");
|
||||||
if ((term = getenv("TERM"))) {
|
|
||||||
/* anything but emacs basically */
|
|
||||||
result = strcmp(term, "dumb") != 0;
|
|
||||||
} else {
|
|
||||||
/* TODO(jart): Why does Mac bash login shell exec nuke TERM? */
|
|
||||||
result = IsXnu();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
once = true;
|
once = true;
|
||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
|
|
|
@ -21,9 +21,6 @@
|
||||||
#include "libc/runtime/runtime.h"
|
#include "libc/runtime/runtime.h"
|
||||||
#include "libc/str/str.h"
|
#include "libc/str/str.h"
|
||||||
|
|
||||||
/**
|
|
||||||
* Checks if we're probably running inside Emacs.
|
|
||||||
*/
|
|
||||||
bool IsTerminalInarticulate(void) {
|
bool IsTerminalInarticulate(void) {
|
||||||
return strcmp(nulltoempty(getenv("TERM")), "dumb") == 0;
|
return !strcmp(nulltoempty(getenv("TERM")), "dumb");
|
||||||
}
|
}
|
||||||
|
|
|
@ -29,26 +29,26 @@
|
||||||
* @see xasprintf() for a better API
|
* @see xasprintf() for a better API
|
||||||
*/
|
*/
|
||||||
int(vasprintf)(char **strp, const char *fmt, va_list va) {
|
int(vasprintf)(char **strp, const char *fmt, va_list va) {
|
||||||
int wrote;
|
|
||||||
char *p;
|
char *p;
|
||||||
size_t size;
|
size_t size;
|
||||||
va_list va2;
|
va_list vb;
|
||||||
|
int wrote, rc = -1;
|
||||||
if ((*strp = malloc((size = 512)))) {
|
if ((*strp = malloc((size = 512)))) {
|
||||||
va_copy(va2, va);
|
va_copy(vb, va);
|
||||||
wrote = (vsnprintf)(*strp, size, fmt, va);
|
wrote = (vsnprintf)(*strp, size, fmt, va);
|
||||||
if (wrote == -1) return -1;
|
|
||||||
if (wrote < size) {
|
if (wrote < size) {
|
||||||
if ((p = realloc(*strp, wrote + 1))) *strp = p;
|
if ((p = realloc(*strp, wrote + 1))) *strp = p;
|
||||||
return wrote;
|
rc = wrote;
|
||||||
} else {
|
} else {
|
||||||
size = wrote + 1;
|
size = wrote + 1;
|
||||||
if ((p = realloc(*strp, size))) {
|
if ((p = realloc(*strp, size))) {
|
||||||
*strp = p;
|
*strp = p;
|
||||||
wrote = (vsnprintf)(*strp, size, fmt, va2);
|
wrote = (vsnprintf)(*strp, size, fmt, vb);
|
||||||
assert(wrote == size - 1);
|
assert(wrote == size - 1);
|
||||||
return wrote;
|
rc = wrote;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
va_end(vb);
|
||||||
}
|
}
|
||||||
return -1;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
|
@ -27,6 +27,8 @@
|
||||||
// @param dil contains byte to escape
|
// @param dil contains byte to escape
|
||||||
// @see libc/nexgen32e/cescapec.c
|
// @see libc/nexgen32e/cescapec.c
|
||||||
cescapec:
|
cescapec:
|
||||||
|
.leafprologue
|
||||||
|
.profilable
|
||||||
movzbl %dil,%edi
|
movzbl %dil,%edi
|
||||||
lea -7(%rdi),%ecx
|
lea -7(%rdi),%ecx
|
||||||
cmp $85,%cl
|
cmp $85,%cl
|
||||||
|
@ -36,28 +38,28 @@ cescapec:
|
||||||
jmp *cescapectab(,%rcx,8)
|
jmp *cescapectab(,%rcx,8)
|
||||||
.Lanchorpoint:
|
.Lanchorpoint:
|
||||||
.LBEL: mov $'a',%ah
|
.LBEL: mov $'a',%ah
|
||||||
ret
|
.leafepilogue
|
||||||
.LBS: mov $'b',%ah
|
.LBS: mov $'b',%ah
|
||||||
ret
|
.leafepilogue
|
||||||
.LHT: mov $'t',%ah
|
.LHT: mov $'t',%ah
|
||||||
ret
|
.leafepilogue
|
||||||
.LLF: mov $'n',%ah
|
.LLF: mov $'n',%ah
|
||||||
ret
|
.leafepilogue
|
||||||
.LVT: mov $'v',%ah
|
.LVT: mov $'v',%ah
|
||||||
ret
|
.leafepilogue
|
||||||
.LFF: mov $'f',%ah
|
.LFF: mov $'f',%ah
|
||||||
ret
|
.leafepilogue
|
||||||
.LCR: mov $'r',%ah
|
.LCR: mov $'r',%ah
|
||||||
ret
|
.leafepilogue
|
||||||
.LDQ: mov $'\"',%ah
|
.LDQ: mov $'\"',%ah
|
||||||
ret
|
.leafepilogue
|
||||||
.LSQ: mov $'\'',%ah
|
.LSQ: mov $'\'',%ah
|
||||||
ret
|
.leafepilogue
|
||||||
.LBSL: mov $'\\',%ah
|
.LBSL: mov $'\\',%ah
|
||||||
ret
|
.leafepilogue
|
||||||
#ifdef __STRICT_ANSI__
|
#ifdef __STRICT_ANSI__
|
||||||
.LQM: mov $'?',%ah
|
.LQM: mov $'?',%ah
|
||||||
ret
|
.leafepilogue
|
||||||
#else
|
#else
|
||||||
.LQM:
|
.LQM:
|
||||||
#endif
|
#endif
|
||||||
|
@ -65,7 +67,7 @@ cescapec:
|
||||||
lea -0x20(%rax),%ecx
|
lea -0x20(%rax),%ecx
|
||||||
cmp $0x5E,%ecx
|
cmp $0x5E,%ecx
|
||||||
ja 2f
|
ja 2f
|
||||||
ret
|
.leafepilogue
|
||||||
2: and $-64,%eax
|
2: and $-64,%eax
|
||||||
mov %edi,%ecx
|
mov %edi,%ecx
|
||||||
and $56,%ecx
|
and $56,%ecx
|
||||||
|
@ -75,7 +77,7 @@ cescapec:
|
||||||
or %ecx,%edi
|
or %ecx,%edi
|
||||||
lea (%rdi,%rax,4),%eax
|
lea (%rdi,%rax,4),%eax
|
||||||
add $'0'<<030|'0'<<020|'0'<<010|'\\',%eax
|
add $'0'<<030|'0'<<020|'0'<<010|'\\',%eax
|
||||||
ret
|
.leafepilogue
|
||||||
.endfn cescapec,globl
|
.endfn cescapec,globl
|
||||||
|
|
||||||
.initro 300,_init_cescapec
|
.initro 300,_init_cescapec
|
||||||
|
|
|
@ -3,6 +3,8 @@
|
||||||
#if !(__ASSEMBLER__ + __LINKER__ + 0)
|
#if !(__ASSEMBLER__ + __LINKER__ + 0)
|
||||||
COSMOPOLITAN_C_START_
|
COSMOPOLITAN_C_START_
|
||||||
|
|
||||||
|
extern const uint32_t kCrc32cTab[256];
|
||||||
|
|
||||||
void crc32init(uint32_t[hasatleast 256], uint32_t);
|
void crc32init(uint32_t[hasatleast 256], uint32_t);
|
||||||
uint32_t crc32c(uint32_t, const void *, size_t);
|
uint32_t crc32c(uint32_t, const void *, size_t);
|
||||||
uint32_t crc32_z(uint32_t, const void *, size_t);
|
uint32_t crc32_z(uint32_t, const void *, size_t);
|
||||||
|
|
|
@ -28,7 +28,8 @@
|
||||||
// @return rax is address of last %sil in %rdi, or NULL
|
// @return rax is address of last %sil in %rdi, or NULL
|
||||||
// @note AVX2 requires Haswell (2014+) or Excavator (2015+)
|
// @note AVX2 requires Haswell (2014+) or Excavator (2015+)
|
||||||
// @asyncsignalsafe
|
// @asyncsignalsafe
|
||||||
memrchr:.leafprologue
|
memrchr:
|
||||||
|
.leafprologue
|
||||||
.profilable
|
.profilable
|
||||||
#if !IsTiny()
|
#if !IsTiny()
|
||||||
cmp $32,%rdx
|
cmp $32,%rdx
|
||||||
|
|
|
@ -106,37 +106,7 @@ privileged noasan void ftrace(void) {
|
||||||
noreentry = 0;
|
noreentry = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
textstartup void ftrace_install(void) {
|
||||||
* Enables plaintext function tracing if `--ftrace` flag is passed.
|
|
||||||
*
|
|
||||||
* The `--ftrace` CLI arg is removed before main() is called. This code
|
|
||||||
* is intended for diagnostic purposes and assumes binaries are
|
|
||||||
* trustworthy and stack isn't corrupted. Logging plain text allows
|
|
||||||
* program structure to easily be visualized and hotspots identified w/
|
|
||||||
* `sed | sort | uniq -c | sort`. A compressed trace can be made by
|
|
||||||
* appending `--ftrace 2>&1 | gzip -4 >trace.gz` to the CLI arguments.
|
|
||||||
*
|
|
||||||
* @see libc/runtime/_init.S for documentation
|
|
||||||
*/
|
|
||||||
textstartup int ftrace_init(int argc, char *argv[]) {
|
|
||||||
int i;
|
|
||||||
bool foundflag;
|
|
||||||
foundflag = false;
|
|
||||||
for (i = 1; i <= argc; ++i) {
|
|
||||||
if (!foundflag) {
|
|
||||||
if (argv[i]) {
|
|
||||||
if (strcmp(argv[i], "--ftrace") == 0) {
|
|
||||||
foundflag = true;
|
|
||||||
} else if (strcmp(argv[i], "----ftrace") == 0) {
|
|
||||||
strcpy(argv[i], "--ftrace");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
argv[i - 1] = argv[i];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (foundflag) {
|
|
||||||
--argc;
|
|
||||||
g_buf[0] = '+';
|
g_buf[0] = '+';
|
||||||
g_buf[1] = ' ';
|
g_buf[1] = ' ';
|
||||||
if ((g_symbols = OpenSymbolTable(FindDebugBinary()))) {
|
if ((g_symbols = OpenSymbolTable(FindDebugBinary()))) {
|
||||||
|
@ -145,5 +115,3 @@ textstartup int ftrace_init(int argc, char *argv[]) {
|
||||||
write(2, "error: --ftrace needs the concomitant .com.dbg binary\n", 54);
|
write(2, "error: --ftrace needs the concomitant .com.dbg binary\n", 54);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return argc;
|
|
||||||
}
|
|
||||||
|
|
56
libc/runtime/ftraceinit.c
Normal file
56
libc/runtime/ftraceinit.c
Normal file
|
@ -0,0 +1,56 @@
|
||||||
|
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
|
||||||
|
│vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi│
|
||||||
|
╞══════════════════════════════════════════════════════════════════════════════╡
|
||||||
|
│ Copyright 2021 Justine Alexandra Roberts Tunney │
|
||||||
|
│ │
|
||||||
|
│ Permission to use, copy, modify, and/or distribute this software for │
|
||||||
|
│ any purpose with or without fee is hereby granted, provided that the │
|
||||||
|
│ above copyright notice and this permission notice appear in all copies. │
|
||||||
|
│ │
|
||||||
|
│ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL │
|
||||||
|
│ WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED │
|
||||||
|
│ WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE │
|
||||||
|
│ AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL │
|
||||||
|
│ DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR │
|
||||||
|
│ PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER │
|
||||||
|
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
||||||
|
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||||
|
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||||
|
#include "libc/runtime/runtime.h"
|
||||||
|
#include "libc/str/str.h"
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Enables plaintext function tracing if `--ftrace` flag is passed.
|
||||||
|
*
|
||||||
|
* The `--ftrace` CLI arg is removed before main() is called. This code
|
||||||
|
* is intended for diagnostic purposes and assumes binaries are
|
||||||
|
* trustworthy and stack isn't corrupted. Logging plain text allows
|
||||||
|
* program structure to easily be visualized and hotspots identified w/
|
||||||
|
* `sed | sort | uniq -c | sort`. A compressed trace can be made by
|
||||||
|
* appending `--ftrace 2>&1 | gzip -4 >trace.gz` to the CLI arguments.
|
||||||
|
*
|
||||||
|
* @see libc/runtime/_init.S for documentation
|
||||||
|
*/
|
||||||
|
textstartup int ftrace_init(int argc, char *argv[]) {
|
||||||
|
int i;
|
||||||
|
bool foundflag;
|
||||||
|
foundflag = false;
|
||||||
|
for (i = 1; i <= argc; ++i) {
|
||||||
|
if (!foundflag) {
|
||||||
|
if (argv[i]) {
|
||||||
|
if (strcmp(argv[i], "--ftrace") == 0) {
|
||||||
|
foundflag = true;
|
||||||
|
} else if (strcmp(argv[i], "----ftrace") == 0) {
|
||||||
|
strcpy(argv[i], "--ftrace");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
argv[i - 1] = argv[i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (foundflag) {
|
||||||
|
--argc;
|
||||||
|
ftrace_install();
|
||||||
|
}
|
||||||
|
return argc;
|
||||||
|
}
|
|
@ -88,6 +88,7 @@ void _weakfree(void *);
|
||||||
void free_s(void *) paramsnonnull() libcesque;
|
void free_s(void *) paramsnonnull() libcesque;
|
||||||
int close_s(int *) paramsnonnull() libcesque;
|
int close_s(int *) paramsnonnull() libcesque;
|
||||||
int OpenExecutable(void);
|
int OpenExecutable(void);
|
||||||
|
void ftrace_install(void);
|
||||||
|
|
||||||
COSMOPOLITAN_C_END_
|
COSMOPOLITAN_C_END_
|
||||||
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
|
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
|
||||||
|
|
|
@ -17,6 +17,7 @@
|
||||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||||
#include "libc/calls/calls.h"
|
#include "libc/calls/calls.h"
|
||||||
|
#include "libc/calls/internal.h"
|
||||||
#include "libc/calls/struct/iovec.h"
|
#include "libc/calls/struct/iovec.h"
|
||||||
#include "libc/errno.h"
|
#include "libc/errno.h"
|
||||||
#include "libc/fmt/conv.h"
|
#include "libc/fmt/conv.h"
|
||||||
|
@ -28,30 +29,6 @@
|
||||||
#include "libc/str/str.h"
|
#include "libc/str/str.h"
|
||||||
#include "libc/sysv/consts/o.h"
|
#include "libc/sysv/consts/o.h"
|
||||||
|
|
||||||
static ssize_t WritevAll(int fd, struct iovec *iov, int iovlen) {
|
|
||||||
ssize_t rc;
|
|
||||||
size_t wrote;
|
|
||||||
do {
|
|
||||||
if ((rc = writev(fd, iov, iovlen)) != -1) {
|
|
||||||
wrote = rc;
|
|
||||||
do {
|
|
||||||
if (wrote >= iov->iov_len) {
|
|
||||||
wrote -= iov->iov_len;
|
|
||||||
++iov;
|
|
||||||
--iovlen;
|
|
||||||
} else {
|
|
||||||
iov->iov_base = (char *)iov->iov_base + wrote;
|
|
||||||
iov->iov_len -= wrote;
|
|
||||||
wrote = 0;
|
|
||||||
}
|
|
||||||
} while (wrote);
|
|
||||||
} else if (errno != EINTR) {
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
} while (iovlen);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Writes data to stream.
|
* Writes data to stream.
|
||||||
*
|
*
|
||||||
|
@ -102,7 +79,7 @@ size_t fwrite(const void *data, size_t stride, size_t count, FILE *f) {
|
||||||
iov[1].iov_base = data;
|
iov[1].iov_base = data;
|
||||||
iov[1].iov_len = n;
|
iov[1].iov_len = n;
|
||||||
n += f->beg;
|
n += f->beg;
|
||||||
if (WritevAll(f->fd, iov, 2) == -1) {
|
if (WritevUninterruptible(f->fd, iov, 2) == -1) {
|
||||||
f->state = errno;
|
f->state = errno;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
|
@ -16,6 +16,7 @@
|
||||||
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
||||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||||
|
#include "libc/calls/calls.h"
|
||||||
#include "libc/fmt/fmt.h"
|
#include "libc/fmt/fmt.h"
|
||||||
#include "libc/limits.h"
|
#include "libc/limits.h"
|
||||||
#include "libc/stdio/stdio.h"
|
#include "libc/stdio/stdio.h"
|
||||||
|
@ -26,9 +27,17 @@ struct state {
|
||||||
int n;
|
int n;
|
||||||
};
|
};
|
||||||
|
|
||||||
static noinstrument int vfprintfputchar(int c, struct state *st) {
|
static int vfprintfputchar(const char *s, struct state *t, size_t n) {
|
||||||
st->n++;
|
if (n) {
|
||||||
return fputc(c, st->f);
|
if (n == 1 && *s != '\n' && t->f->beg < t->f->size &&
|
||||||
|
t->f->bufmode != _IONBF) {
|
||||||
|
t->f->buf[t->f->beg++] = *s;
|
||||||
|
} else if (!fwrite(s, 1, n, t->f)) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
t->n += n;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int(vfprintf)(FILE *f, const char *fmt, va_list va) {
|
int(vfprintf)(FILE *f, const char *fmt, va_list va) {
|
||||||
|
|
|
@ -1,79 +0,0 @@
|
||||||
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
|
|
||||||
│vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi│
|
|
||||||
╞══════════════════════════════════════════════════════════════════════════════╡
|
|
||||||
│ Copyright 2020 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/nexgen32e/crc32.h"
|
|
||||||
|
|
||||||
extern const uint32_t kCrc32cTab[256];
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Computes Castagnoli CRC-32 on old computers.
|
|
||||||
*/
|
|
||||||
uint32_t crc32c_pure(uint32_t init, const void *data, size_t size) {
|
|
||||||
const unsigned char *p = data;
|
|
||||||
uint32_t h = init ^ 0xffffffff;
|
|
||||||
unsigned i;
|
|
||||||
for (i = 0; i < size; i++) {
|
|
||||||
h = h >> 8 ^ kCrc32cTab[(h & 0xff) ^ p[i]];
|
|
||||||
}
|
|
||||||
return h ^ 0xffffffff;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
bench_crc32c_pure for #c per n where c ≈ 0.293ns
|
|
||||||
N x1 x8 x64 mBps
|
|
||||||
------------------------------------------------------------
|
|
||||||
1 4305.000 91.375 44.203 74
|
|
||||||
1 75.000 55.875 44.703 73
|
|
||||||
2 46.500 35.188 24.617 132
|
|
||||||
3 40.333 26.625 19.193 169
|
|
||||||
4 32.250 19.969 16.215 200
|
|
||||||
7 18.429 15.089 12.033 270
|
|
||||||
8 20.625 13.547 11.607 280
|
|
||||||
15 15.667 10.775 9.589 339
|
|
||||||
16 17.562 10.695 9.419 345
|
|
||||||
31 12.226 8.891 8.317 391
|
|
||||||
32 13.219 8.480 8.078 402
|
|
||||||
63 9.571 8.065 7.731 420
|
|
||||||
64 9.672 7.955 7.633 426
|
|
||||||
127 8.433 7.548 7.329 443
|
|
||||||
128 8.492 7.528 7.352 442
|
|
||||||
255 7.557 7.366 7.239 449
|
|
||||||
256 7.699 7.342 7.305 445
|
|
||||||
511 7.376 7.243 7.223 450
|
|
||||||
512 7.408 7.233 7.225 450
|
|
||||||
1023 7.188 7.192 7.098 458
|
|
||||||
1024 7.171 7.194 7.097 458
|
|
||||||
2047 7.130 7.172 7.085 459
|
|
||||||
2048 7.117 7.170 7.169 453
|
|
||||||
4095 7.063 7.076 7.085 459
|
|
||||||
4096 7.078 7.161 7.081 459
|
|
||||||
8191 7.041 7.095 7.055 461
|
|
||||||
8192 7.051 7.098 7.087 459
|
|
||||||
16383 7.039 7.114 7.067 460
|
|
||||||
16384 6.876 6.931 7.133 456
|
|
||||||
32767 7.055 7.108 7.290 446
|
|
||||||
32768 6.868 6.887 6.974 466
|
|
||||||
65535 6.984 6.885 6.967 467
|
|
||||||
65536 6.877 6.924 10.994 296
|
|
||||||
131071 7.166 7.141 7.011 464
|
|
||||||
131072 6.853 6.971 7.694 422
|
|
||||||
262143 6.853 7.213 7.406 439
|
|
||||||
262144 6.852 6.968 7.290 446
|
|
||||||
524287 7.398 7.389 7.166 454
|
|
||||||
524288 6.851 7.094 7.159 454
|
|
||||||
*/
|
|
|
@ -1,95 +0,0 @@
|
||||||
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
|
|
||||||
│vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi│
|
|
||||||
╞══════════════════════════════════════════════════════════════════════════════╡
|
|
||||||
│ Copyright 2020 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/str/internal.h"
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Hashes data with hardware acceleration at 10GBps.
|
|
||||||
* @note needs Nehalem+ c. 2008 or Bulldozer+ c. 2011
|
|
||||||
*/
|
|
||||||
optimizespeed uint32_t crc32c_sse42(uint32_t init, const void *data, size_t n) {
|
|
||||||
const unsigned char *p = (const unsigned char *)data;
|
|
||||||
const unsigned char *pe = (const unsigned char *)data + n;
|
|
||||||
uint32_t h = init ^ 0xffffffff;
|
|
||||||
if (n >= 16 + 8) {
|
|
||||||
while ((uintptr_t)p & 7) asm("crc32b\t%1,%0" : "+r"(h) : "rm"(*p++));
|
|
||||||
uint64_t hl = h;
|
|
||||||
while (p < pe - 16ul) {
|
|
||||||
asm("crc32q\t%1,%0" : "+r"(hl) : "rm"(*(const uint64_t *)p));
|
|
||||||
p += 8;
|
|
||||||
asm("crc32q\t%1,%0" : "+r"(hl) : "rm"(*(const uint64_t *)p));
|
|
||||||
p += 8;
|
|
||||||
}
|
|
||||||
h = (uint32_t)hl;
|
|
||||||
}
|
|
||||||
while (p < pe) asm("crc32b\t%1,%0" : "+r"(h) : "rm"(*p++));
|
|
||||||
return h ^ 0xffffffff;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
bench_crc32c_sse42 for #c per n where c ≈ 0.293ns
|
|
||||||
N x1 x8 x64 mBps
|
|
||||||
------------------------------------------------------------
|
|
||||||
1 877.000 43.375 40.359 81
|
|
||||||
1 45.000 39.625 40.484 80
|
|
||||||
2 34.500 27.562 20.461 159
|
|
||||||
3 23.000 16.708 14.245 228
|
|
||||||
4 18.250 13.094 11.449 284
|
|
||||||
7 10.429 8.339 8.185 397
|
|
||||||
8 42.125 8.734 6.850 475
|
|
||||||
15 9.400 5.375 4.884 665
|
|
||||||
16 7.312 5.070 4.882 666
|
|
||||||
31 5.258 2.923 2.680 1213
|
|
||||||
32 3.969 2.676 2.562 1269
|
|
||||||
63 3.095 1.581 1.428 2276
|
|
||||||
64 2.234 1.623 1.478 2199
|
|
||||||
127 1.205 0.901 0.900 3610
|
|
||||||
128 1.164 0.960 0.915 3552
|
|
||||||
255 0.922 0.651 0.618 5260
|
|
||||||
256 0.715 0.650 0.609 5341
|
|
||||||
511 0.558 0.482 0.477 6819
|
|
||||||
512 0.529 0.475 0.469 6932
|
|
||||||
1023 0.425 0.400 0.396 8204
|
|
||||||
1024 0.417 0.392 0.388 8383
|
|
||||||
2047 0.367 0.355 0.353 9199
|
|
||||||
2048 0.374 0.366 0.364 8929
|
|
||||||
4095 0.351 0.338 0.337 9644
|
|
||||||
4096 0.353 0.338 0.338 9624
|
|
||||||
8191 0.335 0.338 0.337 9641
|
|
||||||
8192 0.335 0.329 0.329 9870
|
|
||||||
16383 0.336 0.325 0.325 10011
|
|
||||||
16384 0.336 0.326 0.375 8666
|
|
||||||
32767 0.329 0.323 0.323 10070
|
|
||||||
32768 0.327 0.324 0.323 10062
|
|
||||||
65535 0.322 0.322 0.322 10103
|
|
||||||
65536 0.321 0.322 0.322 10102
|
|
||||||
131071 0.322 0.321 0.321 10125
|
|
||||||
131072 0.321 0.321 0.321 10124
|
|
||||||
262143 0.322 0.321 0.335 9699
|
|
||||||
262144 0.321 0.321 0.321 10134
|
|
||||||
524287 0.321 0.321 0.499 6516
|
|
||||||
524288 0.321 0.321 0.339 9575
|
|
||||||
1048575 0.322 0.321 0.322 10095
|
|
||||||
1048576 0.320 1.001 0.323 10048
|
|
||||||
2097151 0.325 0.321 0.322 10086
|
|
||||||
2097152 0.330 0.320 0.323 10076
|
|
||||||
4194303 0.331 0.322 0.321 10128
|
|
||||||
4194304 0.332 0.321 0.325 10004
|
|
||||||
8388607 0.334 0.332 0.331 9829
|
|
||||||
8388608 0.334 0.329 0.327 9934
|
|
||||||
*/
|
|
|
@ -22,16 +22,29 @@
|
||||||
/**
|
/**
|
||||||
* Computes 32-bit Castagnoli Cyclic Redundancy Check.
|
* Computes 32-bit Castagnoli Cyclic Redundancy Check.
|
||||||
*
|
*
|
||||||
* @param h is the initial hash value (0 is fine)
|
* @param init is the initial hash value
|
||||||
* @param p points to the data
|
* @param data points to the data
|
||||||
* @param n is the byte size of data
|
* @param size is the byte size of data
|
||||||
* @return eax is the new hash value
|
* @return eax is the new hash value
|
||||||
* @note Used by ISCSI, TensorFlow, etc.
|
* @note Used by ISCSI, TensorFlow, etc.
|
||||||
*/
|
*/
|
||||||
uint32_t crc32c(uint32_t h, const void *p, size_t n) {
|
uint32_t crc32c(uint32_t init, const void *data, size_t size) {
|
||||||
|
uint64_t h;
|
||||||
|
const unsigned char *p, *pe;
|
||||||
|
p = data;
|
||||||
|
pe = p + size;
|
||||||
|
h = init ^ 0xffffffff;
|
||||||
if (X86_HAVE(SSE4_2)) {
|
if (X86_HAVE(SSE4_2)) {
|
||||||
return crc32c_sse42(h, p, n);
|
for (; p + 8 <= pe; p += 8) {
|
||||||
|
asm("crc32q\t%1,%0" : "+r"(h) : "rm"(*(const uint64_t *)p));
|
||||||
|
}
|
||||||
|
while (p < pe) {
|
||||||
|
asm("crc32b\t%1,%0" : "+r"(h) : "rm"(*p++));
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
return crc32c_pure(h, p, n);
|
while (p < pe) {
|
||||||
|
h = h >> 8 ^ kCrc32cTab[(h & 0xff) ^ *p++];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
return h ^ 0xffffffff;
|
||||||
|
}
|
||||||
|
|
|
@ -20,7 +20,7 @@
|
||||||
#include "libc/intrin/pmovmskb.h"
|
#include "libc/intrin/pmovmskb.h"
|
||||||
#include "libc/str/str.h"
|
#include "libc/str/str.h"
|
||||||
|
|
||||||
static noasan size_t stpcpy_sse2(char *d, const char *s, size_t i) {
|
static inline noasan size_t stpcpy_sse2(char *d, const char *s, size_t i) {
|
||||||
uint8_t v1[16], v2[16], vz[16];
|
uint8_t v1[16], v2[16], vz[16];
|
||||||
for (;;) {
|
for (;;) {
|
||||||
memset(vz, 0, 16);
|
memset(vz, 0, 16);
|
||||||
|
|
|
@ -26,11 +26,11 @@
|
||||||
*/
|
*/
|
||||||
int CategorizeIp(uint32_t x) {
|
int CategorizeIp(uint32_t x) {
|
||||||
int a;
|
int a;
|
||||||
if (IsAnonymousIp(x)) return kIpAnonymous;
|
|
||||||
if (IsMulticastIp(x)) return kIpMulticast;
|
|
||||||
if (IsLoopbackIp(x)) return kIpLoopback;
|
if (IsLoopbackIp(x)) return kIpLoopback;
|
||||||
if (IsPrivateIp(x)) return kIpPrivate;
|
if (IsPrivateIp(x)) return kIpPrivate;
|
||||||
if (IsTestnetIp(x)) return kIpTestnet;
|
if (IsMulticastIp(x)) return kIpMulticast;
|
||||||
|
if (IsAnonymousIp(x)) return kIpAnonymous; /* order matters */
|
||||||
|
if (IsTestnetIp(x)) return kIpTestnet; /* order matters */
|
||||||
if (IsAfrinicIp(x)) return kIpAfrinic;
|
if (IsAfrinicIp(x)) return kIpAfrinic;
|
||||||
if (IsLacnicIp(x)) return kIpLacnic;
|
if (IsLacnicIp(x)) return kIpLacnic;
|
||||||
if (IsApnicIp(x)) return kIpApnic;
|
if (IsApnicIp(x)) return kIpApnic;
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
/* ANSI-C code produced by gperf version 3.1 */
|
/* ANSI-C code produced by gperf version 3.1 */
|
||||||
/* Command-line: gperf gethttpheader.gperf */
|
/* Command-line: gperf gethttpheader.gperf */
|
||||||
/* Computed positions: -k'3-4,10' */
|
/* Computed positions: -k'3-4,10' */
|
||||||
|
/* clang-format off */
|
||||||
|
|
||||||
#if !((' ' == 32) && ('!' == 33) && ('"' == 34) && ('#' == 35) \
|
#if !((' ' == 32) && ('!' == 33) && ('"' == 34) && ('#' == 35) \
|
||||||
&& ('%' == 37) && ('&' == 38) && ('\'' == 39) && ('(' == 40) \
|
&& ('%' == 37) && ('&' == 38) && ('\'' == 39) && ('(' == 40) \
|
||||||
|
@ -71,7 +72,7 @@ static unsigned char gperf_downcase[256] =
|
||||||
|
|
||||||
#ifndef GPERF_CASE_STRNCMP
|
#ifndef GPERF_CASE_STRNCMP
|
||||||
#define GPERF_CASE_STRNCMP 1
|
#define GPERF_CASE_STRNCMP 1
|
||||||
static int
|
static inline int
|
||||||
gperf_case_strncmp (register const char *s1, register const char *s2, register size_t n)
|
gperf_case_strncmp (register const char *s1, register const char *s2, register size_t n)
|
||||||
{
|
{
|
||||||
for (; n > 0;)
|
for (; n > 0;)
|
||||||
|
@ -152,7 +153,7 @@ hash (register const char *str, register size_t len)
|
||||||
return hval;
|
return hval;
|
||||||
}
|
}
|
||||||
|
|
||||||
const struct thatispacked HttpHeaderSlot *
|
static inline const struct thatispacked HttpHeaderSlot *
|
||||||
LookupHttpHeader (register const char *str, register size_t len)
|
LookupHttpHeader (register const char *str, register size_t len)
|
||||||
{
|
{
|
||||||
static const struct thatispacked HttpHeaderSlot wordlist[] =
|
static const struct thatispacked HttpHeaderSlot wordlist[] =
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
/* ANSI-C code produced by gperf version 3.1 */
|
/* ANSI-C code produced by gperf version 3.1 */
|
||||||
/* Command-line: gperf gethttpmethod.gperf */
|
/* Command-line: gperf gethttpmethod.gperf */
|
||||||
/* Computed positions: -k'1-2' */
|
/* Computed positions: -k'1-2' */
|
||||||
|
/* clang-format off */
|
||||||
|
|
||||||
#if !((' ' == 32) && ('!' == 33) && ('"' == 34) && ('#' == 35) \
|
#if !((' ' == 32) && ('!' == 33) && ('"' == 34) && ('#' == 35) \
|
||||||
&& ('%' == 37) && ('&' == 38) && ('\'' == 39) && ('(' == 40) \
|
&& ('%' == 37) && ('&' == 38) && ('\'' == 39) && ('(' == 40) \
|
||||||
|
@ -71,7 +72,7 @@ static unsigned char gperf_downcase[256] =
|
||||||
|
|
||||||
#ifndef GPERF_CASE_STRNCMP
|
#ifndef GPERF_CASE_STRNCMP
|
||||||
#define GPERF_CASE_STRNCMP 1
|
#define GPERF_CASE_STRNCMP 1
|
||||||
static int
|
static inline int
|
||||||
gperf_case_strncmp (register const char *s1, register const char *s2, register size_t n)
|
gperf_case_strncmp (register const char *s1, register const char *s2, register size_t n)
|
||||||
{
|
{
|
||||||
for (; n > 0;)
|
for (; n > 0;)
|
||||||
|
@ -131,7 +132,7 @@ hash (register const char *str, register size_t len)
|
||||||
return len + asso_values[(unsigned char)str[1]] + asso_values[(unsigned char)str[0]];
|
return len + asso_values[(unsigned char)str[1]] + asso_values[(unsigned char)str[0]];
|
||||||
}
|
}
|
||||||
|
|
||||||
const struct HttpMethodSlot *
|
static inline const struct HttpMethodSlot *
|
||||||
LookupHttpMethod (register const char *str, register size_t len)
|
LookupHttpMethod (register const char *str, register size_t len)
|
||||||
{
|
{
|
||||||
static const struct HttpMethodSlot wordlist[] =
|
static const struct HttpMethodSlot wordlist[] =
|
||||||
|
@ -153,7 +154,7 @@ LookupHttpMethod (register const char *str, register size_t len)
|
||||||
{""},
|
{""},
|
||||||
#line 27 "gethttpmethod.gperf"
|
#line 27 "gethttpmethod.gperf"
|
||||||
{"NOTIFY", kHttpNotify},
|
{"NOTIFY", kHttpNotify},
|
||||||
#line 20 "gethttpmethod.gperf"
|
#line 19 "gethttpmethod.gperf"
|
||||||
{"OPTIONS", kHttpOptions},
|
{"OPTIONS", kHttpOptions},
|
||||||
{""},
|
{""},
|
||||||
#line 22 "gethttpmethod.gperf"
|
#line 22 "gethttpmethod.gperf"
|
||||||
|
@ -162,7 +163,7 @@ LookupHttpMethod (register const char *str, register size_t len)
|
||||||
{"MERGE", kHttpMerge},
|
{"MERGE", kHttpMerge},
|
||||||
#line 29 "gethttpmethod.gperf"
|
#line 29 "gethttpmethod.gperf"
|
||||||
{"REPORT", kHttpReport},
|
{"REPORT", kHttpReport},
|
||||||
#line 19 "gethttpmethod.gperf"
|
#line 20 "gethttpmethod.gperf"
|
||||||
{"CONNECT", kHttpConnect},
|
{"CONNECT", kHttpConnect},
|
||||||
{""},
|
{""},
|
||||||
#line 26 "gethttpmethod.gperf"
|
#line 26 "gethttpmethod.gperf"
|
||||||
|
|
|
@ -19,6 +19,26 @@
|
||||||
#include "libc/str/str.h"
|
#include "libc/str/str.h"
|
||||||
#include "net/http/http.h"
|
#include "net/http/http.h"
|
||||||
|
|
||||||
|
// -_0-9A-Za-z
|
||||||
|
static const char kHostChars[256] = {
|
||||||
|
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 0x00
|
||||||
|
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 0x10
|
||||||
|
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, // 0x20
|
||||||
|
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, // 0x30
|
||||||
|
0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 0x40
|
||||||
|
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 1, // 0x50
|
||||||
|
0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 0x60
|
||||||
|
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, // 0x70
|
||||||
|
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 0x80
|
||||||
|
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 0x90
|
||||||
|
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 0xa0
|
||||||
|
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 0xb0
|
||||||
|
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 0xc0
|
||||||
|
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 0xd0
|
||||||
|
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 0xe0
|
||||||
|
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 0xf0
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns true if host seems legit.
|
* Returns true if host seems legit.
|
||||||
*
|
*
|
||||||
|
@ -49,18 +69,11 @@
|
||||||
*/
|
*/
|
||||||
bool IsAcceptableHost(const char *s, size_t n) {
|
bool IsAcceptableHost(const char *s, size_t n) {
|
||||||
size_t i;
|
size_t i;
|
||||||
bool isip;
|
|
||||||
int c, b, j;
|
int c, b, j;
|
||||||
if (n == -1) n = s ? strlen(s) : 0;
|
if (n == -1) n = s ? strlen(s) : 0;
|
||||||
if (!n) return true;
|
if (!n) return true;
|
||||||
for (isip = true, b = j = i = 0; i < n; ++i) {
|
for (b = j = i = 0; i < n; ++i) {
|
||||||
c = s[i] & 255;
|
c = s[i] & 255;
|
||||||
if (c == '.' && (!i || s[i - 1] == '.')) {
|
|
||||||
return false;
|
|
||||||
} else if (!(isalnum(c) || c == '-' || c == '_' || c == '.')) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
if (isip) {
|
|
||||||
if (isdigit(c)) {
|
if (isdigit(c)) {
|
||||||
b *= 10;
|
b *= 10;
|
||||||
b += c - '0';
|
b += c - '0';
|
||||||
|
@ -68,14 +81,23 @@ bool IsAcceptableHost(const char *s, size_t n) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
} else if (c == '.') {
|
} else if (c == '.') {
|
||||||
|
if (!i || s[i - 1] == '.') return false;
|
||||||
b = 0;
|
b = 0;
|
||||||
++j;
|
++j;
|
||||||
} else {
|
} else {
|
||||||
isip = false;
|
for (;;) {
|
||||||
|
if (!kHostChars[c] && (c != '.' || (!i || s[i - 1] == '.'))) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (++i < n) {
|
||||||
|
c = s[i] & 255;
|
||||||
|
} else {
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (isip && j != 3) return false;
|
}
|
||||||
|
if (j != 3) return false;
|
||||||
if (i && s[i - 1] == '.') return false;
|
if (i && s[i - 1] == '.') return false;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
|
@ -20,7 +20,10 @@
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns true if IPv4 address can come from the Internet.
|
* Returns true if IPv4 address can come from the Internet.
|
||||||
|
*
|
||||||
|
* We intentionally omit TEST-NET here which can be used to simulate
|
||||||
|
* public Internet traffic using non-Internet IPs.
|
||||||
*/
|
*/
|
||||||
bool IsPublicIp(uint32_t x) {
|
bool IsPublicIp(uint32_t x) {
|
||||||
return !IsLoopbackIp(x) && !IsPrivateIp(x) && !IsTestnetIp(x);
|
return !IsLoopbackIp(x) && !IsPrivateIp(x);
|
||||||
}
|
}
|
||||||
|
|
|
@ -75,7 +75,7 @@ void DestroyHttpRequest(struct HttpRequest *r) {
|
||||||
* fragmented. If a message is valid but incomplete, this function will
|
* fragmented. If a message is valid but incomplete, this function will
|
||||||
* return zero so that it can be resumed as soon as more data arrives.
|
* return zero so that it can be resumed as soon as more data arrives.
|
||||||
*
|
*
|
||||||
* This parser takes about 500 nanoseconds to parse a 403 byte Chrome
|
* This parser takes about 400 nanoseconds to parse a 403 byte Chrome
|
||||||
* HTTP request under MODE=rel on a Core i9 which is about three cycles
|
* HTTP request under MODE=rel on a Core i9 which is about three cycles
|
||||||
* per byte or a gigabyte per second of throughput per core.
|
* per byte or a gigabyte per second of throughput per core.
|
||||||
*
|
*
|
||||||
|
|
|
@ -40,6 +40,8 @@ TEST(uint64toarray_radix10, test) {
|
||||||
char buf[21];
|
char buf[21];
|
||||||
EXPECT_EQ(1, uint64toarray_radix10(0, buf));
|
EXPECT_EQ(1, uint64toarray_radix10(0, buf));
|
||||||
EXPECT_STREQ("0", buf);
|
EXPECT_STREQ("0", buf);
|
||||||
|
EXPECT_EQ(4, uint64toarray_radix10(1024, buf));
|
||||||
|
EXPECT_STREQ("1024", buf);
|
||||||
EXPECT_EQ(20, uint64toarray_radix10(UINT64_MAX, buf));
|
EXPECT_EQ(20, uint64toarray_radix10(UINT64_MAX, buf));
|
||||||
EXPECT_STREQ("18446744073709551615", buf);
|
EXPECT_STREQ("18446744073709551615", buf);
|
||||||
EXPECT_EQ(19, uint64toarray_radix10(INT64_MIN, buf));
|
EXPECT_EQ(19, uint64toarray_radix10(INT64_MIN, buf));
|
||||||
|
|
|
@ -38,8 +38,9 @@
|
||||||
#include "libc/testlib/testlib.h"
|
#include "libc/testlib/testlib.h"
|
||||||
#include "libc/x/x.h"
|
#include "libc/x/x.h"
|
||||||
|
|
||||||
static char buffer[128];
|
char buffer[1000];
|
||||||
#define Format(...) gc(xasprintf(__VA_ARGS__))
|
/* #define Format(...) gc(xasprintf(__VA_ARGS__)) */
|
||||||
|
#define Format(...) (snprintf(buffer, sizeof(buffer), __VA_ARGS__), buffer)
|
||||||
|
|
||||||
TEST(sprintf, test_space_flag) {
|
TEST(sprintf, test_space_flag) {
|
||||||
EXPECT_STREQ(" 42", Format("% d", 42));
|
EXPECT_STREQ(" 42", Format("% d", 42));
|
||||||
|
@ -593,32 +594,14 @@ TEST(snprintf, testFixedWidthString_wontOverrunInput) {
|
||||||
TEST(snprintf, testFixedWidthStringIsNull_wontOverrunBuffer) {
|
TEST(snprintf, testFixedWidthStringIsNull_wontOverrunBuffer) {
|
||||||
int N = 3;
|
int N = 3;
|
||||||
char *buf = malloc(N + 1);
|
char *buf = malloc(N + 1);
|
||||||
EXPECT_EQ(6, snprintf(buf, N + 1, "%.*s", pushpop(N), pushpop(NULL)));
|
EXPECT_EQ(3, snprintf(buf, N + 1, "%.*s", pushpop(N), pushpop(NULL)));
|
||||||
EXPECT_BINEQ(u"(nu ", buf);
|
EXPECT_STREQ("(nu", buf);
|
||||||
EXPECT_EQ(6, snprintf(buf, N + 1, "%#.*s", pushpop(N), pushpop(NULL)));
|
EXPECT_EQ(3, snprintf(buf, N + 1, "%#.*s", pushpop(N), pushpop(NULL)));
|
||||||
EXPECT_BINEQ(u"(nu ", buf);
|
EXPECT_STREQ("(nu", buf);
|
||||||
EXPECT_EQ(4, snprintf(buf, N + 1, "%`.*s", pushpop(N), pushpop(NULL)));
|
EXPECT_EQ(3, snprintf(buf, N + 1, "%`'.*s", pushpop(N), pushpop(NULL)));
|
||||||
EXPECT_BINEQ(u"NUL ", buf);
|
EXPECT_STREQ("NUL", buf);
|
||||||
EXPECT_EQ(4, snprintf(buf, N + 1, "%`#.*s", pushpop(N), pushpop(NULL)));
|
EXPECT_EQ(3, snprintf(buf, N + 1, "%`#.*s", pushpop(N), pushpop(NULL)));
|
||||||
EXPECT_BINEQ(u"NUL ", buf);
|
EXPECT_STREQ("NUL", buf);
|
||||||
free(buf);
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST(snprintf, testFixedWidthStringIsNull_wontLeakMemory) {
|
|
||||||
int N = 16;
|
|
||||||
char *buf = malloc(N + 1);
|
|
||||||
memset(buf, 0, N + 1);
|
|
||||||
EXPECT_EQ(6, snprintf(buf, N + 1, "%.*s", pushpop(N), pushpop(NULL)));
|
|
||||||
EXPECT_BINEQ(u"(null) ", buf);
|
|
||||||
memset(buf, 0, N + 1);
|
|
||||||
EXPECT_EQ(6, snprintf(buf, N + 1, "%#.*s", pushpop(N), pushpop(NULL)));
|
|
||||||
EXPECT_BINEQ(u"(null) ", buf);
|
|
||||||
memset(buf, 0, N + 1);
|
|
||||||
EXPECT_EQ(4, snprintf(buf, N + 1, "%`.*s", pushpop(N), pushpop(NULL)));
|
|
||||||
EXPECT_BINEQ(u"NULL ", buf);
|
|
||||||
memset(buf, 0, N + 1);
|
|
||||||
EXPECT_EQ(4, snprintf(buf, N + 1, "%`#.*s", pushpop(N), pushpop(NULL)));
|
|
||||||
EXPECT_BINEQ(u"NULL ", buf);
|
|
||||||
free(buf);
|
free(buf);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -640,7 +623,9 @@ TEST(palandprintf, precisionStillRespectsNulTerminatorIfNotEscOrRepr) {
|
||||||
}
|
}
|
||||||
|
|
||||||
BENCH(palandprintf, bench) {
|
BENCH(palandprintf, bench) {
|
||||||
|
EZBENCH2("ascii", donothing, Format(VEIL("r", "hiuhcreohucreo")));
|
||||||
EZBENCH2("ascii %s", donothing, Format("%s", VEIL("r", "hiuhcreohucreo")));
|
EZBENCH2("ascii %s", donothing, Format("%s", VEIL("r", "hiuhcreohucreo")));
|
||||||
|
EZBENCH2("ascii %`'s", donothing, Format("%`'s", VEIL("r", "hiuhcreohucre")));
|
||||||
EZBENCH2("utf8 %s", donothing, Format("%s", VEIL("r", "hi (╯°□°)╯")));
|
EZBENCH2("utf8 %s", donothing, Format("%s", VEIL("r", "hi (╯°□°)╯")));
|
||||||
EZBENCH2("snprintf %hs", donothing, Format("%hs", VEIL("r", u"hi (╯°□°)╯")));
|
EZBENCH2("snprintf %hs", donothing, Format("%hs", VEIL("r", u"hi (╯°□°)╯")));
|
||||||
EZBENCH2("snprintf %ls", donothing, Format("%ls", VEIL("r", L"hi (╯°□°)╯")));
|
EZBENCH2("snprintf %ls", donothing, Format("%ls", VEIL("r", L"hi (╯°□°)╯")));
|
||||||
|
@ -648,6 +633,8 @@ BENCH(palandprintf, bench) {
|
||||||
EZBENCH2("23 %d", donothing, Format("%d", VEIL("r", 23)));
|
EZBENCH2("23 %d", donothing, Format("%d", VEIL("r", 23)));
|
||||||
EZBENCH2("INT_MIN %x", donothing, Format("%x", VEIL("r", INT_MIN)));
|
EZBENCH2("INT_MIN %x", donothing, Format("%x", VEIL("r", INT_MIN)));
|
||||||
EZBENCH2("INT_MIN %d", donothing, Format("%d", VEIL("r", INT_MIN)));
|
EZBENCH2("INT_MIN %d", donothing, Format("%d", VEIL("r", INT_MIN)));
|
||||||
|
EZBENCH2("LONG_MIN %x", donothing, Format("%lx", VEIL("r", LONG_MIN)));
|
||||||
|
EZBENCH2("LONG_MIN %d", donothing, Format("%ld", VEIL("r", LONG_MIN)));
|
||||||
EZBENCH2("23 int64toarray", donothing, int64toarray_radix10(23, buffer));
|
EZBENCH2("23 int64toarray", donothing, int64toarray_radix10(23, buffer));
|
||||||
EZBENCH2("INT_MIN int64toarray", donothing,
|
EZBENCH2("INT_MIN int64toarray", donothing,
|
||||||
int64toarray_radix10(INT_MIN, buffer));
|
int64toarray_radix10(INT_MIN, buffer));
|
||||||
|
|
|
@ -20,6 +20,8 @@
|
||||||
#include "libc/nexgen32e/crc32.h"
|
#include "libc/nexgen32e/crc32.h"
|
||||||
#include "libc/nexgen32e/x86feature.h"
|
#include "libc/nexgen32e/x86feature.h"
|
||||||
#include "libc/str/str.h"
|
#include "libc/str/str.h"
|
||||||
|
#include "libc/testlib/ezbench.h"
|
||||||
|
#include "libc/testlib/hyperion.h"
|
||||||
#include "libc/testlib/testlib.h"
|
#include "libc/testlib/testlib.h"
|
||||||
|
|
||||||
#define FANATICS "Fanatics"
|
#define FANATICS "Fanatics"
|
||||||
|
@ -40,12 +42,6 @@ TEST(crc32c, test) {
|
||||||
strlen(hyperion) - strlen(FANATICS)));
|
strlen(hyperion) - strlen(FANATICS)));
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(crc32c_pure, test) {
|
BENCH(crc32c, bench) {
|
||||||
EXPECT_EQ(0, crc32c_pure(0, "", 0));
|
EZBENCH2("crc32c", donothing, crc32c(0, kHyperion, kHyperionSize));
|
||||||
EXPECT_EQ(crc32c_pure(0, "hello", 5), crc32c_pure(0, "hello", 5));
|
|
||||||
EXPECT_EQ(0xe3069283, crc32c_pure(0, "123456789", 9));
|
|
||||||
EXPECT_EQ(0x6d6eefba, crc32c_pure(0, hyperion, strlen(hyperion)));
|
|
||||||
EXPECT_EQ(0x6d6eefba, crc32c_pure(crc32c_pure(0, FANATICS, strlen(FANATICS)),
|
|
||||||
hyperion + strlen(FANATICS),
|
|
||||||
strlen(hyperion) - strlen(FANATICS)));
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -37,7 +37,7 @@ TEST(IsAcceptableHost, test) {
|
||||||
EXPECT_FALSE(IsAcceptableHost("hello.example\300\200", -1));
|
EXPECT_FALSE(IsAcceptableHost("hello.example\300\200", -1));
|
||||||
EXPECT_FALSE(IsAcceptableHost(".", -1));
|
EXPECT_FALSE(IsAcceptableHost(".", -1));
|
||||||
EXPECT_FALSE(IsAcceptableHost(".e", -1));
|
EXPECT_FALSE(IsAcceptableHost(".e", -1));
|
||||||
EXPECT_FALSE(IsAcceptableHost("e.", -1));
|
EXPECT_TRUE(IsAcceptableHost("e.", -1));
|
||||||
EXPECT_FALSE(IsAcceptableHost(".hi.example", -1));
|
EXPECT_FALSE(IsAcceptableHost(".hi.example", -1));
|
||||||
EXPECT_FALSE(IsAcceptableHost("hi..example", -1));
|
EXPECT_FALSE(IsAcceptableHost("hi..example", -1));
|
||||||
EXPECT_TRUE(IsAcceptableHost("hi-there.example", -1));
|
EXPECT_TRUE(IsAcceptableHost("hi-there.example", -1));
|
||||||
|
@ -126,4 +126,6 @@ BENCH(IsAcceptableHost, bench) {
|
||||||
EZBENCH2("IsAcceptablePort 80", donothing, IsAcceptablePort("80", 2));
|
EZBENCH2("IsAcceptablePort 80", donothing, IsAcceptablePort("80", 2));
|
||||||
EZBENCH2("ParseForwarded 80", donothing,
|
EZBENCH2("ParseForwarded 80", donothing,
|
||||||
ParseForwarded("203.0.113.42:31337", 20, &ip, &port));
|
ParseForwarded("203.0.113.42:31337", 20, &ip, &port));
|
||||||
|
EZBENCH2("IsAcceptableHost foo.example", donothing,
|
||||||
|
IsAcceptableHost("foo.example:31337", 17));
|
||||||
}
|
}
|
||||||
|
|
|
@ -80,8 +80,12 @@ o/$(MODE)/tool/net/redbean.com: \
|
||||||
@$(COMPILE) -ADD -T$@ dd if=$@ of=o/$(MODE)/tool/net/.ape bs=64 count=11 conv=notrunc 2>/dev/null
|
@$(COMPILE) -ADD -T$@ dd if=$@ of=o/$(MODE)/tool/net/.ape bs=64 count=11 conv=notrunc 2>/dev/null
|
||||||
@$(COMPILE) -AZIP -T$@ zip -qj $@ o/$(MODE)/tool/net/.ape tool/net/.init.lua tool/net/.reload.lua tool/net/favicon.ico tool/net/redbean.png
|
@$(COMPILE) -AZIP -T$@ zip -qj $@ o/$(MODE)/tool/net/.ape tool/net/.init.lua tool/net/.reload.lua tool/net/favicon.ico tool/net/redbean.png
|
||||||
|
|
||||||
|
o/$(MODE)/tool/net/redbean-demo.com.dbg: \
|
||||||
|
o/$(MODE)/tool/net/redbean.com.dbg
|
||||||
|
@$(COMPILE) -ACP -T$@ cp $< $@
|
||||||
|
|
||||||
o/$(MODE)/tool/net/redbean-demo.com: \
|
o/$(MODE)/tool/net/redbean-demo.com: \
|
||||||
o/$(MODE)/tool/net/redbean.com.dbg \
|
o/$(MODE)/tool/net/redbean-demo.com.dbg \
|
||||||
tool/net/net.mk \
|
tool/net/net.mk \
|
||||||
tool/net/.init.lua \
|
tool/net/.init.lua \
|
||||||
tool/net/.reload.lua \
|
tool/net/.reload.lua \
|
||||||
|
@ -114,16 +118,6 @@ o/$(MODE)/tool/net/redbean-static.com: \
|
||||||
@$(COMPILE) -ADD -T$@ dd if=$@ of=o/$(MODE)/tool/net/.ape bs=64 count=11 conv=notrunc 2>/dev/null
|
@$(COMPILE) -ADD -T$@ dd if=$@ of=o/$(MODE)/tool/net/.ape bs=64 count=11 conv=notrunc 2>/dev/null
|
||||||
@$(COMPILE) -AZIP -T$@ zip -qj $@ o/$(MODE)/tool/net/.ape tool/net/favicon.ico tool/net/redbean.png
|
@$(COMPILE) -AZIP -T$@ zip -qj $@ o/$(MODE)/tool/net/.ape tool/net/favicon.ico tool/net/redbean.png
|
||||||
|
|
||||||
o/$(MODE)/tool/net/redbean-bench.com.dbg: \
|
|
||||||
$(TOOL_NET_DEPS) \
|
|
||||||
o/$(MODE)/tool/net/redbean.o \
|
|
||||||
o/$(MODE)/tool/net/index.html.zip.o \
|
|
||||||
o/$(MODE)/tool/net/redbean.lua.zip.o \
|
|
||||||
o/$(MODE)/tool/net/net.pkg \
|
|
||||||
$(CRT) \
|
|
||||||
$(APE)
|
|
||||||
@$(APELINK)
|
|
||||||
|
|
||||||
o/$(MODE)/tool/net/redbean-static.com.dbg: \
|
o/$(MODE)/tool/net/redbean-static.com.dbg: \
|
||||||
$(TOOL_NET_DEPS) \
|
$(TOOL_NET_DEPS) \
|
||||||
o/$(MODE)/tool/net/redbean-static.o \
|
o/$(MODE)/tool/net/redbean-static.o \
|
||||||
|
|
|
@ -33,6 +33,7 @@
|
||||||
#include "libc/nexgen32e/bsr.h"
|
#include "libc/nexgen32e/bsr.h"
|
||||||
#include "libc/nexgen32e/crc32.h"
|
#include "libc/nexgen32e/crc32.h"
|
||||||
#include "libc/runtime/clktck.h"
|
#include "libc/runtime/clktck.h"
|
||||||
|
#include "libc/runtime/runtime.h"
|
||||||
#include "libc/sock/sock.h"
|
#include "libc/sock/sock.h"
|
||||||
#include "libc/stdio/stdio.h"
|
#include "libc/stdio/stdio.h"
|
||||||
#include "libc/sysv/consts/af.h"
|
#include "libc/sysv/consts/af.h"
|
||||||
|
@ -71,7 +72,11 @@
|
||||||
#define HASH_LOAD_FACTOR /* 1. / */ 4
|
#define HASH_LOAD_FACTOR /* 1. / */ 4
|
||||||
#define DEFAULT_PORT 8080
|
#define DEFAULT_PORT 8080
|
||||||
|
|
||||||
|
#define read(F, P, N) readv(F, &(struct iovec){P, N}, 1)
|
||||||
|
#define Hash(P, N) max(1, crc32c(0, P, N));
|
||||||
#define LockInc(P) asm volatile("lock inc%z0\t%0" : "=m"(*(P)))
|
#define LockInc(P) asm volatile("lock inc%z0\t%0" : "=m"(*(P)))
|
||||||
|
#define AppendCrlf(P) mempcpy(P, "\r\n", 2)
|
||||||
|
#define HasHeader(H) (!!msg.headers[H].a)
|
||||||
#define HeaderData(H) (inbuf.p + msg.headers[H].a)
|
#define HeaderData(H) (inbuf.p + msg.headers[H].a)
|
||||||
#define HeaderLength(H) (msg.headers[H].b - msg.headers[H].a)
|
#define HeaderLength(H) (msg.headers[H].b - msg.headers[H].a)
|
||||||
#define HeaderEqualCase(H, S) \
|
#define HeaderEqualCase(H, S) \
|
||||||
|
@ -171,7 +176,7 @@ static const char kRegCode[][9] = {
|
||||||
};
|
};
|
||||||
|
|
||||||
struct Buffer {
|
struct Buffer {
|
||||||
size_t n;
|
size_t n, c;
|
||||||
char *p;
|
char *p;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -327,6 +332,7 @@ static bool istext;
|
||||||
static bool zombied;
|
static bool zombied;
|
||||||
static bool gzipped;
|
static bool gzipped;
|
||||||
static bool branded;
|
static bool branded;
|
||||||
|
static bool funtrace;
|
||||||
static bool meltdown;
|
static bool meltdown;
|
||||||
static bool heartless;
|
static bool heartless;
|
||||||
static bool printport;
|
static bool printport;
|
||||||
|
@ -385,6 +391,7 @@ static struct Buffer effectivepath;
|
||||||
|
|
||||||
static struct Url url;
|
static struct Url url;
|
||||||
static struct HttpRequest msg;
|
static struct HttpRequest msg;
|
||||||
|
static char slashpath[PATH_MAX];
|
||||||
|
|
||||||
static long double startread;
|
static long double startread;
|
||||||
static long double lastrefresh;
|
static long double lastrefresh;
|
||||||
|
@ -399,7 +406,7 @@ static wontreturn void PrintUsage(FILE *f, int rc) {
|
||||||
fprintf(f, "\
|
fprintf(f, "\
|
||||||
SYNOPSIS\n\
|
SYNOPSIS\n\
|
||||||
\n\
|
\n\
|
||||||
%s [-hvduzmba] [-p PORT] [-- SCRIPTARGS...]\n\
|
%s [-hvduzmbagf] [-p PORT] [-- SCRIPTARGS...]\n\
|
||||||
\n\
|
\n\
|
||||||
DESCRIPTION\n\
|
DESCRIPTION\n\
|
||||||
\n\
|
\n\
|
||||||
|
@ -415,8 +422,11 @@ FLAGS\n\
|
||||||
-m log messages\n\
|
-m log messages\n\
|
||||||
-b log message body\n\
|
-b log message body\n\
|
||||||
-a log resource usage\n\
|
-a log resource usage\n\
|
||||||
-g log handler latency\n\
|
-g log handler latency\n"
|
||||||
-H K:V sets http header globally [repeat]\n\
|
#ifndef TINY
|
||||||
|
" -f log worker function calls\n"
|
||||||
|
#endif
|
||||||
|
" -H K:V sets http header globally [repeat]\n\
|
||||||
-D DIR serve assets from local directory [repeat]\n\
|
-D DIR serve assets from local directory [repeat]\n\
|
||||||
-t MS tunes read and write timeouts [default 30000]\n\
|
-t MS tunes read and write timeouts [default 30000]\n\
|
||||||
-c SEC configures static asset cache-control headers\n\
|
-c SEC configures static asset cache-control headers\n\
|
||||||
|
@ -545,8 +555,6 @@ USAGE\n\
|
||||||
then puts the original back once the program loads. If you want\n\
|
then puts the original back once the program loads. If you want\n\
|
||||||
your redbean to follow the platform-local executable convention\n\
|
your redbean to follow the platform-local executable convention\n\
|
||||||
then delete the /.ape file from zip.\n\
|
then delete the /.ape file from zip.\n\
|
||||||
\n\
|
|
||||||
LEGAL\n\
|
|
||||||
\n\
|
\n\
|
||||||
redbean contains software licensed ISC, MIT, BSD-2, BSD-3, zlib\n\
|
redbean contains software licensed ISC, MIT, BSD-2, BSD-3, zlib\n\
|
||||||
which makes it a permissively licensed gift to anyone who might\n\
|
which makes it a permissively licensed gift to anyone who might\n\
|
||||||
|
@ -664,38 +672,53 @@ static void UseOutput(void) {
|
||||||
contentlength = outbuf.n;
|
contentlength = outbuf.n;
|
||||||
outbuf.p = 0;
|
outbuf.p = 0;
|
||||||
outbuf.n = 0;
|
outbuf.n = 0;
|
||||||
|
outbuf.c = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void DropOutput(void) {
|
static void DropOutput(void) {
|
||||||
free(outbuf.p);
|
free(outbuf.p);
|
||||||
outbuf.p = 0;
|
outbuf.p = 0;
|
||||||
outbuf.n = 0;
|
outbuf.n = 0;
|
||||||
|
outbuf.c = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void ClearOutput(void) {
|
static void ClearOutput(void) {
|
||||||
outbuf.n = 0;
|
outbuf.n = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void Grow(size_t n) {
|
||||||
|
do {
|
||||||
|
if (outbuf.c) {
|
||||||
|
outbuf.c += outbuf.c >> 1;
|
||||||
|
} else {
|
||||||
|
outbuf.c = 16 * 1024;
|
||||||
|
}
|
||||||
|
} while (n > outbuf.c);
|
||||||
|
outbuf.p = xrealloc(outbuf.p, outbuf.c);
|
||||||
|
}
|
||||||
|
|
||||||
static void AppendData(const char *data, size_t size) {
|
static void AppendData(const char *data, size_t size) {
|
||||||
outbuf.p = xrealloc(outbuf.p, outbuf.n + size);
|
size_t n;
|
||||||
|
n = outbuf.n + size;
|
||||||
|
if (n > outbuf.c) Grow(n);
|
||||||
memcpy(outbuf.p + outbuf.n, data, size);
|
memcpy(outbuf.p + outbuf.n, data, size);
|
||||||
outbuf.n += size;
|
outbuf.n = n;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void AppendString(const char *s) {
|
static void Append(const char *fmt, ...) {
|
||||||
AppendData(s, strlen(s));
|
|
||||||
}
|
|
||||||
|
|
||||||
static void AppendFmt(const char *fmt, ...) {
|
|
||||||
int n;
|
int n;
|
||||||
char *p;
|
char *p;
|
||||||
va_list va;
|
va_list va, vb;
|
||||||
va_start(va, fmt);
|
va_start(va, fmt);
|
||||||
n = vasprintf(&p, fmt, va);
|
va_copy(vb, va);
|
||||||
|
n = vsnprintf(outbuf.p + outbuf.n, outbuf.c - outbuf.n, fmt, va);
|
||||||
|
if (n >= outbuf.c - outbuf.n) {
|
||||||
|
Grow(outbuf.n + n + 1);
|
||||||
|
vsnprintf(outbuf.p + outbuf.n, outbuf.c - outbuf.n, fmt, vb);
|
||||||
|
}
|
||||||
|
va_end(vb);
|
||||||
va_end(va);
|
va_end(va);
|
||||||
CHECK_NE(-1, n);
|
outbuf.n += n;
|
||||||
AppendData(p, n);
|
|
||||||
free(p);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static char *MergePaths(const char *p, size_t n, const char *q, size_t m,
|
static char *MergePaths(const char *p, size_t n, const char *q, size_t m,
|
||||||
|
@ -833,10 +856,6 @@ static void DescribeAddress(char buf[32], uint32_t addr, uint16_t port) {
|
||||||
*p++ = '\0';
|
*p++ = '\0';
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool HasHeader(int h) {
|
|
||||||
return !!msg.headers[h].a;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void GetServerAddr(uint32_t *ip, uint16_t *port) {
|
static void GetServerAddr(uint32_t *ip, uint16_t *port) {
|
||||||
*ip = ntohl(serveraddr.sin_addr.s_addr);
|
*ip = ntohl(serveraddr.sin_addr.s_addr);
|
||||||
if (port) *port = ntohs(serveraddr.sin_port);
|
if (port) *port = ntohs(serveraddr.sin_port);
|
||||||
|
@ -975,7 +994,7 @@ static void ProgramHeader(const char *s) {
|
||||||
|
|
||||||
static void GetOpts(int argc, char *argv[]) {
|
static void GetOpts(int argc, char *argv[]) {
|
||||||
int opt;
|
int opt;
|
||||||
while ((opt = getopt(argc, argv, "azhdugvmbl:p:r:R:H:c:L:P:U:G:B:D:t:")) !=
|
while ((opt = getopt(argc, argv, "azhdugvmbfl:p:r:R:H:c:L:P:U:G:B:D:t:")) !=
|
||||||
-1) {
|
-1) {
|
||||||
switch (opt) {
|
switch (opt) {
|
||||||
case 'v':
|
case 'v':
|
||||||
|
@ -1002,6 +1021,9 @@ static void GetOpts(int argc, char *argv[]) {
|
||||||
case 'z':
|
case 'z':
|
||||||
printport = true;
|
printport = true;
|
||||||
break;
|
break;
|
||||||
|
case 'f':
|
||||||
|
funtrace = true;
|
||||||
|
break;
|
||||||
case 'k':
|
case 'k':
|
||||||
encouragekeepalive = true;
|
encouragekeepalive = true;
|
||||||
break;
|
break;
|
||||||
|
@ -1097,53 +1119,53 @@ static void AppendResourceReport(struct rusage *ru, const char *nl) {
|
||||||
long utime, stime;
|
long utime, stime;
|
||||||
long double ticks;
|
long double ticks;
|
||||||
if (ru->ru_maxrss) {
|
if (ru->ru_maxrss) {
|
||||||
AppendFmt("ballooned to %,ldkb in size%s", ru->ru_maxrss, nl);
|
Append("ballooned to %,ldkb in size%s", ru->ru_maxrss, nl);
|
||||||
}
|
}
|
||||||
if ((utime = ru->ru_utime.tv_sec * 1000000 + ru->ru_utime.tv_usec) |
|
if ((utime = ru->ru_utime.tv_sec * 1000000 + ru->ru_utime.tv_usec) |
|
||||||
(stime = ru->ru_stime.tv_sec * 1000000 + ru->ru_stime.tv_usec)) {
|
(stime = ru->ru_stime.tv_sec * 1000000 + ru->ru_stime.tv_usec)) {
|
||||||
ticks = ceill((long double)(utime + stime) / (1000000.L / CLK_TCK));
|
ticks = ceill((long double)(utime + stime) / (1000000.L / CLK_TCK));
|
||||||
AppendFmt("needed %,ldµs cpu (%d%% kernel)%s", utime + stime,
|
Append("needed %,ldµs cpu (%d%% kernel)%s", utime + stime,
|
||||||
(int)((long double)stime / (utime + stime) * 100), nl);
|
(int)((long double)stime / (utime + stime) * 100), nl);
|
||||||
if (ru->ru_idrss) {
|
if (ru->ru_idrss) {
|
||||||
AppendFmt("needed %,ldkb memory on average%s",
|
Append("needed %,ldkb memory on average%s", lroundl(ru->ru_idrss / ticks),
|
||||||
lroundl(ru->ru_idrss / ticks), nl);
|
nl);
|
||||||
}
|
}
|
||||||
if (ru->ru_isrss) {
|
if (ru->ru_isrss) {
|
||||||
AppendFmt("needed %,ldkb stack on average%s",
|
Append("needed %,ldkb stack on average%s", lroundl(ru->ru_isrss / ticks),
|
||||||
lroundl(ru->ru_isrss / ticks), nl);
|
nl);
|
||||||
}
|
}
|
||||||
if (ru->ru_ixrss) {
|
if (ru->ru_ixrss) {
|
||||||
AppendFmt("mapped %,ldkb shared on average%s",
|
Append("mapped %,ldkb shared on average%s", lroundl(ru->ru_ixrss / ticks),
|
||||||
lroundl(ru->ru_ixrss / ticks), nl);
|
nl);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (ru->ru_minflt || ru->ru_majflt) {
|
if (ru->ru_minflt || ru->ru_majflt) {
|
||||||
AppendFmt("caused %,ld page faults (%d%% memcpy)%s",
|
Append("caused %,ld page faults (%d%% memcpy)%s",
|
||||||
ru->ru_minflt + ru->ru_majflt,
|
ru->ru_minflt + ru->ru_majflt,
|
||||||
(int)((long double)ru->ru_minflt /
|
(int)((long double)ru->ru_minflt / (ru->ru_minflt + ru->ru_majflt) *
|
||||||
(ru->ru_minflt + ru->ru_majflt) * 100),
|
100),
|
||||||
nl);
|
nl);
|
||||||
}
|
}
|
||||||
if (ru->ru_nvcsw + ru->ru_nivcsw > 1) {
|
if (ru->ru_nvcsw + ru->ru_nivcsw > 1) {
|
||||||
AppendFmt(
|
Append(
|
||||||
"%,ld context switches (%d%% consensual)%s",
|
"%,ld context switches (%d%% consensual)%s",
|
||||||
ru->ru_nvcsw + ru->ru_nivcsw,
|
ru->ru_nvcsw + ru->ru_nivcsw,
|
||||||
(int)((long double)ru->ru_nvcsw / (ru->ru_nvcsw + ru->ru_nivcsw) * 100),
|
(int)((long double)ru->ru_nvcsw / (ru->ru_nvcsw + ru->ru_nivcsw) * 100),
|
||||||
nl);
|
nl);
|
||||||
}
|
}
|
||||||
if (ru->ru_inblock || ru->ru_oublock) {
|
if (ru->ru_inblock || ru->ru_oublock) {
|
||||||
AppendFmt("performed %,ld read and %,ld write i/o operations%s",
|
Append("performed %,ld read and %,ld write i/o operations%s",
|
||||||
ru->ru_inblock, ru->ru_oublock, nl);
|
ru->ru_inblock, ru->ru_oublock, nl);
|
||||||
}
|
}
|
||||||
if (ru->ru_msgrcv || ru->ru_msgsnd) {
|
if (ru->ru_msgrcv || ru->ru_msgsnd) {
|
||||||
AppendFmt("received %,ld message and sent %,ld%s", ru->ru_msgrcv,
|
Append("received %,ld message and sent %,ld%s", ru->ru_msgrcv,
|
||||||
ru->ru_msgsnd, nl);
|
ru->ru_msgsnd, nl);
|
||||||
}
|
}
|
||||||
if (ru->ru_nsignals) {
|
if (ru->ru_nsignals) {
|
||||||
AppendFmt("received %,ld signals%s", ru->ru_nsignals, nl);
|
Append("received %,ld signals%s", ru->ru_nsignals, nl);
|
||||||
}
|
}
|
||||||
if (ru->ru_nswap) {
|
if (ru->ru_nswap) {
|
||||||
AppendFmt("got swapped %,ld times%s", ru->ru_nswap, nl);
|
Append("got swapped %,ld times%s", ru->ru_nswap, nl);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1237,7 +1259,7 @@ static void ReapZombies(void) {
|
||||||
} while (!terminated);
|
} while (!terminated);
|
||||||
}
|
}
|
||||||
|
|
||||||
static ssize_t WritevAll(int fd, struct iovec *iov, int iovlen) {
|
static inline ssize_t WritevAll(int fd, struct iovec *iov, int iovlen) {
|
||||||
ssize_t rc;
|
ssize_t rc;
|
||||||
size_t wrote;
|
size_t wrote;
|
||||||
do {
|
do {
|
||||||
|
@ -1266,13 +1288,6 @@ static ssize_t WritevAll(int fd, struct iovec *iov, int iovlen) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static uint32_t Hash(const void *data, size_t size) {
|
|
||||||
uint32_t h;
|
|
||||||
h = crc32c(0, data, size);
|
|
||||||
if (!h) h = 1;
|
|
||||||
return h;
|
|
||||||
}
|
|
||||||
|
|
||||||
static bool ClientAcceptsGzip(void) {
|
static bool ClientAcceptsGzip(void) {
|
||||||
return msg.version >= 10 && /* RFC1945 § 3.5 */
|
return msg.version >= 10 && /* RFC1945 § 3.5 */
|
||||||
HeaderHas(&msg, inbuf.p, kHttpAcceptEncoding, "gzip", 4);
|
HeaderHas(&msg, inbuf.p, kHttpAcceptEncoding, "gzip", 4);
|
||||||
|
@ -1453,23 +1468,16 @@ static struct Asset *GetAsset(const char *path, size_t pathlen) {
|
||||||
struct Asset *a;
|
struct Asset *a;
|
||||||
if (!(a = GetAssetFile(path, pathlen))) {
|
if (!(a = GetAssetFile(path, pathlen))) {
|
||||||
if (!(a = GetAssetZip(path, pathlen))) {
|
if (!(a = GetAssetZip(path, pathlen))) {
|
||||||
if (pathlen > 1 && path[pathlen - 1] != '/') {
|
if (pathlen > 1 && path[pathlen - 1] != '/' &&
|
||||||
path2 = xmalloc(pathlen + 1);
|
pathlen + 1 <= sizeof(slashpath)) {
|
||||||
memcpy(mempcpy(path2, path, pathlen), "/", 1);
|
memcpy(mempcpy(slashpath, path, pathlen), "/", 1);
|
||||||
a = GetAssetZip(path2, pathlen + 1);
|
a = GetAssetZip(slashpath, pathlen + 1);
|
||||||
free(path2);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return a;
|
return a;
|
||||||
}
|
}
|
||||||
|
|
||||||
static char *AppendCrlf(char *p) {
|
|
||||||
p[0] = '\r';
|
|
||||||
p[1] = '\n';
|
|
||||||
return p + 2;
|
|
||||||
}
|
|
||||||
|
|
||||||
static bool MustNotIncludeMessageBody(void) { /* RFC2616 § 4.4 */
|
static bool MustNotIncludeMessageBody(void) { /* RFC2616 § 4.4 */
|
||||||
return msg.method == kHttpHead || (100 <= statuscode && statuscode <= 199) ||
|
return msg.method == kHttpHead || (100 <= statuscode && statuscode <= 199) ||
|
||||||
statuscode == 204 || statuscode == 304;
|
statuscode == 204 || statuscode == 304;
|
||||||
|
@ -1523,19 +1531,9 @@ static char *AppendCache(char *p, int64_t seconds) {
|
||||||
return AppendExpires(p, (int64_t)shared->nowish + seconds);
|
return AppendExpires(p, (int64_t)shared->nowish + seconds);
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool IsPublic(void) {
|
|
||||||
uint32_t ip;
|
|
||||||
GetRemoteAddr(&ip, 0);
|
|
||||||
return IsPublicIp(ip);
|
|
||||||
}
|
|
||||||
|
|
||||||
static char *AppendServer(char *p, const char *s) {
|
static char *AppendServer(char *p, const char *s) {
|
||||||
p = stpcpy(p, "Server: ");
|
p = stpcpy(p, "Server: ");
|
||||||
if (IsPublic()) {
|
|
||||||
p = mempcpy(p, s, strchrnul(s, '/') - s);
|
|
||||||
} else {
|
|
||||||
p = stpcpy(p, s);
|
p = stpcpy(p, s);
|
||||||
}
|
|
||||||
return AppendCrlf(p);
|
return AppendCrlf(p);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1658,15 +1656,15 @@ static void AppendLogo(void) {
|
||||||
struct Asset *a;
|
struct Asset *a;
|
||||||
if ((a = GetAsset("/redbean.png", 12)) && (p = LoadAsset(a, &n))) {
|
if ((a = GetAsset("/redbean.png", 12)) && (p = LoadAsset(a, &n))) {
|
||||||
q = EncodeBase64(p, n, &n);
|
q = EncodeBase64(p, n, &n);
|
||||||
AppendString("<img src=\"data:image/png;base64,");
|
Append("<img src=\"data:image/png;base64,");
|
||||||
AppendData(q, n);
|
AppendData(q, n);
|
||||||
AppendString("\">\r\n");
|
Append("\">\r\n");
|
||||||
free(q);
|
free(q);
|
||||||
free(p);
|
free(p);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static ssize_t Send(struct iovec *iov, int iovlen) {
|
static inline ssize_t Send(struct iovec *iov, int iovlen) {
|
||||||
ssize_t rc;
|
ssize_t rc;
|
||||||
if ((rc = WritevAll(client, iov, iovlen)) == -1) {
|
if ((rc = WritevAll(client, iov, iovlen)) == -1) {
|
||||||
if (errno == ECONNRESET) {
|
if (errno == ECONNRESET) {
|
||||||
|
@ -1711,11 +1709,11 @@ static char *CommitOutput(char *p) {
|
||||||
static char *ServeDefaultErrorPage(char *p, unsigned code, const char *reason) {
|
static char *ServeDefaultErrorPage(char *p, unsigned code, const char *reason) {
|
||||||
p = AppendContentType(p, "text/html; charset=ISO-8859-1");
|
p = AppendContentType(p, "text/html; charset=ISO-8859-1");
|
||||||
reason = FreeLater(EscapeHtml(reason, -1, 0));
|
reason = FreeLater(EscapeHtml(reason, -1, 0));
|
||||||
AppendString("\
|
Append("\
|
||||||
<!doctype html>\r\n\
|
<!doctype html>\r\n\
|
||||||
<title>");
|
<title>");
|
||||||
AppendFmt("%d %s", code, reason);
|
Append("%d %s", code, reason);
|
||||||
AppendString("\
|
Append("\
|
||||||
</title>\r\n\
|
</title>\r\n\
|
||||||
<style>\r\n\
|
<style>\r\n\
|
||||||
html { color: #111; font-family: sans-serif; }\r\n\
|
html { color: #111; font-family: sans-serif; }\r\n\
|
||||||
|
@ -1723,8 +1721,8 @@ img { vertical-align: middle; }\r\n\
|
||||||
</style>\r\n\
|
</style>\r\n\
|
||||||
<h1>\r\n");
|
<h1>\r\n");
|
||||||
AppendLogo();
|
AppendLogo();
|
||||||
AppendFmt("%d %s\r\n", code, reason);
|
Append("%d %s\r\n", code, reason);
|
||||||
AppendString("</h1>\r\n");
|
Append("</h1>\r\n");
|
||||||
UseOutput();
|
UseOutput();
|
||||||
return p;
|
return p;
|
||||||
}
|
}
|
||||||
|
@ -1734,7 +1732,7 @@ static char *ServeErrorImpl(unsigned code, const char *reason) {
|
||||||
char *p, *s;
|
char *p, *s;
|
||||||
struct Asset *a;
|
struct Asset *a;
|
||||||
LockInc(&shared->errors);
|
LockInc(&shared->errors);
|
||||||
DropOutput();
|
ClearOutput();
|
||||||
p = SetStatus(code, reason);
|
p = SetStatus(code, reason);
|
||||||
s = xasprintf("/%d.html", code);
|
s = xasprintf("/%d.html", code);
|
||||||
a = GetAsset(s, strlen(s));
|
a = GetAsset(s, strlen(s));
|
||||||
|
@ -1877,8 +1875,16 @@ static char *ServeAsset(struct Asset *a, const char *path, size_t pathlen) {
|
||||||
} else {
|
} else {
|
||||||
LockInc(&shared->openfails);
|
LockInc(&shared->openfails);
|
||||||
WARNF("open(%`'s) failed %s", a->file->path, strerror(errno));
|
WARNF("open(%`'s) failed %s", a->file->path, strerror(errno));
|
||||||
|
if (errno == ENFILE) {
|
||||||
|
LockInc(&shared->enfiles);
|
||||||
|
return ServeError(503, "Service Unavailable");
|
||||||
|
} else if (errno == EMFILE) {
|
||||||
|
LockInc(&shared->emfiles);
|
||||||
|
return ServeError(503, "Service Unavailable");
|
||||||
|
} else {
|
||||||
return ServeError(500, "Internal Server Error");
|
return ServeError(500, "Internal Server Error");
|
||||||
}
|
}
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
content = "";
|
content = "";
|
||||||
contentlength = 0;
|
contentlength = 0;
|
||||||
|
@ -3320,7 +3326,6 @@ static char *HandleRedirect(struct Redirect *r) {
|
||||||
static void LogMessage(const char *d, const char *s, size_t n) {
|
static void LogMessage(const char *d, const char *s, size_t n) {
|
||||||
size_t n2, n3;
|
size_t n2, n3;
|
||||||
char *s2, *s3;
|
char *s2, *s3;
|
||||||
if (logmessages) {
|
|
||||||
while (n && (s[n - 1] == '\r' || s[n - 1] == '\n')) --n;
|
while (n && (s[n - 1] == '\r' || s[n - 1] == '\n')) --n;
|
||||||
if ((s2 = DecodeLatin1(s, n, &n2))) {
|
if ((s2 = DecodeLatin1(s, n, &n2))) {
|
||||||
if ((s3 = IndentLines(s2, n2, &n3, 1))) {
|
if ((s3 = IndentLines(s2, n2, &n3, 1))) {
|
||||||
|
@ -3330,12 +3335,11 @@ static void LogMessage(const char *d, const char *s, size_t n) {
|
||||||
free(s2);
|
free(s2);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
static void LogBody(const char *d, const char *s, size_t n) {
|
static void LogBody(const char *d, const char *s, size_t n) {
|
||||||
char *s2, *s3;
|
char *s2, *s3;
|
||||||
size_t n2, n3;
|
size_t n2, n3;
|
||||||
if (n && logbodies) {
|
if (!n) return;
|
||||||
while (n && (s[n - 1] == '\r' || s[n - 1] == '\n')) --n;
|
while (n && (s[n - 1] == '\r' || s[n - 1] == '\n')) --n;
|
||||||
if ((s2 = VisualizeControlCodes(s, n, &n2))) {
|
if ((s2 = VisualizeControlCodes(s, n, &n2))) {
|
||||||
if ((s3 = IndentLines(s2, n2, &n3, 1))) {
|
if ((s3 = IndentLines(s2, n2, &n3, 1))) {
|
||||||
|
@ -3345,13 +3349,12 @@ static void LogBody(const char *d, const char *s, size_t n) {
|
||||||
free(s2);
|
free(s2);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
static ssize_t SendString(const char *s) {
|
static ssize_t SendString(const char *s) {
|
||||||
size_t n;
|
size_t n;
|
||||||
ssize_t rc;
|
ssize_t rc;
|
||||||
n = strlen(s);
|
n = strlen(s);
|
||||||
LogMessage("sending", s, n);
|
if (logmessages) LogMessage("sending", s, n);
|
||||||
for (;;) {
|
for (;;) {
|
||||||
if ((rc = write(client, s, n)) != -1 || errno != EINTR) {
|
if ((rc = write(client, s, n)) != -1 || errno != EINTR) {
|
||||||
return rc;
|
return rc;
|
||||||
|
@ -3522,11 +3525,11 @@ static const char *MergeNames(const char *a, const char *b) {
|
||||||
}
|
}
|
||||||
|
|
||||||
static void AppendLong1(const char *a, long x) {
|
static void AppendLong1(const char *a, long x) {
|
||||||
if (x) AppendFmt("%s: %ld\r\n", a, x);
|
if (x) Append("%s: %ld\r\n", a, x);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void AppendLong2(const char *a, const char *b, long x) {
|
static void AppendLong2(const char *a, const char *b, long x) {
|
||||||
if (x) AppendFmt("%s.%s: %ld\r\n", a, b, x);
|
if (x) Append("%s.%s: %ld\r\n", a, b, x);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void AppendTimeval(const char *a, struct timeval *tv) {
|
static void AppendTimeval(const char *a, struct timeval *tv) {
|
||||||
|
@ -3681,7 +3684,7 @@ char *ServeListing(void) {
|
||||||
char rb[8], tb[64], *rp[6];
|
char rb[8], tb[64], *rp[6];
|
||||||
size_t i, n, pathlen, rn[6];
|
size_t i, n, pathlen, rn[6];
|
||||||
if (msg.method != kHttpGet && msg.method != kHttpHead) return BadMethod();
|
if (msg.method != kHttpGet && msg.method != kHttpHead) return BadMethod();
|
||||||
AppendString("\
|
Append("\
|
||||||
<!doctype html>\r\n\
|
<!doctype html>\r\n\
|
||||||
<meta charset=\"utf-8\">\r\n\
|
<meta charset=\"utf-8\">\r\n\
|
||||||
<title>redbean zip listing</title>\r\n\
|
<title>redbean zip listing</title>\r\n\
|
||||||
|
@ -3698,7 +3701,7 @@ td { padding-right: 3em; }\r\n\
|
||||||
rp[0] = EscapeHtml(brand, -1, &rn[0]);
|
rp[0] = EscapeHtml(brand, -1, &rn[0]);
|
||||||
AppendData(rp[0], rn[0]);
|
AppendData(rp[0], rn[0]);
|
||||||
free(rp[0]);
|
free(rp[0]);
|
||||||
AppendString("</h1><hr></header><pre>\r\n");
|
Append("</h1><hr></header><pre>\r\n");
|
||||||
memset(w, 0, sizeof(w));
|
memset(w, 0, sizeof(w));
|
||||||
n = GetZipCdirRecords(cdir);
|
n = GetZipCdirRecords(cdir);
|
||||||
for (cf = GetZipCdirOffset(cdir); n--; cf += ZIP_CFILE_HDRSIZE(zmap + cf)) {
|
for (cf = GetZipCdirOffset(cdir); n--; cf += ZIP_CFILE_HDRSIZE(zmap + cf)) {
|
||||||
|
@ -3733,12 +3736,12 @@ td { padding-right: 3em; }\r\n\
|
||||||
if (IsCompressionMethodSupported(
|
if (IsCompressionMethodSupported(
|
||||||
ZIP_LFILE_COMPRESSIONMETHOD(zmap + lf)) &&
|
ZIP_LFILE_COMPRESSIONMETHOD(zmap + lf)) &&
|
||||||
IsAcceptablePath(path, pathlen)) {
|
IsAcceptablePath(path, pathlen)) {
|
||||||
AppendFmt("<a href=\"%.*s\">%-*.*s</a> %s %0*o %4s %,*ld %'s\r\n",
|
Append("<a href=\"%.*s\">%-*.*s</a> %s %0*o %4s %,*ld %'s\r\n",
|
||||||
rn[2], rp[2], w[0], rn[4], rp[4], tb, w[1],
|
rn[2], rp[2], w[0], rn[4], rp[4], tb, w[1],
|
||||||
GetZipCfileMode(zmap + cf), DescribeCompressionRatio(rb, lf),
|
GetZipCfileMode(zmap + cf), DescribeCompressionRatio(rb, lf),
|
||||||
w[2], GetZipLfileUncompressedSize(zmap + lf), rp[5]);
|
w[2], GetZipLfileUncompressedSize(zmap + lf), rp[5]);
|
||||||
} else {
|
} else {
|
||||||
AppendFmt("%-*.*s %s %0*o %4s %,*ld %'s\r\n", w[0], rn[4], rp[4], tb,
|
Append("%-*.*s %s %0*o %4s %,*ld %'s\r\n", w[0], rn[4], rp[4], tb,
|
||||||
w[1], GetZipCfileMode(zmap + cf),
|
w[1], GetZipCfileMode(zmap + cf),
|
||||||
DescribeCompressionRatio(rb, lf), w[2],
|
DescribeCompressionRatio(rb, lf), w[2],
|
||||||
GetZipLfileUncompressedSize(zmap + lf), rp[5]);
|
GetZipLfileUncompressedSize(zmap + lf), rp[5]);
|
||||||
|
@ -3752,38 +3755,38 @@ td { padding-right: 3em; }\r\n\
|
||||||
}
|
}
|
||||||
free(path);
|
free(path);
|
||||||
}
|
}
|
||||||
AppendString("</pre><footer><hr>\r\n");
|
Append("</pre><footer><hr>\r\n");
|
||||||
AppendString("<table border=\"0\"><tr><td valign=\"top\">\r\n");
|
Append("<table border=\"0\"><tr><td valign=\"top\">\r\n");
|
||||||
AppendString("<a href=\"/statusz\">/statusz</a> says your redbean<br>\r\n");
|
Append("<a href=\"/statusz\">/statusz</a> says your redbean<br>\r\n");
|
||||||
AppendResourceReport(&shared->children, "<br>\r\n");
|
AppendResourceReport(&shared->children, "<br>\r\n");
|
||||||
AppendString("<td valign=\"top\">\r\n");
|
Append("<td valign=\"top\">\r\n");
|
||||||
and = "";
|
and = "";
|
||||||
x = nowl() - startserver;
|
x = nowl() - startserver;
|
||||||
y = ldiv(x, 24L * 60 * 60);
|
y = ldiv(x, 24L * 60 * 60);
|
||||||
if (y.quot) {
|
if (y.quot) {
|
||||||
AppendFmt("%,ld day%s ", y.quot, y.quot == 1 ? "" : "s");
|
Append("%,ld day%s ", y.quot, y.quot == 1 ? "" : "s");
|
||||||
and = "and ";
|
and = "and ";
|
||||||
}
|
}
|
||||||
y = ldiv(y.rem, 60 * 60);
|
y = ldiv(y.rem, 60 * 60);
|
||||||
if (y.quot) {
|
if (y.quot) {
|
||||||
AppendFmt("%,ld hour%s ", y.quot, y.quot == 1 ? "" : "s");
|
Append("%,ld hour%s ", y.quot, y.quot == 1 ? "" : "s");
|
||||||
and = "and ";
|
and = "and ";
|
||||||
}
|
}
|
||||||
y = ldiv(y.rem, 60);
|
y = ldiv(y.rem, 60);
|
||||||
if (y.quot) {
|
if (y.quot) {
|
||||||
AppendFmt("%,ld minute%s ", y.quot, y.quot == 1 ? "" : "s");
|
Append("%,ld minute%s ", y.quot, y.quot == 1 ? "" : "s");
|
||||||
and = "and ";
|
and = "and ";
|
||||||
}
|
}
|
||||||
AppendFmt("%s%,ld second%s of operation<br>\r\n", and, y.rem,
|
Append("%s%,ld second%s of operation<br>\r\n", and, y.rem,
|
||||||
y.rem == 1 ? "" : "s");
|
y.rem == 1 ? "" : "s");
|
||||||
x = shared->messageshandled;
|
x = shared->messageshandled;
|
||||||
AppendFmt("%,ld message%s handled<br>\r\n", x, x == 1 ? "" : "s");
|
Append("%,ld message%s handled<br>\r\n", x, x == 1 ? "" : "s");
|
||||||
x = shared->connectionshandled;
|
x = shared->connectionshandled;
|
||||||
AppendFmt("%,ld connection%s handled<br>\r\n", x, x == 1 ? "" : "s");
|
Append("%,ld connection%s handled<br>\r\n", x, x == 1 ? "" : "s");
|
||||||
x = shared->workers;
|
x = shared->workers;
|
||||||
AppendFmt("%,ld connection%s active<br>\r\n", x, x == 1 ? "" : "s");
|
Append("%,ld connection%s active<br>\r\n", x, x == 1 ? "" : "s");
|
||||||
AppendString("</table>\r\n");
|
Append("</table>\r\n");
|
||||||
AppendString("</footer>\r\n");
|
Append("</footer>\r\n");
|
||||||
p = SetStatus(200, "OK");
|
p = SetStatus(200, "OK");
|
||||||
p = AppendContentType(p, "text/html");
|
p = AppendContentType(p, "text/html");
|
||||||
p = AppendCache(p, 0);
|
p = AppendCache(p, 0);
|
||||||
|
@ -4014,7 +4017,7 @@ static char *HandleRequest(void) {
|
||||||
return ServeFailure(505, "HTTP Version Not Supported");
|
return ServeFailure(505, "HTTP Version Not Supported");
|
||||||
}
|
}
|
||||||
if ((p = SynchronizeStream())) return p;
|
if ((p = SynchronizeStream())) return p;
|
||||||
LogBody("received", inbuf.p + hdrsize, msgsize - hdrsize);
|
if (logbodies) LogBody("received", inbuf.p + hdrsize, msgsize - hdrsize);
|
||||||
if (msg.version < 11 || HeaderEqualCase(kHttpConnection, "close")) {
|
if (msg.version < 11 || HeaderEqualCase(kHttpConnection, "close")) {
|
||||||
connectionclose = true;
|
connectionclose = true;
|
||||||
}
|
}
|
||||||
|
@ -4072,10 +4075,11 @@ static bool HandleMessage(void) {
|
||||||
char *p, *s;
|
char *p, *s;
|
||||||
struct iovec iov[4];
|
struct iovec iov[4];
|
||||||
long actualcontentlength;
|
long actualcontentlength;
|
||||||
|
g_syscount = 0;
|
||||||
if ((rc = ParseHttpRequest(&msg, inbuf.p, amtread)) != -1) {
|
if ((rc = ParseHttpRequest(&msg, inbuf.p, amtread)) != -1) {
|
||||||
if (!rc) return false;
|
if (!rc) return false;
|
||||||
hdrsize = rc;
|
hdrsize = rc;
|
||||||
LogMessage("received", inbuf.p, hdrsize);
|
if (logmessages) LogMessage("received", inbuf.p, hdrsize);
|
||||||
RecordNetworkOrigin();
|
RecordNetworkOrigin();
|
||||||
p = HandleRequest();
|
p = HandleRequest();
|
||||||
} else {
|
} else {
|
||||||
|
@ -4091,12 +4095,12 @@ static bool HandleMessage(void) {
|
||||||
LockInc(&shared->synchronizationfailures);
|
LockInc(&shared->synchronizationfailures);
|
||||||
DEBUGF("could not synchronize message stream");
|
DEBUGF("could not synchronize message stream");
|
||||||
}
|
}
|
||||||
if (connectionclose) {
|
if (0 && connectionclose) {
|
||||||
LockInc(&shared->shutdowns);
|
LockInc(&shared->shutdowns);
|
||||||
shutdown(client, SHUT_RD);
|
shutdown(client, SHUT_RD);
|
||||||
}
|
}
|
||||||
if (msg.version >= 10) {
|
if (msg.version >= 10) {
|
||||||
p = AppendHeader(p, "Date", shared->currentdate);
|
p = AppendCrlf(stpcpy(stpcpy(p, "Date: "), shared->currentdate));
|
||||||
if (!branded) p = AppendServer(p, serverheader);
|
if (!branded) p = AppendServer(p, serverheader);
|
||||||
if (extrahdrs) p = stpcpy(p, extrahdrs);
|
if (extrahdrs) p = stpcpy(p, extrahdrs);
|
||||||
if (connectionclose) {
|
if (connectionclose) {
|
||||||
|
@ -4112,7 +4116,7 @@ static bool HandleMessage(void) {
|
||||||
p = AppendContentLength(p, actualcontentlength);
|
p = AppendContentLength(p, actualcontentlength);
|
||||||
p = AppendCrlf(p);
|
p = AppendCrlf(p);
|
||||||
CHECK_LE(p - hdrbuf.p, hdrbuf.n);
|
CHECK_LE(p - hdrbuf.p, hdrbuf.n);
|
||||||
LogMessage("sending", hdrbuf.p, p - hdrbuf.p);
|
if (logmessages) LogMessage("sending", hdrbuf.p, p - hdrbuf.p);
|
||||||
iov[0].iov_base = hdrbuf.p;
|
iov[0].iov_base = hdrbuf.p;
|
||||||
iov[0].iov_len = p - hdrbuf.p;
|
iov[0].iov_len = p - hdrbuf.p;
|
||||||
iovlen = 1;
|
iovlen = 1;
|
||||||
|
@ -4137,7 +4141,7 @@ static bool HandleMessage(void) {
|
||||||
iovlen = 1;
|
iovlen = 1;
|
||||||
}
|
}
|
||||||
if (loglatency || LOGGABLE(kLogDebug)) {
|
if (loglatency || LOGGABLE(kLogDebug)) {
|
||||||
flogf(kLogDebug, __FILE__, __LINE__, NULL, "%`'.*s handled in %,ldµs",
|
flogf(kLogDebug, __FILE__, __LINE__, NULL, "%`'.*s latency %,ldµs",
|
||||||
msg.uri.b - msg.uri.a, inbuf.p + msg.uri.a,
|
msg.uri.b - msg.uri.a, inbuf.p + msg.uri.a,
|
||||||
(long)((nowl() - startrequest) * 1e6L));
|
(long)((nowl() - startrequest) * 1e6L));
|
||||||
}
|
}
|
||||||
|
@ -4150,6 +4154,7 @@ static bool HandleMessage(void) {
|
||||||
static void InitRequest(void) {
|
static void InitRequest(void) {
|
||||||
frags = 0;
|
frags = 0;
|
||||||
msgsize = 0;
|
msgsize = 0;
|
||||||
|
outbuf.n = 0;
|
||||||
content = NULL;
|
content = NULL;
|
||||||
gzipped = false;
|
gzipped = false;
|
||||||
branded = false;
|
branded = false;
|
||||||
|
@ -4272,10 +4277,13 @@ static void HandleConnection(void) {
|
||||||
case 0:
|
case 0:
|
||||||
meltdown = false;
|
meltdown = false;
|
||||||
connectionclose = false;
|
connectionclose = false;
|
||||||
|
if (funtrace && !IsTiny()) {
|
||||||
|
ftrace_install();
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
case -1:
|
case -1:
|
||||||
FATALF("%s too many processes %s", DescribeServer(), strerror(errno));
|
FATALF("%s too many processes %s", DescribeServer(), strerror(errno));
|
||||||
LockInc(&shared->forkerrors);
|
++shared->forkerrors;
|
||||||
LockInc(&shared->dropped);
|
LockInc(&shared->dropped);
|
||||||
EnterMeltdownMode();
|
EnterMeltdownMode();
|
||||||
SendServiceUnavailable();
|
SendServiceUnavailable();
|
||||||
|
@ -4292,8 +4300,7 @@ static void HandleConnection(void) {
|
||||||
HandleMessages();
|
HandleMessages();
|
||||||
DEBUGF("%s closing after %,ldµs", DescribeClient(),
|
DEBUGF("%s closing after %,ldµs", DescribeClient(),
|
||||||
(long)((nowl() - startconnection) * 1e6L));
|
(long)((nowl() - startconnection) * 1e6L));
|
||||||
if (close(client) != -1) {
|
if (close(client) == -1) {
|
||||||
} else {
|
|
||||||
LockInc(&shared->closeerrors);
|
LockInc(&shared->closeerrors);
|
||||||
WARNF("%s close failed", DescribeClient());
|
WARNF("%s close failed", DescribeClient());
|
||||||
}
|
}
|
||||||
|
@ -4303,7 +4310,7 @@ static void HandleConnection(void) {
|
||||||
CollectGarbage();
|
CollectGarbage();
|
||||||
}
|
}
|
||||||
} else if (errno == EINTR || errno == EAGAIN) {
|
} else if (errno == EINTR || errno == EAGAIN) {
|
||||||
LockInc(&shared->acceptinterrupts);
|
++shared->acceptinterrupts;
|
||||||
} else if (errno == ENFILE) {
|
} else if (errno == ENFILE) {
|
||||||
LockInc(&shared->enfiles);
|
LockInc(&shared->enfiles);
|
||||||
WARNF("%s too many open files", DescribeServer());
|
WARNF("%s too many open files", DescribeServer());
|
||||||
|
@ -4321,19 +4328,19 @@ static void HandleConnection(void) {
|
||||||
WARNF("%s ran out of buffer");
|
WARNF("%s ran out of buffer");
|
||||||
EnterMeltdownMode();
|
EnterMeltdownMode();
|
||||||
} else if (errno == ENONET) {
|
} else if (errno == ENONET) {
|
||||||
LockInc(&shared->enonets);
|
++shared->enonets;
|
||||||
WARNF("%s network gone", DescribeServer());
|
WARNF("%s network gone", DescribeServer());
|
||||||
sleep(1);
|
sleep(1);
|
||||||
} else if (errno == ENETDOWN) {
|
} else if (errno == ENETDOWN) {
|
||||||
LockInc(&shared->enetdowns);
|
++shared->enetdowns;
|
||||||
WARNF("%s network down", DescribeServer());
|
WARNF("%s network down", DescribeServer());
|
||||||
sleep(1);
|
sleep(1);
|
||||||
} else if (errno == ECONNABORTED) {
|
} else if (errno == ECONNABORTED) {
|
||||||
LockInc(&shared->acceptresets);
|
++shared->acceptresets;
|
||||||
WARNF("%s connection reset before accept");
|
WARNF("%s connection reset before accept");
|
||||||
} else if (errno == ENETUNREACH || errno == EHOSTUNREACH ||
|
} else if (errno == ENETUNREACH || errno == EHOSTUNREACH ||
|
||||||
errno == EOPNOTSUPP || errno == ENOPROTOOPT || errno == EPROTO) {
|
errno == EOPNOTSUPP || errno == ENOPROTOOPT || errno == EPROTO) {
|
||||||
LockInc(&shared->accepterrors);
|
++shared->accepterrors;
|
||||||
WARNF("%s ephemeral accept error %s", DescribeServer(), strerror(errno));
|
WARNF("%s ephemeral accept error %s", DescribeServer(), strerror(errno));
|
||||||
} else {
|
} else {
|
||||||
FATALF("%s accept error %s", DescribeServer(), strerror(errno));
|
FATALF("%s accept error %s", DescribeServer(), strerror(errno));
|
||||||
|
@ -4408,8 +4415,8 @@ void RedBean(int argc, char *argv[], const char *prog) {
|
||||||
if (setitimer(ITIMER_REAL, &kHeartbeat, NULL) == -1) {
|
if (setitimer(ITIMER_REAL, &kHeartbeat, NULL) == -1) {
|
||||||
heartless = true;
|
heartless = true;
|
||||||
}
|
}
|
||||||
CHECK_NE(-1,
|
server = socket(AF_INET, SOCK_STREAM | SOCK_CLOEXEC, IPPROTO_TCP);
|
||||||
(server = socket(AF_INET, SOCK_STREAM | SOCK_CLOEXEC, IPPROTO_TCP)));
|
CHECK_NE(-1, server);
|
||||||
TuneSockets();
|
TuneSockets();
|
||||||
if (bind(server, &serveraddr, sizeof(serveraddr)) == -1) {
|
if (bind(server, &serveraddr, sizeof(serveraddr)) == -1) {
|
||||||
if (errno == EADDRINUSE) {
|
if (errno == EADDRINUSE) {
|
||||||
|
@ -4473,7 +4480,7 @@ void RedBean(int argc, char *argv[], const char *prog) {
|
||||||
|
|
||||||
int main(int argc, char *argv[]) {
|
int main(int argc, char *argv[]) {
|
||||||
setenv("GDB", "", true);
|
setenv("GDB", "", true);
|
||||||
showcrashreports();
|
if (!IsTiny()) showcrashreports();
|
||||||
RedBean(argc, argv, (const char *)getauxval(AT_EXECFN));
|
RedBean(argc, argv, (const char *)getauxval(AT_EXECFN));
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
|
@ -262,7 +262,7 @@ local function main()
|
||||||
pat = re.compile([[([0-9]{1,3})\.([0-9]{1,3})\.([0-9]{1,3})\.([0-9]{1,3})]])
|
pat = re.compile([[([0-9]{1,3})\.([0-9]{1,3})\.([0-9]{1,3})\.([0-9]{1,3})]])
|
||||||
m,a,b,c,d = pat:search(s) -- m and rest are nil if match not found
|
m,a,b,c,d = pat:search(s) -- m and rest are nil if match not found
|
||||||
Write('<pre>\r\n')
|
Write('<pre>\r\n')
|
||||||
Write([[pat = re.compile('([0-9]{1,3})\\.([0-9]{1,3})\\.([0-9]{1,3})\\.([0-9]{1,3})', re.EXTENDED)]])
|
Write([[pat = re.compile('([0-9]{1,3})\\.([0-9]{1,3})\\.([0-9]{1,3})\\.([0-9]{1,3})')]])
|
||||||
Write(string.format('\r\nm,a,b,c,d = pat:search(%q)\r\n', s))
|
Write(string.format('\r\nm,a,b,c,d = pat:search(%q)\r\n', s))
|
||||||
Write('</pre>\r\n')
|
Write('</pre>\r\n')
|
||||||
Write('<dl>\r\n')
|
Write('<dl>\r\n')
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue