mirror of
https://github.com/jart/cosmopolitan.git
synced 2025-01-31 03:27:39 +00:00
Do code cleanup use duff device linenoise i/o
This commit is contained in:
parent
6ff46ca373
commit
2f56ebfe78
79 changed files with 1393 additions and 1484 deletions
|
@ -14,11 +14,11 @@
|
||||||
|
|
||||||
int main(int argc, char *argv[]) {
|
int main(int argc, char *argv[]) {
|
||||||
int c, n;
|
int c, n;
|
||||||
char a[22];
|
char a[22], *p;
|
||||||
if ((c = GetCpuCount())) {
|
if ((c = GetCpuCount())) {
|
||||||
n = int64toarray_radix10(c, a);
|
p = FormatInt64(a, c);
|
||||||
a[n++] = '\n';
|
*p++ = '\n';
|
||||||
return write(1, a, n) == n ? 0 : 1;
|
return write(1, a, p - a) == p - a ? 0 : 1;
|
||||||
} else {
|
} else {
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
|
@ -27,7 +27,7 @@ int main(int argc, char *argv[]) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (isprime) {
|
if (isprime) {
|
||||||
int64toarray_radix10(i, buf);
|
FormatInt64(buf, i);
|
||||||
fputs(buf, stdout);
|
fputs(buf, stdout);
|
||||||
fputc('\n', stdout);
|
fputc('\n', stdout);
|
||||||
if (k++ % 100 == 0) {
|
if (k++ % 100 == 0) {
|
||||||
|
|
|
@ -47,8 +47,8 @@ void PrintMetric(const char *name, long double d) {
|
||||||
mils = fmodl(d * 1000, 1000);
|
mils = fmodl(d * 1000, 1000);
|
||||||
mics = fmodl(d * 1000000, 1000);
|
mics = fmodl(d * 1000000, 1000);
|
||||||
p = stpcpy(p, name), *p++ = '\t';
|
p = stpcpy(p, name), *p++ = '\t';
|
||||||
p += int64toarray_radix10(mins, p), *p++ = 'm';
|
p = FormatInt64(p, mins), *p++ = 'm';
|
||||||
p += int64toarray_radix10(secs, p), *p++ = '.';
|
p = FormatInt64(p, secs), *p++ = '.';
|
||||||
*p++ = '0' + mils / 100;
|
*p++ = '0' + mils / 100;
|
||||||
*p++ = '0' + mils / 10 % 10;
|
*p++ = '0' + mils / 10 % 10;
|
||||||
*p++ = '0' + mils % 10;
|
*p++ = '0' + mils % 10;
|
||||||
|
|
|
@ -28,31 +28,30 @@
|
||||||
#include "libc/sysv/consts/ok.h"
|
#include "libc/sysv/consts/ok.h"
|
||||||
#include "libc/sysv/errfuns.h"
|
#include "libc/sysv/errfuns.h"
|
||||||
|
|
||||||
static noasan bool IsExePath(const char *s, size_t n) {
|
static bool IsExePath(const char *s, size_t n) {
|
||||||
return n >= 4 && (READ32LE(s + n - 4) == READ32LE(".exe") ||
|
return n >= 4 && (READ32LE(s + n - 4) == READ32LE(".exe") ||
|
||||||
READ32LE(s + n - 4) == READ32LE(".EXE"));
|
READ32LE(s + n - 4) == READ32LE(".EXE"));
|
||||||
}
|
}
|
||||||
|
|
||||||
static noasan bool IsComPath(const char *s, size_t n) {
|
static bool IsComPath(const char *s, size_t n) {
|
||||||
return n >= 4 && (READ32LE(s + n - 4) == READ32LE(".com") ||
|
return n >= 4 && (READ32LE(s + n - 4) == READ32LE(".com") ||
|
||||||
READ32LE(s + n - 4) == READ32LE(".COM"));
|
READ32LE(s + n - 4) == READ32LE(".COM"));
|
||||||
}
|
}
|
||||||
|
|
||||||
static noasan bool IsComDbgPath(const char *s, size_t n) {
|
static bool IsComDbgPath(const char *s, size_t n) {
|
||||||
return n >= 8 && (READ64LE(s + n - 8) == READ64LE(".com.dbg") ||
|
return n >= 8 && (READ64LE(s + n - 8) == READ64LE(".com.dbg") ||
|
||||||
READ64LE(s + n - 8) == READ64LE(".COM.DBG"));
|
READ64LE(s + n - 8) == READ64LE(".COM.DBG"));
|
||||||
}
|
}
|
||||||
|
|
||||||
static noasan bool AccessCommand(const char *name,
|
static bool AccessCommand(const char *name, char path[hasatleast PATH_MAX],
|
||||||
char path[hasatleast PATH_MAX], size_t namelen,
|
size_t namelen, int *err, const char *suffix,
|
||||||
int *err, const char *suffix, size_t pathlen) {
|
size_t pathlen) {
|
||||||
size_t suffixlen;
|
size_t suffixlen;
|
||||||
suffixlen = strlen(suffix);
|
suffixlen = strlen(suffix);
|
||||||
if (pathlen + 1 + namelen + suffixlen + 1 > PATH_MAX) return false;
|
if (pathlen + 1 + namelen + suffixlen + 1 > PATH_MAX) return false;
|
||||||
if (pathlen && (path[pathlen - 1] != '/' && path[pathlen - 1] != '\\')) {
|
if (pathlen && (path[pathlen - 1] != '/' && path[pathlen - 1] != '\\')) {
|
||||||
path[pathlen] = !IsWindows() ? '/'
|
path[pathlen] =
|
||||||
: memchr(path, '\\', pathlen) ? '\\'
|
!IsWindows() ? '/' : memchr(path, '\\', pathlen) ? '\\' : '/';
|
||||||
: '/';
|
|
||||||
pathlen++;
|
pathlen++;
|
||||||
}
|
}
|
||||||
memcpy(path + pathlen, name, namelen);
|
memcpy(path + pathlen, name, namelen);
|
||||||
|
@ -62,8 +61,8 @@ static noasan bool AccessCommand(const char *name,
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
static noasan bool SearchPath(const char *name, char path[hasatleast PATH_MAX],
|
static bool SearchPath(const char *name, char path[hasatleast PATH_MAX],
|
||||||
size_t namelen, int *err, const char *suffix) {
|
size_t namelen, int *err, const char *suffix) {
|
||||||
char sep;
|
char sep;
|
||||||
size_t i;
|
size_t i;
|
||||||
const char *p;
|
const char *p;
|
||||||
|
@ -87,10 +86,9 @@ static noasan bool SearchPath(const char *name, char path[hasatleast PATH_MAX],
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
static noasan bool FindCommand(const char *name,
|
static bool FindCommand(const char *name, char pathbuf[hasatleast PATH_MAX],
|
||||||
char pathbuf[hasatleast PATH_MAX],
|
size_t namelen, bool priorityonly, const char *suffix,
|
||||||
size_t namelen, bool priorityonly,
|
int *err) {
|
||||||
const char *suffix, int *err) {
|
|
||||||
if (priorityonly &&
|
if (priorityonly &&
|
||||||
(memchr(name, '/', namelen) || memchr(name, '\\', namelen))) {
|
(memchr(name, '/', namelen) || memchr(name, '\\', namelen))) {
|
||||||
pathbuf[0] = 0;
|
pathbuf[0] = 0;
|
||||||
|
@ -107,15 +105,13 @@ static noasan bool FindCommand(const char *name,
|
||||||
SearchPath(name, pathbuf, namelen, err, suffix);
|
SearchPath(name, pathbuf, namelen, err, suffix);
|
||||||
}
|
}
|
||||||
|
|
||||||
static noasan bool FindVerbatim(const char *name,
|
static bool FindVerbatim(const char *name, char pathbuf[hasatleast PATH_MAX],
|
||||||
char pathbuf[hasatleast PATH_MAX],
|
size_t namelen, bool priorityonly, int *err) {
|
||||||
size_t namelen, bool priorityonly, int *err) {
|
|
||||||
return FindCommand(name, pathbuf, namelen, priorityonly, "", err);
|
return FindCommand(name, pathbuf, namelen, priorityonly, "", err);
|
||||||
}
|
}
|
||||||
|
|
||||||
static noasan bool FindSuffixed(const char *name,
|
static bool FindSuffixed(const char *name, char pathbuf[hasatleast PATH_MAX],
|
||||||
char pathbuf[hasatleast PATH_MAX],
|
size_t namelen, bool priorityonly, int *err) {
|
||||||
size_t namelen, bool priorityonly, int *err) {
|
|
||||||
return !IsExePath(name, namelen) && !IsComPath(name, namelen) &&
|
return !IsExePath(name, namelen) && !IsComPath(name, namelen) &&
|
||||||
!IsComDbgPath(name, namelen) &&
|
!IsComDbgPath(name, namelen) &&
|
||||||
(FindCommand(name, pathbuf, namelen, priorityonly, ".com", err) ||
|
(FindCommand(name, pathbuf, namelen, priorityonly, ".com", err) ||
|
||||||
|
@ -131,7 +127,7 @@ static noasan bool FindSuffixed(const char *name,
|
||||||
* @asyncsignalsafe
|
* @asyncsignalsafe
|
||||||
* @vforksafe
|
* @vforksafe
|
||||||
*/
|
*/
|
||||||
noasan char *commandv(const char *name, char pathbuf[hasatleast PATH_MAX]) {
|
char *commandv(const char *name, char pathbuf[hasatleast PATH_MAX]) {
|
||||||
int e, f;
|
int e, f;
|
||||||
char *res;
|
char *res;
|
||||||
size_t namelen;
|
size_t namelen;
|
||||||
|
|
|
@ -73,7 +73,7 @@ int ioctl_tcgets(int fd, ...) {
|
||||||
tio = va_arg(va, struct termios *);
|
tio = va_arg(va, struct termios *);
|
||||||
va_end(va);
|
va_end(va);
|
||||||
if (fd >= 0) {
|
if (fd >= 0) {
|
||||||
if (!tio) {
|
if (!tio || (IsAsan() && !__asan_is_valid(tio, sizeof(*tio)))) {
|
||||||
rc = efault();
|
rc = efault();
|
||||||
} else if (fd < g_fds.n && g_fds.p[fd].kind == kFdZip) {
|
} else if (fd < g_fds.n && g_fds.p[fd].kind == kFdZip) {
|
||||||
rc = enotty();
|
rc = enotty();
|
||||||
|
|
|
@ -68,7 +68,7 @@ int ioctl_tcsets(int fd, uint64_t request, ...) {
|
||||||
va_start(va, request);
|
va_start(va, request);
|
||||||
tio = va_arg(va, const struct termios *);
|
tio = va_arg(va, const struct termios *);
|
||||||
va_end(va);
|
va_end(va);
|
||||||
if (!tio) {
|
if (!tio || (IsAsan() && !__asan_is_valid(tio, sizeof(*tio)))) {
|
||||||
rc = efault();
|
rc = efault();
|
||||||
} else if (fd >= 0) {
|
} else if (fd >= 0) {
|
||||||
if (fd < g_fds.n && g_fds.p[fd].kind == kFdZip) {
|
if (fd < g_fds.n && g_fds.p[fd].kind == kFdZip) {
|
||||||
|
|
|
@ -29,7 +29,7 @@ errno_t ptsname_r(int fd, char *buf, size_t size) {
|
||||||
if (size) {
|
if (size) {
|
||||||
if (!buf) return einval();
|
if (!buf) return einval();
|
||||||
if (ioctl(fd, TIOCGPTN, &pty) == -1) return errno;
|
if (ioctl(fd, TIOCGPTN, &pty) == -1) return errno;
|
||||||
int64toarray_radix10(pty, stpcpy(tb, "/dev/pts/"));
|
FormatInt32(stpcpy(tb, "/dev/pts/"), pty);
|
||||||
if (strlen(tb) + 1 >= size) return (errno = ERANGE);
|
if (strlen(tb) + 1 >= size) return (errno = ERANGE);
|
||||||
stpcpy(buf, tb);
|
stpcpy(buf, tb);
|
||||||
/* TODO(jart): OpenBSD OMG */
|
/* TODO(jart): OpenBSD OMG */
|
||||||
|
|
|
@ -5,10 +5,10 @@
|
||||||
#include "libc/calls/struct/sigaction.h"
|
#include "libc/calls/struct/sigaction.h"
|
||||||
#include "libc/calls/struct/stat.h"
|
#include "libc/calls/struct/stat.h"
|
||||||
|
|
||||||
#define _KERNTRACE 0 /* not configurable w/ flag yet */
|
#define _KERNTRACE 1 /* not configurable w/ flag yet */
|
||||||
#define _POLLTRACE 0 /* not configurable w/ flag yet */
|
#define _POLLTRACE 1 /* not configurable w/ flag yet */
|
||||||
#define _DATATRACE 1 /* not configurable w/ flag yet */
|
#define _DATATRACE 1 /* not configurable w/ flag yet */
|
||||||
#define _NTTRACE 0 /* not configurable w/ flag yet */
|
#define _NTTRACE 1 /* not configurable w/ flag yet */
|
||||||
|
|
||||||
#define STRACE_PROLOGUE "%rSYS %5P %'18T "
|
#define STRACE_PROLOGUE "%rSYS %5P %'18T "
|
||||||
|
|
||||||
|
|
|
@ -64,7 +64,7 @@ static int ttyname_linux(int fd, char *buf, size_t size) {
|
||||||
struct stat st1, st2;
|
struct stat st1, st2;
|
||||||
if (!isatty(fd)) return errno;
|
if (!isatty(fd)) return errno;
|
||||||
char name[PATH_MAX];
|
char name[PATH_MAX];
|
||||||
int64toarray_radix10(fd, stpcpy(name, "/proc/self/fd/"));
|
FormatInt32(stpcpy(name, "/proc/self/fd/"), fd);
|
||||||
ssize_t got;
|
ssize_t got;
|
||||||
got = readlink(name, buf, size);
|
got = readlink(name, buf, size);
|
||||||
if (got == -1) return errno;
|
if (got == -1) return errno;
|
||||||
|
|
|
@ -73,10 +73,10 @@ int getnameinfo(const struct sockaddr *addr, socklen_t addrlen, char *name,
|
||||||
|
|
||||||
ip = (uint8_t *)&(((struct sockaddr_in *)addr)->sin_addr);
|
ip = (uint8_t *)&(((struct sockaddr_in *)addr)->sin_addr);
|
||||||
p = rdomain;
|
p = rdomain;
|
||||||
p += int64toarray_radix10(ip[3], p), *p++ = '.';
|
p = FormatUint32(p, ip[3]), *p++ = '.';
|
||||||
p += int64toarray_radix10(ip[2], p), *p++ = '.';
|
p = FormatUint32(p, ip[2]), *p++ = '.';
|
||||||
p += int64toarray_radix10(ip[1], p), *p++ = '.';
|
p = FormatUint32(p, ip[1]), *p++ = '.';
|
||||||
p += int64toarray_radix10(ip[0], p), stpcpy(p, ".in-addr.arpa");
|
p = FormatUint32(p, ip[0]), stpcpy(p, ".in-addr.arpa");
|
||||||
info[0] = '\0';
|
info[0] = '\0';
|
||||||
if (name != NULL && namelen != 0) {
|
if (name != NULL && namelen != 0) {
|
||||||
if ((flags & NI_NUMERICHOST) && (flags & NI_NAMEREQD)) return EAI_NONAME;
|
if ((flags & NI_NUMERICHOST) && (flags & NI_NAMEREQD)) return EAI_NONAME;
|
||||||
|
|
|
@ -147,12 +147,12 @@ hidden int __fmt(void *fn, void *arg, const char *format, va_list va) {
|
||||||
continue;
|
continue;
|
||||||
} else if (format[1] == 'd') { /* FAST PATH: PLAIN INTEGER */
|
} else if (format[1] == 'd') { /* FAST PATH: PLAIN INTEGER */
|
||||||
d = va_arg(va, int);
|
d = va_arg(va, int);
|
||||||
if (out(ibuf, arg, int64toarray_radix10(d, ibuf)) == -1) return -1;
|
if (out(ibuf, arg, FormatInt64(ibuf, d) - ibuf) == -1) return -1;
|
||||||
format += 2;
|
format += 2;
|
||||||
continue;
|
continue;
|
||||||
} else if (format[1] == 'u') { /* FAST PATH: PLAIN UNSIGNED */
|
} else if (format[1] == 'u') { /* FAST PATH: PLAIN UNSIGNED */
|
||||||
u = va_arg(va, unsigned);
|
u = va_arg(va, unsigned);
|
||||||
if (out(ibuf, arg, uint64toarray_radix10(u, ibuf)) == -1) return -1;
|
if (out(ibuf, arg, FormatUint64(ibuf, u) - ibuf) == -1) return -1;
|
||||||
format += 2;
|
format += 2;
|
||||||
continue;
|
continue;
|
||||||
} else if (format[1] == 'x') { /* FAST PATH: PLAIN HEX */
|
} else if (format[1] == 'x') { /* FAST PATH: PLAIN HEX */
|
||||||
|
@ -167,12 +167,12 @@ hidden int __fmt(void *fn, void *arg, const char *format, va_list va) {
|
||||||
continue;
|
continue;
|
||||||
} else if (format[1] == 'l' && format[2] == 'd') {
|
} else if (format[1] == 'l' && format[2] == 'd') {
|
||||||
ld = va_arg(va, long); /* FAST PATH: PLAIN LONG */
|
ld = va_arg(va, long); /* FAST PATH: PLAIN LONG */
|
||||||
if (out(ibuf, arg, int64toarray_radix10(ld, ibuf)) == -1) return -1;
|
if (out(ibuf, arg, FormatInt64(ibuf, ld) - ibuf) == -1) return -1;
|
||||||
format += 3;
|
format += 3;
|
||||||
continue;
|
continue;
|
||||||
} else if (format[1] == 'l' && format[2] == 'u') {
|
} else if (format[1] == 'l' && format[2] == 'u') {
|
||||||
lu = va_arg(va, unsigned long); /* FAST PATH: PLAIN UNSIGNED LONG */
|
lu = va_arg(va, unsigned long); /* FAST PATH: PLAIN UNSIGNED LONG */
|
||||||
if (out(ibuf, arg, uint64toarray_radix10(lu, ibuf)) == -1) return -1;
|
if (out(ibuf, arg, FormatUint64(ibuf, lu) - ibuf) == -1) return -1;
|
||||||
format += 3;
|
format += 3;
|
||||||
continue;
|
continue;
|
||||||
} else if (format[1] == '.' && format[2] == '*' && format[3] == 's') {
|
} else if (format[1] == '.' && format[2] == '*' && format[3] == 's') {
|
||||||
|
|
|
@ -24,7 +24,7 @@
|
||||||
* @param p needs at least 12 bytes
|
* @param p needs at least 12 bytes
|
||||||
* @return pointer to nul byte
|
* @return pointer to nul byte
|
||||||
*/
|
*/
|
||||||
dontinline char *FormatUint32(char p[static 12], uint32_t x) {
|
dontinline char *FormatUint32(char p[hasatleast 12], uint32_t x) {
|
||||||
char t;
|
char t;
|
||||||
size_t i, a, b;
|
size_t i, a, b;
|
||||||
i = 0;
|
i = 0;
|
||||||
|
@ -49,7 +49,7 @@ dontinline char *FormatUint32(char p[static 12], uint32_t x) {
|
||||||
* @param p needs at least 12 bytes
|
* @param p needs at least 12 bytes
|
||||||
* @return pointer to nul byte
|
* @return pointer to nul byte
|
||||||
*/
|
*/
|
||||||
char *FormatInt32(char p[static 12], int32_t x) {
|
char *FormatInt32(char p[hasatleast 12], int32_t x) {
|
||||||
if (x < 0) *p++ = '-', x = -(uint32_t)x;
|
if (x < 0) *p++ = '-', x = -(uint32_t)x;
|
||||||
return FormatUint32(p, x);
|
return FormatUint32(p, x);
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
|
/*-*- 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│
|
│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,34 +16,32 @@
|
||||||
│ 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/fmt/conv.h"
|
|
||||||
#include "libc/fmt/itoa.h"
|
#include "libc/fmt/itoa.h"
|
||||||
#include "libc/limits.h"
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Converts unsigned 64-bit integer to string.
|
* Converts unsigned 32-bit integer to octal string.
|
||||||
* @param a needs at least 21 bytes
|
*
|
||||||
* @return bytes written w/o nul
|
* @param p needs at least 12 bytes
|
||||||
|
* @param z ensures it starts with zero
|
||||||
|
* @return pointer to nul byte
|
||||||
*/
|
*/
|
||||||
dontinline size_t uint64toarray_radix10(uint64_t i, char a[hasatleast 21]) {
|
char *FormatOctal32(char p[hasatleast 13], uint32_t x, bool z) {
|
||||||
size_t j = 0;
|
char t;
|
||||||
|
size_t i, a, b;
|
||||||
|
i = 0;
|
||||||
|
z = x && z;
|
||||||
do {
|
do {
|
||||||
a[j++] = i % 10 + '0';
|
p[i++] = x % 8 + '0';
|
||||||
i = i / 10;
|
x = x / 8;
|
||||||
} while (i > 0);
|
} while (x > 0);
|
||||||
a[j] = '\0';
|
if (z) p[i++] = '0';
|
||||||
reverse(a, j);
|
p[i] = '\0';
|
||||||
return j;
|
if (i) {
|
||||||
}
|
for (a = 0, b = i - 1; a < b; ++a, --b) {
|
||||||
|
t = p[a];
|
||||||
/**
|
p[a] = p[b];
|
||||||
* Converts signed 64-bit integer to string.
|
p[b] = t;
|
||||||
* @param a needs at least 21 bytes
|
}
|
||||||
* @return bytes written w/o nul
|
}
|
||||||
*/
|
return p + i;
|
||||||
size_t int64toarray_radix10(int64_t i, char a[hasatleast 21]) {
|
|
||||||
if (i >= 0) return uint64toarray_radix10(i, a);
|
|
||||||
*a++ = '-';
|
|
||||||
return 1 + uint64toarray_radix10(-(uint64_t)i, a);
|
|
||||||
}
|
}
|
47
libc/fmt/formatoctal64.c
Normal file
47
libc/fmt/formatoctal64.c
Normal file
|
@ -0,0 +1,47 @@
|
||||||
|
/*-*- 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/fmt/itoa.h"
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Converts unsigned 64-bit integer to octal string.
|
||||||
|
*
|
||||||
|
* @param p needs at least 12 bytes
|
||||||
|
* @param z ensures it starts with zero
|
||||||
|
* @return pointer to nul byte
|
||||||
|
*/
|
||||||
|
char *FormatOctal64(char p[hasatleast 24], uint64_t x, bool z) {
|
||||||
|
char t;
|
||||||
|
size_t i, a, b;
|
||||||
|
i = 0;
|
||||||
|
z = x && z;
|
||||||
|
do {
|
||||||
|
p[i++] = x % 8 + '0';
|
||||||
|
x = x / 8;
|
||||||
|
} while (x > 0);
|
||||||
|
if (z) p[i++] = '0';
|
||||||
|
p[i] = '\0';
|
||||||
|
if (i) {
|
||||||
|
for (a = 0, b = i - 1; a < b; ++a, --b) {
|
||||||
|
t = p[a];
|
||||||
|
p[a] = p[b];
|
||||||
|
p[b] = t;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return p + i;
|
||||||
|
}
|
|
@ -2,19 +2,6 @@
|
||||||
#define COSMOPOLITAN_LIBC_FMT_ITOA_H_
|
#define COSMOPOLITAN_LIBC_FMT_ITOA_H_
|
||||||
#if !(__ASSEMBLER__ + __LINKER__ + 0)
|
#if !(__ASSEMBLER__ + __LINKER__ + 0)
|
||||||
COSMOPOLITAN_C_START_
|
COSMOPOLITAN_C_START_
|
||||||
/*───────────────────────────────────────────────────────────────────────────│─╗
|
|
||||||
│ cosmopolitan § integer conversion ─╬─│┼
|
|
||||||
╚────────────────────────────────────────────────────────────────────────────│─╝
|
|
||||||
FASTEST + TINY
|
|
||||||
|
|
||||||
- uint64toarray_radix10(0x31337, a) l: 68 (20ns) m: 112 (33ns)
|
|
||||||
- int64toarray_radix10(0x31337, a) l: 69 (20ns) m: 134 (39ns)
|
|
||||||
|
|
||||||
FAST + AWESOME
|
|
||||||
|
|
||||||
- snprintf(a, sizeof(a), "%d", 0x31337) l: 199 (58ns) m: 421 (123ns)
|
|
||||||
- uint128toarray_radix10(0x31337, a) l: 93 (27ns) m: 141 (41ns)
|
|
||||||
- int128toarray_radix10(0x31337, a) l: 96 (28ns) m: 173 (51ns) */
|
|
||||||
|
|
||||||
unsigned LengthInt64(int64_t) pureconst;
|
unsigned LengthInt64(int64_t) pureconst;
|
||||||
unsigned LengthUint64(uint64_t) pureconst;
|
unsigned LengthUint64(uint64_t) pureconst;
|
||||||
|
@ -26,8 +13,8 @@ char *FormatInt64(char[hasatleast 21], int64_t);
|
||||||
char *FormatUint64(char[hasatleast 21], uint64_t);
|
char *FormatUint64(char[hasatleast 21], uint64_t);
|
||||||
char *FormatInt64Thousands(char[hasatleast 27], int64_t);
|
char *FormatInt64Thousands(char[hasatleast 27], int64_t);
|
||||||
char *FormatUint64Thousands(char[hasatleast 27], uint64_t);
|
char *FormatUint64Thousands(char[hasatleast 27], uint64_t);
|
||||||
size_t int64toarray_radix10(int64_t, char[hasatleast 21]);
|
char *FormatOctal32(char[hasatleast 13], uint32_t, bool);
|
||||||
size_t uint64toarray_radix10(uint64_t, char[hasatleast 21]);
|
char *FormatOctal64(char[hasatleast 24], uint64_t, bool);
|
||||||
size_t uint64toarray_radix16(uint64_t, char[hasatleast 17]);
|
size_t uint64toarray_radix16(uint64_t, char[hasatleast 17]);
|
||||||
size_t uint64toarray_fixed16(uint64_t, char[hasatleast 17], uint8_t);
|
size_t uint64toarray_fixed16(uint64_t, char[hasatleast 17], uint8_t);
|
||||||
size_t uint64toarray_radix8(uint64_t, char[hasatleast 24]);
|
size_t uint64toarray_radix8(uint64_t, char[hasatleast 24]);
|
||||||
|
|
|
@ -722,7 +722,7 @@ static void __asan_report_memory_origin(const unsigned char *addr, int size,
|
||||||
if (_base <= addr && addr < _end) {
|
if (_base <= addr && addr < _end) {
|
||||||
__asan_report_memory_origin_image((intptr_t)addr, size);
|
__asan_report_memory_origin_image((intptr_t)addr, size);
|
||||||
} else if (IsAutoFrame((intptr_t)addr >> 16)) {
|
} else if (IsAutoFrame((intptr_t)addr >> 16)) {
|
||||||
__asan_report_memory_origin_heap(addr, size);
|
/* __asan_report_memory_origin_heap(addr, size); */
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1202,8 +1202,9 @@ void __asan_unregister_globals(struct AsanGlobal g[], int n) {
|
||||||
void __asan_evil(uint8_t *addr, int size, const char *s1, const char *s2) {
|
void __asan_evil(uint8_t *addr, int size, const char *s1, const char *s2) {
|
||||||
struct AsanTrace tr;
|
struct AsanTrace tr;
|
||||||
__asan_rawtrace(&tr, __builtin_frame_address(0));
|
__asan_rawtrace(&tr, __builtin_frame_address(0));
|
||||||
kprintf("WARNING: ASAN error during %s bad %d byte %s at %p bt %p %p %p %p%n",
|
kprintf(
|
||||||
s1, size, s2, addr, tr.p[0], tr.p[1], tr.p[2], tr.p[3]);
|
"WARNING: ASAN error during %s bad %d byte %s at %x bt %x %x %x %x %x%n",
|
||||||
|
s1, size, s2, addr, tr.p[0], tr.p[1], tr.p[2], tr.p[3], tr.p[4], tr.p[5]);
|
||||||
}
|
}
|
||||||
|
|
||||||
void __asan_report_load(uint8_t *addr, int size) {
|
void __asan_report_load(uint8_t *addr, int size) {
|
||||||
|
|
|
@ -149,7 +149,7 @@ void(bzero)(void *p, size_t n) {
|
||||||
} while (n);
|
} while (n);
|
||||||
}
|
}
|
||||||
} else if (IsTiny()) {
|
} else if (IsTiny()) {
|
||||||
asm("rep stosb" : "+D"(b), "+c"(n), "=m"(*(char(*)[n])b) : "0"(p), "a"(0));
|
asm("rep stosb" : "+D"(b), "+c"(n), "=m"(*(char(*)[n])b) : "a"(0));
|
||||||
return;
|
return;
|
||||||
} else if (X86_HAVE(AVX)) {
|
} else if (X86_HAVE(AVX)) {
|
||||||
bzero_avx(b, n);
|
bzero_avx(b, n);
|
||||||
|
|
|
@ -116,7 +116,7 @@ o//libc/intrin/memcmp.o \
|
||||||
o//libc/intrin/memset.o \
|
o//libc/intrin/memset.o \
|
||||||
o//libc/intrin/memmove.o: \
|
o//libc/intrin/memmove.o: \
|
||||||
OVERRIDE_CFLAGS += \
|
OVERRIDE_CFLAGS += \
|
||||||
-O2
|
-O2 -finline
|
||||||
|
|
||||||
o/$(MODE)/libc/intrin/bzero.o \
|
o/$(MODE)/libc/intrin/bzero.o \
|
||||||
o/$(MODE)/libc/intrin/memcmp.o \
|
o/$(MODE)/libc/intrin/memcmp.o \
|
||||||
|
|
|
@ -56,11 +56,11 @@ relegated int(AttachDebugger)(intptr_t continuetoaddr) {
|
||||||
struct StackFrame *bp;
|
struct StackFrame *bp;
|
||||||
char pidstr[11], breakcmd[40];
|
char pidstr[11], breakcmd[40];
|
||||||
const char *se, *elf, *gdb, *rewind, *layout;
|
const char *se, *elf, *gdb, *rewind, *layout;
|
||||||
|
__restore_tty();
|
||||||
if (IsGenuineCosmo() || !(gdb = GetGdbPath()) || !isatty(0) || !isatty(1) ||
|
if (IsGenuineCosmo() || !(gdb = GetGdbPath()) || !isatty(0) || !isatty(1) ||
|
||||||
(ttyfd = open(_PATH_TTY, O_RDWR | O_CLOEXEC)) == -1) {
|
(ttyfd = open(_PATH_TTY, O_RDWR | O_CLOEXEC)) == -1) {
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
__restore_tty(ttyfd);
|
|
||||||
ksnprintf(pidstr, sizeof(pidstr), "%u", getpid());
|
ksnprintf(pidstr, sizeof(pidstr), "%u", getpid());
|
||||||
layout = "layout asm";
|
layout = "layout asm";
|
||||||
if ((elf = FindDebugBinary())) {
|
if ((elf = FindDebugBinary())) {
|
||||||
|
|
|
@ -59,11 +59,12 @@ static int PrintBacktraceUsingAddr2line(int fd, const struct StackFrame *bp) {
|
||||||
size_t i, j, gi;
|
size_t i, j, gi;
|
||||||
int ws, pid, pipefds[2];
|
int ws, pid, pipefds[2];
|
||||||
struct Garbages *garbage;
|
struct Garbages *garbage;
|
||||||
sigset_t chldmask, savemask;
|
|
||||||
const struct StackFrame *frame;
|
const struct StackFrame *frame;
|
||||||
char *debugbin, *p1, *p2, *p3, *addr2line;
|
char *debugbin, *p1, *p2, *p3, *addr2line;
|
||||||
char buf[kBacktraceBufSize], *argv[kBacktraceMaxFrames];
|
char buf[kBacktraceBufSize], *argv[kBacktraceMaxFrames];
|
||||||
|
|
||||||
|
return -1;
|
||||||
|
|
||||||
if (!(debugbin = FindDebugBinary())) {
|
if (!(debugbin = FindDebugBinary())) {
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
@ -105,19 +106,15 @@ static int PrintBacktraceUsingAddr2line(int fd, const struct StackFrame *bp) {
|
||||||
argv[i++] = buf + j;
|
argv[i++] = buf + j;
|
||||||
buf[j++] = '0';
|
buf[j++] = '0';
|
||||||
buf[j++] = 'x';
|
buf[j++] = 'x';
|
||||||
j += uint64toarray_radix16(addr, buf + j) + 1;
|
j += uint64toarray_radix16(addr - 1, buf + j) + 1;
|
||||||
}
|
}
|
||||||
argv[i++] = NULL;
|
argv[i++] = NULL;
|
||||||
sigemptyset(&chldmask);
|
|
||||||
sigaddset(&chldmask, SIGCHLD);
|
|
||||||
sigprocmask(SIG_BLOCK, &chldmask, &savemask);
|
|
||||||
pipe(pipefds);
|
pipe(pipefds);
|
||||||
if (!(pid = vfork())) {
|
if (!(pid = vfork())) {
|
||||||
sigprocmask(SIG_SETMASK, &savemask, NULL);
|
|
||||||
dup2(pipefds[1], 1);
|
dup2(pipefds[1], 1);
|
||||||
if (pipefds[0] != 1) close(pipefds[0]);
|
if (pipefds[0] != 1) close(pipefds[0]);
|
||||||
if (pipefds[1] != 1) close(pipefds[1]);
|
if (pipefds[1] != 1) close(pipefds[1]);
|
||||||
execvp(addr2line, argv);
|
execve(addr2line, argv, environ);
|
||||||
_exit(127);
|
_exit(127);
|
||||||
}
|
}
|
||||||
close(pipefds[1]);
|
close(pipefds[1]);
|
||||||
|
@ -150,7 +147,6 @@ static int PrintBacktraceUsingAddr2line(int fd, const struct StackFrame *bp) {
|
||||||
if (errno == EINTR) continue;
|
if (errno == EINTR) continue;
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
sigprocmask(SIG_SETMASK, &savemask, NULL);
|
|
||||||
if (WIFEXITED(ws) && !WEXITSTATUS(ws)) {
|
if (WIFEXITED(ws) && !WEXITSTATUS(ws)) {
|
||||||
return 0;
|
return 0;
|
||||||
} else {
|
} else {
|
|
@ -35,7 +35,7 @@
|
||||||
*/
|
*/
|
||||||
relegated void ___check_fail_ndebug(uint64_t want, uint64_t got,
|
relegated void ___check_fail_ndebug(uint64_t want, uint64_t got,
|
||||||
const char *opchar) {
|
const char *opchar) {
|
||||||
__restore_tty(1);
|
__restore_tty();
|
||||||
kprintf("%n%serror: %s: check failed: 0x%x %s 0x%x (%s)%n",
|
kprintf("%n%serror: %s: check failed: 0x%x %s 0x%x (%s)%n",
|
||||||
!__nocolor ? "\e[J" : "", program_invocation_name, want, opchar, got,
|
!__nocolor ? "\e[J" : "", program_invocation_name, want, opchar, got,
|
||||||
strerror(errno));
|
strerror(errno));
|
||||||
|
|
|
@ -35,7 +35,7 @@ relegated wontreturn void __die(void) {
|
||||||
int rc;
|
int rc;
|
||||||
static bool once;
|
static bool once;
|
||||||
if (_lockcmpxchg(&once, false, true)) {
|
if (_lockcmpxchg(&once, false, true)) {
|
||||||
__restore_tty(1);
|
__restore_tty();
|
||||||
if (IsDebuggerPresent(false)) {
|
if (IsDebuggerPresent(false)) {
|
||||||
DebugBreak();
|
DebugBreak();
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,12 +10,11 @@ COSMOPOLITAN_C_START_
|
||||||
extern hidden bool __nocolor;
|
extern hidden bool __nocolor;
|
||||||
extern hidden int kCrashSigs[7];
|
extern hidden int kCrashSigs[7];
|
||||||
extern hidden bool g_isrunningundermake;
|
extern hidden bool g_isrunningundermake;
|
||||||
extern hidden struct termios g_oldtermios;
|
|
||||||
extern hidden struct sigaction g_oldcrashacts[7];
|
extern hidden struct sigaction g_oldcrashacts[7];
|
||||||
|
|
||||||
void __start_fatal(const char *, int) hidden;
|
void __start_fatal(const char *, int) hidden;
|
||||||
void __oncrash(int, struct siginfo *, struct ucontext *) relegated;
|
void __oncrash(int, struct siginfo *, struct ucontext *) relegated;
|
||||||
void __restore_tty(int);
|
void __restore_tty(void);
|
||||||
|
|
||||||
COSMOPOLITAN_C_END_
|
COSMOPOLITAN_C_END_
|
||||||
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
|
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
|
||||||
|
|
|
@ -77,15 +77,15 @@ extern unsigned __log_level; /* log level for runtime check */
|
||||||
// log a message with the specified log level (not checking if LOGGABLE)
|
// log a message with the specified log level (not checking if LOGGABLE)
|
||||||
#define LOGF(LEVEL, FMT, ...) \
|
#define LOGF(LEVEL, FMT, ...) \
|
||||||
do { \
|
do { \
|
||||||
++g_ftrace; \
|
|
||||||
flogf(LEVEL, __FILE__, __LINE__, NULL, FMT, ##__VA_ARGS__); \
|
|
||||||
--g_ftrace; \
|
--g_ftrace; \
|
||||||
|
flogf(LEVEL, __FILE__, __LINE__, NULL, FMT, ##__VA_ARGS__); \
|
||||||
|
++g_ftrace; \
|
||||||
} while (0)
|
} while (0)
|
||||||
|
|
||||||
// die with an error message without backtrace and debugger invocation
|
// die with an error message without backtrace and debugger invocation
|
||||||
#define DIEF(FMT, ...) \
|
#define DIEF(FMT, ...) \
|
||||||
do { \
|
do { \
|
||||||
++g_ftrace; \
|
--g_ftrace; \
|
||||||
flogf(kLogError, __FILE__, __LINE__, NULL, FMT, ##__VA_ARGS__); \
|
flogf(kLogError, __FILE__, __LINE__, NULL, FMT, ##__VA_ARGS__); \
|
||||||
exit(1); \
|
exit(1); \
|
||||||
unreachable; \
|
unreachable; \
|
||||||
|
@ -93,7 +93,7 @@ extern unsigned __log_level; /* log level for runtime check */
|
||||||
|
|
||||||
#define FATALF(FMT, ...) \
|
#define FATALF(FMT, ...) \
|
||||||
do { \
|
do { \
|
||||||
++g_ftrace; \
|
--g_ftrace; \
|
||||||
ffatalf(kLogFatal, __FILE__, __LINE__, NULL, FMT, ##__VA_ARGS__); \
|
ffatalf(kLogFatal, __FILE__, __LINE__, NULL, FMT, ##__VA_ARGS__); \
|
||||||
unreachable; \
|
unreachable; \
|
||||||
} while (0)
|
} while (0)
|
||||||
|
@ -101,78 +101,78 @@ extern unsigned __log_level; /* log level for runtime check */
|
||||||
#define ERRORF(FMT, ...) \
|
#define ERRORF(FMT, ...) \
|
||||||
do { \
|
do { \
|
||||||
if (LOGGABLE(kLogError)) { \
|
if (LOGGABLE(kLogError)) { \
|
||||||
++g_ftrace; \
|
|
||||||
flogf(kLogError, __FILE__, __LINE__, NULL, FMT, ##__VA_ARGS__); \
|
|
||||||
--g_ftrace; \
|
--g_ftrace; \
|
||||||
|
flogf(kLogError, __FILE__, __LINE__, NULL, FMT, ##__VA_ARGS__); \
|
||||||
|
++g_ftrace; \
|
||||||
} \
|
} \
|
||||||
} while (0)
|
} while (0)
|
||||||
|
|
||||||
#define WARNF(FMT, ...) \
|
#define WARNF(FMT, ...) \
|
||||||
do { \
|
do { \
|
||||||
if (LOGGABLE(kLogWarn)) { \
|
if (LOGGABLE(kLogWarn)) { \
|
||||||
++g_ftrace; \
|
|
||||||
flogf(kLogWarn, __FILE__, __LINE__, NULL, FMT, ##__VA_ARGS__); \
|
|
||||||
--g_ftrace; \
|
--g_ftrace; \
|
||||||
|
flogf(kLogWarn, __FILE__, __LINE__, NULL, FMT, ##__VA_ARGS__); \
|
||||||
|
++g_ftrace; \
|
||||||
} \
|
} \
|
||||||
} while (0)
|
} while (0)
|
||||||
|
|
||||||
#define INFOF(FMT, ...) \
|
#define INFOF(FMT, ...) \
|
||||||
do { \
|
do { \
|
||||||
if (LOGGABLE(kLogInfo)) { \
|
if (LOGGABLE(kLogInfo)) { \
|
||||||
++g_ftrace; \
|
|
||||||
flogf(kLogInfo, __FILE__, __LINE__, NULL, FMT, ##__VA_ARGS__); \
|
|
||||||
--g_ftrace; \
|
--g_ftrace; \
|
||||||
|
flogf(kLogInfo, __FILE__, __LINE__, NULL, FMT, ##__VA_ARGS__); \
|
||||||
|
++g_ftrace; \
|
||||||
} \
|
} \
|
||||||
} while (0)
|
} while (0)
|
||||||
|
|
||||||
#define VERBOSEF(FMT, ...) \
|
#define VERBOSEF(FMT, ...) \
|
||||||
do { \
|
do { \
|
||||||
if (LOGGABLE(kLogVerbose)) { \
|
if (LOGGABLE(kLogVerbose)) { \
|
||||||
++g_ftrace; \
|
|
||||||
fverbosef(kLogVerbose, __FILE__, __LINE__, NULL, FMT, ##__VA_ARGS__); \
|
|
||||||
--g_ftrace; \
|
--g_ftrace; \
|
||||||
|
fverbosef(kLogVerbose, __FILE__, __LINE__, NULL, FMT, ##__VA_ARGS__); \
|
||||||
|
++g_ftrace; \
|
||||||
} \
|
} \
|
||||||
} while (0)
|
} while (0)
|
||||||
|
|
||||||
#define DEBUGF(FMT, ...) \
|
#define DEBUGF(FMT, ...) \
|
||||||
do { \
|
do { \
|
||||||
if (UNLIKELY(LOGGABLE(kLogDebug))) { \
|
if (UNLIKELY(LOGGABLE(kLogDebug))) { \
|
||||||
++g_ftrace; \
|
|
||||||
fdebugf(kLogDebug, __FILE__, __LINE__, NULL, FMT, ##__VA_ARGS__); \
|
|
||||||
--g_ftrace; \
|
--g_ftrace; \
|
||||||
|
fdebugf(kLogDebug, __FILE__, __LINE__, NULL, FMT, ##__VA_ARGS__); \
|
||||||
|
++g_ftrace; \
|
||||||
} \
|
} \
|
||||||
} while (0)
|
} while (0)
|
||||||
|
|
||||||
#define NOISEF(FMT, ...) \
|
#define NOISEF(FMT, ...) \
|
||||||
do { \
|
do { \
|
||||||
if (UNLIKELY(LOGGABLE(kLogNoise))) { \
|
if (UNLIKELY(LOGGABLE(kLogNoise))) { \
|
||||||
++g_ftrace; \
|
|
||||||
fnoisef(kLogNoise, __FILE__, __LINE__, NULL, FMT, ##__VA_ARGS__); \
|
|
||||||
--g_ftrace; \
|
--g_ftrace; \
|
||||||
|
fnoisef(kLogNoise, __FILE__, __LINE__, NULL, FMT, ##__VA_ARGS__); \
|
||||||
|
++g_ftrace; \
|
||||||
} \
|
} \
|
||||||
} while (0)
|
} while (0)
|
||||||
|
|
||||||
#define FLOGF(F, FMT, ...) \
|
#define FLOGF(F, FMT, ...) \
|
||||||
do { \
|
do { \
|
||||||
if (LOGGABLE(kLogInfo)) { \
|
if (LOGGABLE(kLogInfo)) { \
|
||||||
++g_ftrace; \
|
|
||||||
flogf(kLogInfo, __FILE__, __LINE__, F, FMT, ##__VA_ARGS__); \
|
|
||||||
--g_ftrace; \
|
--g_ftrace; \
|
||||||
|
flogf(kLogInfo, __FILE__, __LINE__, F, FMT, ##__VA_ARGS__); \
|
||||||
|
++g_ftrace; \
|
||||||
} \
|
} \
|
||||||
} while (0)
|
} while (0)
|
||||||
|
|
||||||
#define FWARNF(F, FMT, ...) \
|
#define FWARNF(F, FMT, ...) \
|
||||||
do { \
|
do { \
|
||||||
if (LOGGABLE(kLogWarn)) { \
|
if (LOGGABLE(kLogWarn)) { \
|
||||||
++g_ftrace; \
|
|
||||||
flogf(kLogWarn, __FILE__, __LINE__, F, FMT, ##__VA_ARGS__); \
|
|
||||||
--g_ftrace; \
|
--g_ftrace; \
|
||||||
|
flogf(kLogWarn, __FILE__, __LINE__, F, FMT, ##__VA_ARGS__); \
|
||||||
|
++g_ftrace; \
|
||||||
} \
|
} \
|
||||||
} while (0)
|
} while (0)
|
||||||
|
|
||||||
#define FFATALF(F, FMT, ...) \
|
#define FFATALF(F, FMT, ...) \
|
||||||
do { \
|
do { \
|
||||||
++g_ftrace; \
|
--g_ftrace; \
|
||||||
ffatalf(kLogFatal, __FILE__, __LINE__, F, FMT, ##__VA_ARGS__); \
|
ffatalf(kLogFatal, __FILE__, __LINE__, F, FMT, ##__VA_ARGS__); \
|
||||||
unreachable; \
|
unreachable; \
|
||||||
} while (0)
|
} while (0)
|
||||||
|
@ -180,18 +180,18 @@ extern unsigned __log_level; /* log level for runtime check */
|
||||||
#define FDEBUGF(F, FMT, ...) \
|
#define FDEBUGF(F, FMT, ...) \
|
||||||
do { \
|
do { \
|
||||||
if (UNLIKELY(LOGGABLE(kLogDebug))) { \
|
if (UNLIKELY(LOGGABLE(kLogDebug))) { \
|
||||||
++g_ftrace; \
|
|
||||||
fdebugf(kLogDebug, __FILE__, __LINE__, F, FMT, ##__VA_ARGS__); \
|
|
||||||
--g_ftrace; \
|
--g_ftrace; \
|
||||||
|
fdebugf(kLogDebug, __FILE__, __LINE__, F, FMT, ##__VA_ARGS__); \
|
||||||
|
++g_ftrace; \
|
||||||
} \
|
} \
|
||||||
} while (0)
|
} while (0)
|
||||||
|
|
||||||
#define FNOISEF(F, FMT, ...) \
|
#define FNOISEF(F, FMT, ...) \
|
||||||
do { \
|
do { \
|
||||||
if (UNLIKELY(LOGGABLE(kLogNoise))) { \
|
if (UNLIKELY(LOGGABLE(kLogNoise))) { \
|
||||||
++g_ftrace; \
|
|
||||||
fnoisef(kLogNoise, __FILE__, __LINE__, F, FMT, ##__VA_ARGS__); \
|
|
||||||
--g_ftrace; \
|
--g_ftrace; \
|
||||||
|
fnoisef(kLogNoise, __FILE__, __LINE__, F, FMT, ##__VA_ARGS__); \
|
||||||
|
++g_ftrace; \
|
||||||
} \
|
} \
|
||||||
} while (0)
|
} while (0)
|
||||||
|
|
||||||
|
@ -204,9 +204,9 @@ extern unsigned __log_level; /* log level for runtime check */
|
||||||
int e = errno; \
|
int e = errno; \
|
||||||
autotype(FORM) Ax = (FORM); \
|
autotype(FORM) Ax = (FORM); \
|
||||||
if (UNLIKELY(Ax == (typeof(Ax))(-1)) && LOGGABLE(kLogWarn)) { \
|
if (UNLIKELY(Ax == (typeof(Ax))(-1)) && LOGGABLE(kLogWarn)) { \
|
||||||
++g_ftrace; \
|
|
||||||
__logerrno(__FILE__, __LINE__, #FORM); \
|
|
||||||
--g_ftrace; \
|
--g_ftrace; \
|
||||||
|
__logerrno(__FILE__, __LINE__, #FORM); \
|
||||||
|
++g_ftrace; \
|
||||||
errno = e; \
|
errno = e; \
|
||||||
} \
|
} \
|
||||||
Ax; \
|
Ax; \
|
||||||
|
@ -217,9 +217,9 @@ extern unsigned __log_level; /* log level for runtime check */
|
||||||
int e = errno; \
|
int e = errno; \
|
||||||
autotype(FORM) Ax = (FORM); \
|
autotype(FORM) Ax = (FORM); \
|
||||||
if (Ax == NULL && LOGGABLE(kLogWarn)) { \
|
if (Ax == NULL && LOGGABLE(kLogWarn)) { \
|
||||||
++g_ftrace; \
|
|
||||||
__logerrno(__FILE__, __LINE__, #FORM); \
|
|
||||||
--g_ftrace; \
|
--g_ftrace; \
|
||||||
|
__logerrno(__FILE__, __LINE__, #FORM); \
|
||||||
|
++g_ftrace; \
|
||||||
errno = e; \
|
errno = e; \
|
||||||
} \
|
} \
|
||||||
Ax; \
|
Ax; \
|
||||||
|
|
|
@ -41,6 +41,7 @@ LIBC_LOG_A_DIRECTDEPS = \
|
||||||
LIBC_STR \
|
LIBC_STR \
|
||||||
LIBC_STUBS \
|
LIBC_STUBS \
|
||||||
LIBC_SYSV \
|
LIBC_SYSV \
|
||||||
|
LIBC_SYSV_CALLS \
|
||||||
LIBC_TIME \
|
LIBC_TIME \
|
||||||
LIBC_TINYMATH \
|
LIBC_TINYMATH \
|
||||||
LIBC_UNICODE \
|
LIBC_UNICODE \
|
||||||
|
@ -58,8 +59,8 @@ $(LIBC_LOG_A).pkg: \
|
||||||
$(LIBC_LOG_A_OBJS) \
|
$(LIBC_LOG_A_OBJS) \
|
||||||
$(foreach x,$(LIBC_LOG_A_DIRECTDEPS),$($(x)_A).pkg)
|
$(foreach x,$(LIBC_LOG_A_DIRECTDEPS),$($(x)_A).pkg)
|
||||||
|
|
||||||
o/$(MODE)/libc/log/backtrace2.o \
|
o/$(MODE)/libc/log/backtrace2.greg.o \
|
||||||
o/$(MODE)/libc/log/backtrace3.o: \
|
o/$(MODE)/libc/log/backtrace3.greg.o: \
|
||||||
OVERRIDE_CFLAGS += \
|
OVERRIDE_CFLAGS += \
|
||||||
-fno-sanitize=all
|
-fno-sanitize=all
|
||||||
|
|
||||||
|
@ -67,6 +68,7 @@ o/$(MODE)/libc/log/checkfail.o: \
|
||||||
OVERRIDE_CFLAGS += \
|
OVERRIDE_CFLAGS += \
|
||||||
-mgeneral-regs-only
|
-mgeneral-regs-only
|
||||||
|
|
||||||
|
o/$(MODE)/libc/log/restoretty.greg.o \
|
||||||
o/$(MODE)/libc/log/attachdebugger.o \
|
o/$(MODE)/libc/log/attachdebugger.o \
|
||||||
o/$(MODE)/libc/log/backtrace2.o \
|
o/$(MODE)/libc/log/backtrace2.o \
|
||||||
o/$(MODE)/libc/log/backtrace3.o \
|
o/$(MODE)/libc/log/backtrace3.o \
|
||||||
|
|
|
@ -296,7 +296,7 @@ relegated noinstrument void __oncrash(int sig, struct siginfo *si,
|
||||||
: 0);
|
: 0);
|
||||||
}
|
}
|
||||||
if (!(gdbpid > 0 && (sig == SIGTRAP || sig == SIGQUIT))) {
|
if (!(gdbpid > 0 && (sig == SIGTRAP || sig == SIGQUIT))) {
|
||||||
__restore_tty(1);
|
__restore_tty();
|
||||||
ShowCrashReport(err, sig, si, ctx);
|
ShowCrashReport(err, sig, si, ctx);
|
||||||
__restorewintty();
|
__restorewintty();
|
||||||
_Exit(128 + sig);
|
_Exit(128 + sig);
|
||||||
|
|
|
@ -17,8 +17,11 @@
|
||||||
│ 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/metatermios.internal.h"
|
||||||
#include "libc/calls/struct/termios.h"
|
#include "libc/calls/struct/termios.h"
|
||||||
#include "libc/calls/termios.h"
|
#include "libc/calls/termios.h"
|
||||||
|
#include "libc/dce.h"
|
||||||
#include "libc/errno.h"
|
#include "libc/errno.h"
|
||||||
#include "libc/log/color.internal.h"
|
#include "libc/log/color.internal.h"
|
||||||
#include "libc/log/internal.h"
|
#include "libc/log/internal.h"
|
||||||
|
@ -26,7 +29,7 @@
|
||||||
#include "libc/sysv/consts/termios.h"
|
#include "libc/sysv/consts/termios.h"
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @fileoverview Terminal Restoration Helper
|
* @fileoverview Terminal Restoration Helper for System Five.
|
||||||
*
|
*
|
||||||
* This is used by the crash reporting functions, e.g. __die(), to help
|
* This is used by the crash reporting functions, e.g. __die(), to help
|
||||||
* ensure the terminal is in an unborked state after a crash happens.
|
* ensure the terminal is in an unborked state after a crash happens.
|
||||||
|
@ -37,26 +40,28 @@
|
||||||
#define DISABLE_MOUSE "\e[?1000;1002;1015;1006l"
|
#define DISABLE_MOUSE "\e[?1000;1002;1015;1006l"
|
||||||
#define ANSI_RESTORE RESET_COLOR SHOW_CURSOR DISABLE_MOUSE
|
#define ANSI_RESTORE RESET_COLOR SHOW_CURSOR DISABLE_MOUSE
|
||||||
|
|
||||||
struct termios g_oldtermios;
|
static bool __isrestorable;
|
||||||
|
static union metatermios __oldtermios;
|
||||||
|
|
||||||
static textstartup void g_oldtermios_init() {
|
static textstartup void __oldtermios_init() {
|
||||||
int e = errno;
|
int e;
|
||||||
tcgetattr(1, &g_oldtermios);
|
e = errno;
|
||||||
|
if (sys_ioctl(0, TCGETS, &__oldtermios) != -1) {
|
||||||
|
__isrestorable = true;
|
||||||
|
}
|
||||||
errno = e;
|
errno = e;
|
||||||
}
|
}
|
||||||
|
|
||||||
const void *const g_oldtermios_ctor[] initarray = {
|
const void *const __oldtermios_ctor[] initarray = {
|
||||||
g_oldtermios_init,
|
__oldtermios_init,
|
||||||
};
|
};
|
||||||
|
|
||||||
void __restore_tty(int fd) {
|
void __restore_tty(void) {
|
||||||
int e;
|
int e;
|
||||||
if (!__isworker) {
|
if (__isrestorable && !__isworker && !__nocolor) {
|
||||||
e = errno;
|
e = errno;
|
||||||
if (g_oldtermios.c_lflag && !__nocolor && isatty(fd)) {
|
sys_write(0, ANSI_RESTORE, strlen(ANSI_RESTORE));
|
||||||
write(fd, ANSI_RESTORE, strlen(ANSI_RESTORE));
|
sys_ioctl(0, TCSETSF, &__oldtermios);
|
||||||
tcsetattr(fd, TCSAFLUSH, &g_oldtermios);
|
|
||||||
}
|
|
||||||
errno = e;
|
errno = e;
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -27,7 +27,7 @@
|
||||||
* @note this is support code for __check_fail(), __assert_fail(), etc.
|
* @note this is support code for __check_fail(), __assert_fail(), etc.
|
||||||
*/
|
*/
|
||||||
relegated void __start_fatal(const char *file, int line) {
|
relegated void __start_fatal(const char *file, int line) {
|
||||||
__restore_tty(1);
|
__restore_tty();
|
||||||
kprintf("%r%serror%s:%s:%d:%s%s: ", !__nocolor ? "\e[J\e[30;101m" : "",
|
kprintf("%r%serror%s:%s:%d:%s%s: ", !__nocolor ? "\e[J\e[30;101m" : "",
|
||||||
!__nocolor ? "\e[94;49m" : "", file, line,
|
!__nocolor ? "\e[94;49m" : "", file, line,
|
||||||
program_invocation_short_name, !__nocolor ? "\e[0m" : "");
|
program_invocation_short_name, !__nocolor ? "\e[0m" : "");
|
||||||
|
|
|
@ -249,7 +249,7 @@ textwindows int sys_fork_nt(void) {
|
||||||
kNtFileFlagOverlapped, 0);
|
kNtFileFlagOverlapped, 0);
|
||||||
if (pid != -1 && reader != -1 && writer != -1) {
|
if (pid != -1 && reader != -1 && writer != -1) {
|
||||||
p = stpcpy(forkvar, "_FORK=");
|
p = stpcpy(forkvar, "_FORK=");
|
||||||
p += uint64toarray_radix10(reader, p);
|
p = FormatUint64(p, reader);
|
||||||
bzero(&startinfo, sizeof(startinfo));
|
bzero(&startinfo, sizeof(startinfo));
|
||||||
startinfo.cb = sizeof(struct NtStartupInfo);
|
startinfo.cb = sizeof(struct NtStartupInfo);
|
||||||
startinfo.dwFlags = kNtStartfUsestdhandles;
|
startinfo.dwFlags = kNtStartfUsestdhandles;
|
||||||
|
|
|
@ -31,6 +31,7 @@
|
||||||
#include "libc/stdio/stdio.h"
|
#include "libc/stdio/stdio.h"
|
||||||
#include "libc/sysv/consts/map.h"
|
#include "libc/sysv/consts/map.h"
|
||||||
#include "libc/sysv/consts/o.h"
|
#include "libc/sysv/consts/o.h"
|
||||||
|
#include "libc/time/clockstonanos.internal.h"
|
||||||
|
|
||||||
#pragma weak stderr
|
#pragma weak stderr
|
||||||
|
|
||||||
|
@ -89,7 +90,7 @@ privileged noinstrument noasan noubsan void ftracer(void) {
|
||||||
frame = frame->next;
|
frame = frame->next;
|
||||||
if (frame->addr != g_lastaddr) {
|
if (frame->addr != g_lastaddr) {
|
||||||
kprintf("+ %*s%t %d\r\n", GetNestingLevel(frame) * 2, "", frame->addr,
|
kprintf("+ %*s%t %d\r\n", GetNestingLevel(frame) * 2, "", frame->addr,
|
||||||
(long)(unsignedsubtract(stamp, g_laststamp) / 3.3));
|
ClocksToNanos(stamp, g_laststamp));
|
||||||
g_laststamp = X86_HAVE(RDTSCP) ? rdtscp(0) : rdtsc();
|
g_laststamp = X86_HAVE(RDTSCP) ? rdtscp(0) : rdtsc();
|
||||||
g_lastaddr = frame->addr;
|
g_lastaddr = frame->addr;
|
||||||
}
|
}
|
||||||
|
@ -97,14 +98,15 @@ privileged noinstrument noasan noubsan void ftracer(void) {
|
||||||
noreentry = 0;
|
noreentry = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
textstartup void ftrace_install(void) {
|
textstartup int ftrace_install(void) {
|
||||||
if (GetSymbolTable()) {
|
if (GetSymbolTable()) {
|
||||||
g_lastaddr = -1;
|
g_lastaddr = -1;
|
||||||
g_laststamp = kStartTsc;
|
g_laststamp = kStartTsc;
|
||||||
g_skew = GetNestingLevelImpl(__builtin_frame_address(0));
|
g_skew = GetNestingLevelImpl(__builtin_frame_address(0));
|
||||||
ftrace_enabled = 1;
|
ftrace_enabled = 1;
|
||||||
__hook(ftrace_hook, GetSymbolTable());
|
return __hook(ftrace_hook, GetSymbolTable());
|
||||||
} else {
|
} else {
|
||||||
kprintf("error: --ftrace failed to open symbol table\r\n");
|
kprintf("error: --ftrace failed to open symbol table\r\n");
|
||||||
|
return -1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
31
libc/runtime/ismemtracked.greg.c
Normal file
31
libc/runtime/ismemtracked.greg.c
Normal file
|
@ -0,0 +1,31 @@
|
||||||
|
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
|
||||||
|
│vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi│
|
||||||
|
╞══════════════════════════════════════════════════════════════════════════════╡
|
||||||
|
│ Copyright 2022 Justine Alexandra Roberts Tunney │
|
||||||
|
│ │
|
||||||
|
│ Permission to use, copy, modify, and/or distribute this software for │
|
||||||
|
│ any purpose with or without fee is hereby granted, provided that the │
|
||||||
|
│ above copyright notice and this permission notice appear in all copies. │
|
||||||
|
│ │
|
||||||
|
│ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL │
|
||||||
|
│ WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED │
|
||||||
|
│ WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE │
|
||||||
|
│ AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL │
|
||||||
|
│ DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR │
|
||||||
|
│ PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER │
|
||||||
|
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
||||||
|
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||||
|
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||||
|
#include "libc/runtime/memtrack.internal.h"
|
||||||
|
|
||||||
|
bool IsMemtracked(int x, int y) {
|
||||||
|
unsigned i;
|
||||||
|
i = FindMemoryInterval(&_mmi, x);
|
||||||
|
if (i == _mmi.i) return false;
|
||||||
|
if (x < _mmi.p[i].x) return false;
|
||||||
|
for (;;) {
|
||||||
|
if (y <= _mmi.p[i].y) return true;
|
||||||
|
if (++i == _mmi.i) return false;
|
||||||
|
if (_mmi.p[i].x != _mmi.p[i - 1].y + 1) return false;
|
||||||
|
}
|
||||||
|
}
|
|
@ -36,8 +36,8 @@
|
||||||
#include "libc/sysv/consts/prot.h"
|
#include "libc/sysv/consts/prot.h"
|
||||||
#include "libc/sysv/errfuns.h"
|
#include "libc/sysv/errfuns.h"
|
||||||
|
|
||||||
static noasan void *MoveMemoryIntervals(struct MemoryInterval *d,
|
static void *MoveMemoryIntervals(struct MemoryInterval *d,
|
||||||
const struct MemoryInterval *s, int n) {
|
const struct MemoryInterval *s, int n) {
|
||||||
/* asan runtime depends on this function */
|
/* asan runtime depends on this function */
|
||||||
int i;
|
int i;
|
||||||
assert(n >= 0);
|
assert(n >= 0);
|
||||||
|
@ -53,8 +53,7 @@ static noasan void *MoveMemoryIntervals(struct MemoryInterval *d,
|
||||||
return d;
|
return d;
|
||||||
}
|
}
|
||||||
|
|
||||||
static noasan void RemoveMemoryIntervals(struct MemoryIntervals *mm, int i,
|
static void RemoveMemoryIntervals(struct MemoryIntervals *mm, int i, int n) {
|
||||||
int n) {
|
|
||||||
/* asan runtime depends on this function */
|
/* asan runtime depends on this function */
|
||||||
assert(i >= 0);
|
assert(i >= 0);
|
||||||
assert(i + n <= mm->i);
|
assert(i + n <= mm->i);
|
||||||
|
@ -62,7 +61,7 @@ static noasan void RemoveMemoryIntervals(struct MemoryIntervals *mm, int i,
|
||||||
mm->i -= n;
|
mm->i -= n;
|
||||||
}
|
}
|
||||||
|
|
||||||
static noasan bool ExtendMemoryIntervals(struct MemoryIntervals *mm) {
|
static bool ExtendMemoryIntervals(struct MemoryIntervals *mm) {
|
||||||
int prot, flags;
|
int prot, flags;
|
||||||
char *base, *shad;
|
char *base, *shad;
|
||||||
size_t gran, size;
|
size_t gran, size;
|
||||||
|
@ -99,7 +98,7 @@ static noasan bool ExtendMemoryIntervals(struct MemoryIntervals *mm) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
noasan int CreateMemoryInterval(struct MemoryIntervals *mm, int i) {
|
int CreateMemoryInterval(struct MemoryIntervals *mm, int i) {
|
||||||
/* asan runtime depends on this function */
|
/* asan runtime depends on this function */
|
||||||
int rc;
|
int rc;
|
||||||
rc = 0;
|
rc = 0;
|
||||||
|
@ -111,15 +110,15 @@ noasan int CreateMemoryInterval(struct MemoryIntervals *mm, int i) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static noasan int PunchHole(struct MemoryIntervals *mm, int x, int y, int i) {
|
static int PunchHole(struct MemoryIntervals *mm, int x, int y, int i) {
|
||||||
if (CreateMemoryInterval(mm, i) == -1) return -1;
|
if (CreateMemoryInterval(mm, i) == -1) return -1;
|
||||||
mm->p[i].y = x - 1;
|
mm->p[i].y = x - 1;
|
||||||
mm->p[i + 1].x = y + 1;
|
mm->p[i + 1].x = y + 1;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
noasan int ReleaseMemoryIntervals(struct MemoryIntervals *mm, int x, int y,
|
int ReleaseMemoryIntervals(struct MemoryIntervals *mm, int x, int y,
|
||||||
void wf(struct MemoryIntervals *, int, int)) {
|
void wf(struct MemoryIntervals *, int, int)) {
|
||||||
unsigned l, r;
|
unsigned l, r;
|
||||||
assert(y >= x);
|
assert(y >= x);
|
||||||
assert(AreMemoryIntervalsOk(mm));
|
assert(AreMemoryIntervalsOk(mm));
|
||||||
|
@ -158,9 +157,9 @@ noasan int ReleaseMemoryIntervals(struct MemoryIntervals *mm, int x, int y,
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
noasan int TrackMemoryInterval(struct MemoryIntervals *mm, int x, int y, long h,
|
int TrackMemoryInterval(struct MemoryIntervals *mm, int x, int y, long h,
|
||||||
int prot, int flags, bool readonlyfile,
|
int prot, int flags, bool readonlyfile, bool iscow,
|
||||||
bool iscow, long offset, long size) {
|
long offset, long size) {
|
||||||
/* asan runtime depends on this function */
|
/* asan runtime depends on this function */
|
||||||
unsigned i;
|
unsigned i;
|
||||||
assert(y >= x);
|
assert(y >= x);
|
||||||
|
|
|
@ -50,8 +50,9 @@ struct MemoryIntervals {
|
||||||
|
|
||||||
extern hidden struct MemoryIntervals _mmi;
|
extern hidden struct MemoryIntervals _mmi;
|
||||||
|
|
||||||
const char *DescribeFrame(int);
|
bool IsMemtracked(int, int) hidden;
|
||||||
void PrintSystemMappings(int) hidden;
|
void PrintSystemMappings(int) hidden;
|
||||||
|
const char *DescribeFrame(int) hidden;
|
||||||
char *DescribeMapping(int, int, char[hasatleast 8]) hidden;
|
char *DescribeMapping(int, int, char[hasatleast 8]) hidden;
|
||||||
bool AreMemoryIntervalsOk(const struct MemoryIntervals *) nosideeffect hidden;
|
bool AreMemoryIntervalsOk(const struct MemoryIntervals *) nosideeffect hidden;
|
||||||
void PrintMemoryIntervals(int, const struct MemoryIntervals *) hidden;
|
void PrintMemoryIntervals(int, const struct MemoryIntervals *) hidden;
|
||||||
|
@ -175,18 +176,6 @@ forceinline unsigned FindMemoryInterval(const struct MemoryIntervals *mm,
|
||||||
return l;
|
return l;
|
||||||
}
|
}
|
||||||
|
|
||||||
forceinline bool IsMemtracked(int x, int y) {
|
|
||||||
unsigned i;
|
|
||||||
i = FindMemoryInterval(&_mmi, x);
|
|
||||||
if (i == _mmi.i) return false;
|
|
||||||
if (x < _mmi.p[i].x) return false;
|
|
||||||
for (;;) {
|
|
||||||
if (y <= _mmi.p[i].y) return true;
|
|
||||||
if (++i == _mmi.i) return false;
|
|
||||||
if (_mmi.p[i].x != _mmi.p[i - 1].y + 1) return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
COSMOPOLITAN_C_END_
|
COSMOPOLITAN_C_END_
|
||||||
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
|
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
|
||||||
#endif /* COSMOPOLITAN_LIBC_RUNTIME_MEMTRACK_H_ */
|
#endif /* COSMOPOLITAN_LIBC_RUNTIME_MEMTRACK_H_ */
|
||||||
|
|
|
@ -203,9 +203,8 @@ textstartup void __printargs(const char *prologue) {
|
||||||
PRINT(" L%d%s%s %u-way %,u byte cache w/%s "
|
PRINT(" L%d%s%s %u-way %,u byte cache w/%s "
|
||||||
"%,u sets of %,u byte lines shared across %u threads%s",
|
"%,u sets of %,u byte lines shared across %u threads%s",
|
||||||
CPUID4_CACHE_LEVEL,
|
CPUID4_CACHE_LEVEL,
|
||||||
CPUID4_CACHE_TYPE == 1 ? " data"
|
CPUID4_CACHE_TYPE == 1 ? " data"
|
||||||
: CPUID4_CACHE_TYPE == 2 ? " code"
|
: CPUID4_CACHE_TYPE == 2 ? " code" : "",
|
||||||
: "",
|
|
||||||
CPUID4_IS_FULLY_ASSOCIATIVE ? " fully-associative" : "",
|
CPUID4_IS_FULLY_ASSOCIATIVE ? " fully-associative" : "",
|
||||||
CPUID4_WAYS_OF_ASSOCIATIVITY, CPUID4_CACHE_SIZE_IN_BYTES,
|
CPUID4_WAYS_OF_ASSOCIATIVITY, CPUID4_CACHE_SIZE_IN_BYTES,
|
||||||
CPUID4_PHYSICAL_LINE_PARTITIONS > 1 ? " physically partitioned" : "",
|
CPUID4_PHYSICAL_LINE_PARTITIONS > 1 ? " physically partitioned" : "",
|
||||||
|
@ -245,8 +244,8 @@ textstartup void __printargs(const char *prologue) {
|
||||||
if ((n = poll(pfds, ARRAYLEN(pfds), 0)) != -1) {
|
if ((n = poll(pfds, ARRAYLEN(pfds), 0)) != -1) {
|
||||||
for (i = 0; i < ARRAYLEN(pfds); ++i) {
|
for (i = 0; i < ARRAYLEN(pfds); ++i) {
|
||||||
if (i && (pfds[i].revents & POLLNVAL)) continue;
|
if (i && (pfds[i].revents & POLLNVAL)) continue;
|
||||||
PRINT(" ☼ %d (revents=%#hx F_GETFL=%#x)", i, pfds[i].revents,
|
PRINT(" ☼ %d (revents=%#hx fcntl(F_GETFL)=%#x isatty()=%hhhd)", i,
|
||||||
fcntl(i, F_GETFL));
|
pfds[i].revents, fcntl(i, F_GETFL), isatty(i));
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
PRINT(" poll() returned %d %m", n);
|
PRINT(" poll() returned %d %m", n);
|
||||||
|
|
|
@ -98,7 +98,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);
|
int ftrace_install(void);
|
||||||
long GetResourceLimit(int);
|
long GetResourceLimit(int);
|
||||||
long GetMaxFd(void);
|
long GetMaxFd(void);
|
||||||
char *GetProgramExecutableName(void);
|
char *GetProgramExecutableName(void);
|
||||||
|
|
|
@ -70,8 +70,9 @@ o/$(MODE)/libc/runtime/getdosargv.o \
|
||||||
o/$(MODE)/libc/runtime/getdosenviron.o \
|
o/$(MODE)/libc/runtime/getdosenviron.o \
|
||||||
o/$(MODE)/libc/runtime/hook.greg.o \
|
o/$(MODE)/libc/runtime/hook.greg.o \
|
||||||
o/$(MODE)/libc/runtime/isheap.o \
|
o/$(MODE)/libc/runtime/isheap.o \
|
||||||
o/$(MODE)/libc/runtime/memtrack.o \
|
|
||||||
o/$(MODE)/libc/runtime/memtracknt.o \
|
o/$(MODE)/libc/runtime/memtracknt.o \
|
||||||
|
o/$(MODE)/libc/runtime/memtrack.greg.o \
|
||||||
|
o/$(MODE)/libc/runtime/ismemtracked.greg.o \
|
||||||
o/$(MODE)/libc/runtime/metalprintf.greg.o \
|
o/$(MODE)/libc/runtime/metalprintf.greg.o \
|
||||||
o/$(MODE)/libc/runtime/printargs.greg.o \
|
o/$(MODE)/libc/runtime/printargs.greg.o \
|
||||||
o/$(MODE)/libc/runtime/mman.greg.o \
|
o/$(MODE)/libc/runtime/mman.greg.o \
|
||||||
|
|
|
@ -25,12 +25,12 @@
|
||||||
char *inet_ntoa(struct in_addr in) {
|
char *inet_ntoa(struct in_addr in) {
|
||||||
static char buf[16];
|
static char buf[16];
|
||||||
char *p = buf;
|
char *p = buf;
|
||||||
p += int64toarray_radix10((in.s_addr >> 000) & 255, p);
|
p = FormatUint32(p, (in.s_addr >> 000) & 255);
|
||||||
*p++ = '.';
|
*p++ = '.';
|
||||||
p += int64toarray_radix10((in.s_addr >> 010) & 255, p);
|
p = FormatUint32(p, (in.s_addr >> 010) & 255);
|
||||||
*p++ = '.';
|
*p++ = '.';
|
||||||
p += int64toarray_radix10((in.s_addr >> 020) & 255, p);
|
p = FormatUint32(p, (in.s_addr >> 020) & 255);
|
||||||
*p++ = '.';
|
*p++ = '.';
|
||||||
p += int64toarray_radix10((in.s_addr >> 030) & 255, p);
|
p = FormatUint32(p, (in.s_addr >> 030) & 255);
|
||||||
return buf;
|
return buf;
|
||||||
}
|
}
|
||||||
|
|
|
@ -53,19 +53,19 @@ static relegated void DieBecauseOfQuota(int rc, const char *message) {
|
||||||
}
|
}
|
||||||
|
|
||||||
static relegated void OnXcpu(int sig) {
|
static relegated void OnXcpu(int sig) {
|
||||||
__restore_tty(2);
|
__restore_tty();
|
||||||
DieBecauseOfQuota(23, "\n\nSIGXCPU: ran out of cpu");
|
DieBecauseOfQuota(23, "\n\nSIGXCPU: ran out of cpu");
|
||||||
}
|
}
|
||||||
|
|
||||||
static relegated void OnXfsz(int sig) {
|
static relegated void OnXfsz(int sig) {
|
||||||
__restore_tty(2);
|
__restore_tty();
|
||||||
DieBecauseOfQuota(25, "\n\nSIGXFSZ: exceeded maximum file size");
|
DieBecauseOfQuota(25, "\n\nSIGXFSZ: exceeded maximum file size");
|
||||||
}
|
}
|
||||||
|
|
||||||
relegated void __oom_hook(size_t request) {
|
relegated void __oom_hook(size_t request) {
|
||||||
int e;
|
int e;
|
||||||
uint64_t toto, newlim;
|
uint64_t toto, newlim;
|
||||||
__restore_tty(2);
|
__restore_tty();
|
||||||
e = errno;
|
e = errno;
|
||||||
toto = CountMappedBytes();
|
toto = CountMappedBytes();
|
||||||
kprintf("\n\nWE REQUIRE MORE VESPENE GAS");
|
kprintf("\n\nWE REQUIRE MORE VESPENE GAS");
|
||||||
|
|
|
@ -48,7 +48,7 @@ static char *strftime_secs(char *p, const char *pe, const struct tm *t) {
|
||||||
int64_t s;
|
int64_t s;
|
||||||
tmp = *t; /* Make a copy, mktime(3) modifies the tm struct. */
|
tmp = *t; /* Make a copy, mktime(3) modifies the tm struct. */
|
||||||
s = mktime(&tmp);
|
s = mktime(&tmp);
|
||||||
int64toarray_radix10(s, ibuf);
|
FormatInt64(ibuf, s);
|
||||||
return strftime_add(p, pe, ibuf);
|
return strftime_add(p, pe, ibuf);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -329,13 +329,13 @@ static char *strftime_timefmt(char *p, const char *pe, const char *format,
|
||||||
if (t->tm_isdst == 0)
|
if (t->tm_isdst == 0)
|
||||||
#ifdef USG_COMPAT
|
#ifdef USG_COMPAT
|
||||||
diff = -timezone;
|
diff = -timezone;
|
||||||
#else /* !defined USG_COMPAT */
|
#else /* !defined USG_COMPAT */
|
||||||
continue;
|
continue;
|
||||||
#endif /* !defined USG_COMPAT */
|
#endif /* !defined USG_COMPAT */
|
||||||
else
|
else
|
||||||
#ifdef ALTZONE
|
#ifdef ALTZONE
|
||||||
diff = -altzone;
|
diff = -altzone;
|
||||||
#else /* !defined ALTZONE */
|
#else /* !defined ALTZONE */
|
||||||
continue;
|
continue;
|
||||||
#endif /* !defined ALTZONE */
|
#endif /* !defined ALTZONE */
|
||||||
#endif /* !defined TM_GMTOFF */
|
#endif /* !defined TM_GMTOFF */
|
||||||
|
|
|
@ -46,6 +46,13 @@ TEST(open, eexist) {
|
||||||
ASSERT_SYS(EEXIST, -1, open("exists", O_WRONLY | O_CREAT | O_EXCL));
|
ASSERT_SYS(EEXIST, -1, open("exists", O_WRONLY | O_CREAT | O_EXCL));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TEST(open, enametoolong) {
|
||||||
|
size_t n = 260;
|
||||||
|
char *s = gc(xcalloc(1, n + 1));
|
||||||
|
memset(s, 'J', n);
|
||||||
|
ASSERT_SYS(ENAMETOOLONG, -1, creat(s, 0644));
|
||||||
|
}
|
||||||
|
|
||||||
TEST(open, testOpenExistingForWriteOnly_seeksToStart) {
|
TEST(open, testOpenExistingForWriteOnly_seeksToStart) {
|
||||||
char buf[8] = {0};
|
char buf[8] = {0};
|
||||||
ASSERT_SYS(0, 0, xbarf("hello.txt", "hello", -1));
|
ASSERT_SYS(0, 0, xbarf("hello.txt", "hello", -1));
|
||||||
|
|
|
@ -22,29 +22,29 @@
|
||||||
#include "libc/testlib/ezbench.h"
|
#include "libc/testlib/ezbench.h"
|
||||||
#include "libc/testlib/testlib.h"
|
#include "libc/testlib/testlib.h"
|
||||||
|
|
||||||
TEST(int64toarray_radix10, test) {
|
TEST(FormatInt64, test) {
|
||||||
char buf[21];
|
char buf[21];
|
||||||
EXPECT_EQ(1, int64toarray_radix10(0, buf));
|
EXPECT_EQ(1, FormatInt64(buf, 0) - buf);
|
||||||
EXPECT_STREQ("0", buf);
|
EXPECT_STREQ("0", buf);
|
||||||
EXPECT_EQ(1, int64toarray_radix10(1, buf));
|
EXPECT_EQ(1, FormatInt64(buf, 1) - buf);
|
||||||
EXPECT_STREQ("1", buf);
|
EXPECT_STREQ("1", buf);
|
||||||
EXPECT_EQ(2, int64toarray_radix10(-1, buf));
|
EXPECT_EQ(2, FormatInt64(buf, -1) - buf);
|
||||||
EXPECT_STREQ("-1", buf);
|
EXPECT_STREQ("-1", buf);
|
||||||
EXPECT_EQ(19, int64toarray_radix10(INT64_MAX, buf));
|
EXPECT_EQ(19, FormatInt64(buf, INT64_MAX) - buf);
|
||||||
EXPECT_STREQ("9223372036854775807", buf);
|
EXPECT_STREQ("9223372036854775807", buf);
|
||||||
EXPECT_EQ(20, int64toarray_radix10(INT64_MIN, buf));
|
EXPECT_EQ(20, FormatInt64(buf, INT64_MIN) - buf);
|
||||||
EXPECT_STREQ("-9223372036854775808", buf);
|
EXPECT_STREQ("-9223372036854775808", buf);
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(uint64toarray_radix10, test) {
|
TEST(FormatUint64, test) {
|
||||||
char buf[21];
|
char buf[21];
|
||||||
EXPECT_EQ(1, uint64toarray_radix10(0, buf));
|
EXPECT_EQ(1, FormatUint64(buf, 0) - buf);
|
||||||
EXPECT_STREQ("0", buf);
|
EXPECT_STREQ("0", buf);
|
||||||
EXPECT_EQ(4, uint64toarray_radix10(1024, buf));
|
EXPECT_EQ(4, FormatUint64(buf, 1024) - buf);
|
||||||
EXPECT_STREQ("1024", buf);
|
EXPECT_STREQ("1024", buf);
|
||||||
EXPECT_EQ(20, uint64toarray_radix10(UINT64_MAX, buf));
|
EXPECT_EQ(20, FormatUint64(buf, UINT64_MAX) - buf);
|
||||||
EXPECT_STREQ("18446744073709551615", buf);
|
EXPECT_STREQ("18446744073709551615", buf);
|
||||||
EXPECT_EQ(19, uint64toarray_radix10(INT64_MIN, buf));
|
EXPECT_EQ(19, FormatUint64(buf, INT64_MIN) - buf);
|
||||||
EXPECT_STREQ("9223372036854775808", buf);
|
EXPECT_STREQ("9223372036854775808", buf);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -70,5 +70,5 @@ TEST(uint128toarray_radix10, test) {
|
||||||
|
|
||||||
BENCH(itoa64radix10, bench) {
|
BENCH(itoa64radix10, bench) {
|
||||||
char b[21];
|
char b[21];
|
||||||
EZBENCH2("itoa64radix10", donothing, uint64toarray_radix10(UINT64_MAX, b));
|
EZBENCH2("itoa64radix10", donothing, FormatUint64(b, UINT64_MAX));
|
||||||
}
|
}
|
|
@ -76,8 +76,6 @@ TEST(FormatInt64Thousands, testNegative) {
|
||||||
|
|
||||||
BENCH(FormatInt64Thousands, bench) {
|
BENCH(FormatInt64Thousands, bench) {
|
||||||
char s[27];
|
char s[27];
|
||||||
EZBENCH2("int64toarray_radix10(MAX)", donothing,
|
|
||||||
int64toarray_radix10(INT64_MAX, s));
|
|
||||||
EZBENCH2("FormatInt64Thousands(MAX)", donothing,
|
EZBENCH2("FormatInt64Thousands(MAX)", donothing,
|
||||||
FormatInt64Thousands(s, INT64_MAX));
|
FormatInt64Thousands(s, INT64_MAX));
|
||||||
EZBENCH2("FormatInt64Thousands(MIN)", donothing,
|
EZBENCH2("FormatInt64Thousands(MIN)", donothing,
|
||||||
|
|
57
test/libc/fmt/formatoctal32_test.c
Normal file
57
test/libc/fmt/formatoctal32_test.c
Normal file
|
@ -0,0 +1,57 @@
|
||||||
|
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
|
||||||
|
│vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi│
|
||||||
|
╞══════════════════════════════════════════════════════════════════════════════╡
|
||||||
|
│ Copyright 2022 Justine Alexandra Roberts Tunney │
|
||||||
|
│ │
|
||||||
|
│ Permission to use, copy, modify, and/or distribute this software for │
|
||||||
|
│ any purpose with or without fee is hereby granted, provided that the │
|
||||||
|
│ above copyright notice and this permission notice appear in all copies. │
|
||||||
|
│ │
|
||||||
|
│ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL │
|
||||||
|
│ WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED │
|
||||||
|
│ WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE │
|
||||||
|
│ AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL │
|
||||||
|
│ DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR │
|
||||||
|
│ PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER │
|
||||||
|
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
||||||
|
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||||
|
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||||
|
#include "libc/fmt/itoa.h"
|
||||||
|
#include "libc/str/str.h"
|
||||||
|
#include "libc/testlib/testlib.h"
|
||||||
|
|
||||||
|
char buf[13];
|
||||||
|
|
||||||
|
void SetUp(void) {
|
||||||
|
memset(buf, 0x55, sizeof(buf));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(FormatOctal32, test1) {
|
||||||
|
EXPECT_EQ(1, FormatOctal32(buf, 0, true) - buf);
|
||||||
|
EXPECT_STREQ("0", buf);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(FormatOctal32, test2) {
|
||||||
|
EXPECT_EQ(1, FormatOctal32(buf, 0, false) - buf);
|
||||||
|
EXPECT_STREQ("0", buf);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(FormatOctal32, test3) {
|
||||||
|
EXPECT_EQ(2, FormatOctal32(buf, 1, true) - buf);
|
||||||
|
EXPECT_STREQ("01", buf);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(FormatOctal32, test4) {
|
||||||
|
EXPECT_EQ(1, FormatOctal32(buf, 1, false) - buf);
|
||||||
|
EXPECT_STREQ("1", buf);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(FormatOctal32, test5) {
|
||||||
|
EXPECT_EQ(12, FormatOctal32(buf, 037777777777, true) - buf);
|
||||||
|
EXPECT_STREQ("037777777777", buf);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(FormatOctal32, test6) {
|
||||||
|
EXPECT_EQ(11, FormatOctal32(buf, 037777777777, false) - buf);
|
||||||
|
EXPECT_STREQ("37777777777", buf);
|
||||||
|
}
|
66
test/libc/fmt/formatoctal64_test.c
Normal file
66
test/libc/fmt/formatoctal64_test.c
Normal file
|
@ -0,0 +1,66 @@
|
||||||
|
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
|
||||||
|
│vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi│
|
||||||
|
╞══════════════════════════════════════════════════════════════════════════════╡
|
||||||
|
│ Copyright 2022 Justine Alexandra Roberts Tunney │
|
||||||
|
│ │
|
||||||
|
│ Permission to use, copy, modify, and/or distribute this software for │
|
||||||
|
│ any purpose with or without fee is hereby granted, provided that the │
|
||||||
|
│ above copyright notice and this permission notice appear in all copies. │
|
||||||
|
│ │
|
||||||
|
│ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL │
|
||||||
|
│ WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED │
|
||||||
|
│ WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE │
|
||||||
|
│ AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL │
|
||||||
|
│ DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR │
|
||||||
|
│ PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER │
|
||||||
|
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
||||||
|
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||||
|
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||||
|
#include "libc/fmt/itoa.h"
|
||||||
|
#include "libc/str/str.h"
|
||||||
|
#include "libc/testlib/ezbench.h"
|
||||||
|
#include "libc/testlib/testlib.h"
|
||||||
|
|
||||||
|
char buf[25];
|
||||||
|
|
||||||
|
void SetUp(void) {
|
||||||
|
memset(buf, 0x55, sizeof(buf));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(FormatOctal64, test1) {
|
||||||
|
EXPECT_EQ(1, FormatOctal64(buf, 0, true) - buf);
|
||||||
|
EXPECT_STREQ("0", buf);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(FormatOctal64, test2) {
|
||||||
|
EXPECT_EQ(1, FormatOctal64(buf, 0, false) - buf);
|
||||||
|
EXPECT_STREQ("0", buf);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(FormatOctal64, test3) {
|
||||||
|
EXPECT_EQ(2, FormatOctal64(buf, 1, true) - buf);
|
||||||
|
EXPECT_STREQ("01", buf);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(FormatOctal64, test4) {
|
||||||
|
EXPECT_EQ(1, FormatOctal64(buf, 1, false) - buf);
|
||||||
|
EXPECT_STREQ("1", buf);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(FormatOctal64, test5) {
|
||||||
|
EXPECT_EQ(23, FormatOctal64(buf, 01777777777777777777777UL, true) - buf);
|
||||||
|
EXPECT_STREQ("01777777777777777777777", buf);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(FormatOctal64, test6) {
|
||||||
|
EXPECT_EQ(22, FormatOctal64(buf, 01777777777777777777777UL, false) - buf);
|
||||||
|
EXPECT_STREQ("1777777777777777777777", buf);
|
||||||
|
}
|
||||||
|
|
||||||
|
BENCH(FormatOctal64, bench) {
|
||||||
|
EZBENCH2("FormatUint64", donothing,
|
||||||
|
FormatUint64(buf, 01777777777777777777777UL));
|
||||||
|
EZBENCH2("FormatOctal64", donothing,
|
||||||
|
FormatOctal64(buf, 01777777777777777777777UL, true));
|
||||||
|
EZBENCH2("FormatOctal32", donothing, FormatOctal32(buf, 037777777777U, true));
|
||||||
|
}
|
|
@ -641,6 +641,7 @@ BENCH(palandprintf, bench) {
|
||||||
EZBENCH2("%g M_PI", donothing, Format("%g", VEIL("x", M_PI)));
|
EZBENCH2("%g M_PI", donothing, Format("%g", VEIL("x", M_PI)));
|
||||||
EZBENCH2("%a M_PI", donothing, Format("%a", VEIL("x", M_PI)));
|
EZBENCH2("%a M_PI", donothing, Format("%a", VEIL("x", M_PI)));
|
||||||
EZBENCH2("%e M_PI", donothing, Format("%e", VEIL("x", M_PI)));
|
EZBENCH2("%e M_PI", donothing, Format("%e", VEIL("x", M_PI)));
|
||||||
|
EZBENCH2("ULONG_MAX %lo", donothing, Format("%lo", VEIL("r", ULONG_MAX)));
|
||||||
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("INT_MIN %,d", donothing, Format("%,d", VEIL("r", INT_MIN)));
|
EZBENCH2("INT_MIN %,d", donothing, Format("%,d", VEIL("r", INT_MIN)));
|
||||||
|
@ -649,7 +650,6 @@ BENCH(palandprintf, bench) {
|
||||||
EZBENCH2("LONG_MIN %ld", donothing, Format("%ld", VEIL("r", LONG_MIN)));
|
EZBENCH2("LONG_MIN %ld", donothing, Format("%ld", VEIL("r", LONG_MIN)));
|
||||||
EZBENCH2("INT128_MIN %jjd", donothing, Format("%jjd", INT128_MIN));
|
EZBENCH2("INT128_MIN %jjd", donothing, Format("%jjd", INT128_MIN));
|
||||||
EZBENCH2("INT128_MIN %jjx", donothing, Format("%jjx", INT128_MIN));
|
EZBENCH2("INT128_MIN %jjx", donothing, Format("%jjx", INT128_MIN));
|
||||||
EZBENCH2("int64toarray 23", donothing, int64toarray_radix10(23, buffer));
|
EZBENCH2("int64toarray 23", donothing, FormatInt64(buffer, 23));
|
||||||
EZBENCH2("int64toarray min", donothing,
|
EZBENCH2("int64toarray min", donothing, FormatInt64(buffer, INT_MIN));
|
||||||
int64toarray_radix10(INT_MIN, buffer));
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -43,7 +43,8 @@
|
||||||
*/
|
*/
|
||||||
static uint64_t Rando(void) {
|
static uint64_t Rando(void) {
|
||||||
uint64_t x;
|
uint64_t x;
|
||||||
do x = lemur64();
|
do
|
||||||
|
x = lemur64();
|
||||||
while (((x ^ READ64LE("!!!!!!!!")) - 0x0101010101010101) &
|
while (((x ^ READ64LE("!!!!!!!!")) - 0x0101010101010101) &
|
||||||
~(x ^ READ64LE("!!!!!!!!")) & 0x8080808080808080);
|
~(x ^ READ64LE("!!!!!!!!")) & 0x8080808080808080);
|
||||||
return x;
|
return x;
|
||||||
|
@ -375,6 +376,8 @@ BENCH(printf, bench) {
|
||||||
kusnprintf(b, 128, "%hs\n", u"𐌰𐌱𐌲𐌳𐌴𐌵𐌶𐌷"));
|
kusnprintf(b, 128, "%hs\n", u"𐌰𐌱𐌲𐌳𐌴𐌵𐌶𐌷"));
|
||||||
EZBENCH2("snprintf astral", donothing,
|
EZBENCH2("snprintf astral", donothing,
|
||||||
snprintf_(b, 128, "%hs\n", u"𐌰𐌱𐌲𐌳𐌴𐌵𐌶𐌷"));
|
snprintf_(b, 128, "%hs\n", u"𐌰𐌱𐌲𐌳𐌴𐌵𐌶𐌷"));
|
||||||
|
EZBENCH2("kusnprintf octal", donothing,
|
||||||
|
kusnprintf(b, 128, "%#lo", ULONG_MAX));
|
||||||
EZBENCH2("kusnprintf long", donothing, kusnprintf(b, 128, "%ld", LONG_MAX));
|
EZBENCH2("kusnprintf long", donothing, kusnprintf(b, 128, "%ld", LONG_MAX));
|
||||||
EZBENCH2("snprintf long", donothing, snprintf_(b, 128, "%ld", LONG_MAX));
|
EZBENCH2("snprintf long", donothing, snprintf_(b, 128, "%ld", LONG_MAX));
|
||||||
EZBENCH2("kusnprintf thou", donothing, kusnprintf(b, 128, "%'ld", LONG_MAX));
|
EZBENCH2("kusnprintf thou", donothing, kusnprintf(b, 128, "%'ld", LONG_MAX));
|
||||||
|
|
|
@ -33,6 +33,14 @@ STATIC_YOINK("usr/share/zoneinfo/New_York");
|
||||||
|
|
||||||
char testlib_enable_tmp_setup_teardown;
|
char testlib_enable_tmp_setup_teardown;
|
||||||
|
|
||||||
|
DIR *dir;
|
||||||
|
struct dirent *ent;
|
||||||
|
|
||||||
|
void SetUp(void) {
|
||||||
|
dir = 0;
|
||||||
|
ent = 0;
|
||||||
|
}
|
||||||
|
|
||||||
TEST(opendir, efault) {
|
TEST(opendir, efault) {
|
||||||
ASSERT_SYS(EFAULT, NULL, opendir(0));
|
ASSERT_SYS(EFAULT, NULL, opendir(0));
|
||||||
if (!IsAsan()) return; // not possible
|
if (!IsAsan()) return; // not possible
|
||||||
|
@ -50,10 +58,8 @@ TEST(opendir, enotdir) {
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(dirstream, testDots) {
|
TEST(dirstream, testDots) {
|
||||||
DIR *dir;
|
|
||||||
int hasdot = 0;
|
int hasdot = 0;
|
||||||
int hasdotdot = 0;
|
int hasdotdot = 0;
|
||||||
struct dirent *ent;
|
|
||||||
ASSERT_SYS(0, 0, close(creat("foo", 0644)));
|
ASSERT_SYS(0, 0, close(creat("foo", 0644)));
|
||||||
ASSERT_NE(NULL, (dir = opendir(".")));
|
ASSERT_NE(NULL, (dir = opendir(".")));
|
||||||
while ((ent = readdir(dir))) {
|
while ((ent = readdir(dir))) {
|
||||||
|
@ -72,8 +78,6 @@ TEST(dirstream, testDots) {
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(dirstream, test) {
|
TEST(dirstream, test) {
|
||||||
DIR *dir;
|
|
||||||
struct dirent *ent;
|
|
||||||
bool hasfoo = false;
|
bool hasfoo = false;
|
||||||
bool hasbar = false;
|
bool hasbar = false;
|
||||||
char *dpath, *file1, *file2;
|
char *dpath, *file1, *file2;
|
||||||
|
@ -104,21 +108,17 @@ TEST(dirstream, test) {
|
||||||
|
|
||||||
TEST(dirstream, zipTest) {
|
TEST(dirstream, zipTest) {
|
||||||
bool foundNewYork = false;
|
bool foundNewYork = false;
|
||||||
DIR *d;
|
|
||||||
struct dirent *e;
|
|
||||||
const char *path = "/zip/usr/share/zoneinfo/";
|
const char *path = "/zip/usr/share/zoneinfo/";
|
||||||
ASSERT_NE(0, _gc(xiso8601ts(NULL)));
|
ASSERT_NE(0, _gc(xiso8601ts(NULL)));
|
||||||
ASSERT_NE(NULL, (d = opendir(path)));
|
ASSERT_NE(NULL, (dir = opendir(path)));
|
||||||
while ((e = readdir(d))) {
|
while ((ent = readdir(dir))) {
|
||||||
foundNewYork |= !strcmp(e->d_name, "New_York");
|
foundNewYork |= !strcmp(ent->d_name, "New_York");
|
||||||
}
|
}
|
||||||
closedir(d);
|
closedir(dir);
|
||||||
EXPECT_TRUE(foundNewYork);
|
EXPECT_TRUE(foundNewYork);
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(rewinddir, test) {
|
TEST(rewinddir, test) {
|
||||||
DIR *dir;
|
|
||||||
struct dirent *ent;
|
|
||||||
bool hasfoo = false;
|
bool hasfoo = false;
|
||||||
bool hasbar = false;
|
bool hasbar = false;
|
||||||
char *dpath, *file1, *file2;
|
char *dpath, *file1, *file2;
|
||||||
|
|
|
@ -528,7 +528,7 @@ GET / HTTP/1.1\r\n\
|
||||||
X-In-Your-Way-A: a\r\n\
|
X-In-Your-Way-A: a\r\n\
|
||||||
X-In-Your-Way-B: b\r\n\
|
X-In-Your-Way-B: b\r\n\
|
||||||
X-In-Your-Way-C: b\r\n\
|
X-In-Your-Way-C: b\r\n\
|
||||||
Accept-Encoding: deflate\r\n\
|
Accept-Encoding:deflate\r\n\
|
||||||
ACCEPT-ENCODING: gzip\r\n\
|
ACCEPT-ENCODING: gzip\r\n\
|
||||||
ACCEPT-encoding: bzip2\r\n\
|
ACCEPT-encoding: bzip2\r\n\
|
||||||
\r\n";
|
\r\n";
|
||||||
|
|
|
@ -19,7 +19,6 @@
|
||||||
#include "libc/calls/calls.h"
|
#include "libc/calls/calls.h"
|
||||||
#include "libc/calls/sigbits.h"
|
#include "libc/calls/sigbits.h"
|
||||||
#include "libc/fmt/conv.h"
|
#include "libc/fmt/conv.h"
|
||||||
#include "libc/log/check.h"
|
|
||||||
#include "libc/runtime/gc.internal.h"
|
#include "libc/runtime/gc.internal.h"
|
||||||
#include "libc/runtime/runtime.h"
|
#include "libc/runtime/runtime.h"
|
||||||
#include "libc/sock/goodsocket.internal.h"
|
#include "libc/sock/goodsocket.internal.h"
|
||||||
|
@ -91,7 +90,7 @@ char *SendHttpRequest(const char *s) {
|
||||||
bool Matches(const char *regex, const char *str) {
|
bool Matches(const char *regex, const char *str) {
|
||||||
bool r;
|
bool r;
|
||||||
regex_t re;
|
regex_t re;
|
||||||
CHECK_EQ(REG_OK, regcomp(&re, regex, 0));
|
EXPECT_EQ(REG_OK, regcomp(&re, regex, 0));
|
||||||
r = regexec(&re, str, 0, 0, 0) == REG_OK;
|
r = regexec(&re, str, 0, 0, 0) == REG_OK;
|
||||||
regfree(&re);
|
regfree(&re);
|
||||||
return r;
|
return r;
|
||||||
|
@ -103,15 +102,22 @@ TEST(redbean, testOptions) {
|
||||||
int pid, pipefds[2];
|
int pid, pipefds[2];
|
||||||
sigset_t chldmask, savemask;
|
sigset_t chldmask, savemask;
|
||||||
sigaddset(&chldmask, SIGCHLD);
|
sigaddset(&chldmask, SIGCHLD);
|
||||||
CHECK_NE(-1, sigprocmask(SIG_BLOCK, &chldmask, &savemask));
|
EXPECT_NE(-1, sigprocmask(SIG_BLOCK, &chldmask, &savemask));
|
||||||
ASSERT_NE(-1, pipe(pipefds));
|
ASSERT_NE(-1, pipe(pipefds));
|
||||||
ASSERT_NE(-1, (pid = fork()));
|
ASSERT_NE(-1, (pid = fork()));
|
||||||
if (!pid) {
|
if (!pid) {
|
||||||
|
setpgrp();
|
||||||
|
close(0);
|
||||||
|
open("/dev/null", O_RDWR);
|
||||||
|
close(1);
|
||||||
|
dup(0);
|
||||||
|
close(2);
|
||||||
|
open("log", O_CREAT | O_TRUNC | O_WRONLY | O_APPEND, 0644);
|
||||||
close(pipefds[0]);
|
close(pipefds[0]);
|
||||||
dup2(pipefds[1], 1);
|
dup2(pipefds[1], 1);
|
||||||
sigprocmask(SIG_SETMASK, &savemask, NULL);
|
sigprocmask(SIG_SETMASK, &savemask, NULL);
|
||||||
execv("bin/redbean.com",
|
execv("bin/redbean.com",
|
||||||
(char *const[]){"bin/redbean.com", "-szp0", "-l127.0.0.1", 0});
|
(char *const[]){"bin/redbean.com", "-vvszp0", "-l127.0.0.1", 0});
|
||||||
_exit(127);
|
_exit(127);
|
||||||
}
|
}
|
||||||
EXPECT_NE(-1, close(pipefds[1]));
|
EXPECT_NE(-1, close(pipefds[1]));
|
||||||
|
@ -129,7 +135,8 @@ TEST(redbean, testOptions) {
|
||||||
EXPECT_EQ(0, close(pipefds[0]));
|
EXPECT_EQ(0, close(pipefds[0]));
|
||||||
EXPECT_NE(-1, kill(pid, SIGTERM));
|
EXPECT_NE(-1, kill(pid, SIGTERM));
|
||||||
EXPECT_NE(-1, wait(0));
|
EXPECT_NE(-1, wait(0));
|
||||||
CHECK_NE(-1, sigprocmask(SIG_SETMASK, &savemask, 0));
|
EXPECT_NE(-1, sigprocmask(SIG_SETMASK, &savemask, 0));
|
||||||
|
if (g_testlib_failed) fputs(gc(xslurp("log", 0)), stderr);
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(redbean, testPipeline) {
|
TEST(redbean, testPipeline) {
|
||||||
|
@ -138,15 +145,20 @@ TEST(redbean, testPipeline) {
|
||||||
int pid, pipefds[2];
|
int pid, pipefds[2];
|
||||||
sigset_t chldmask, savemask;
|
sigset_t chldmask, savemask;
|
||||||
sigaddset(&chldmask, SIGCHLD);
|
sigaddset(&chldmask, SIGCHLD);
|
||||||
CHECK_NE(-1, sigprocmask(SIG_BLOCK, &chldmask, &savemask));
|
EXPECT_NE(-1, sigprocmask(SIG_BLOCK, &chldmask, &savemask));
|
||||||
ASSERT_NE(-1, pipe(pipefds));
|
ASSERT_NE(-1, pipe(pipefds));
|
||||||
ASSERT_NE(-1, (pid = fork()));
|
ASSERT_NE(-1, (pid = fork()));
|
||||||
if (!pid) {
|
if (!pid) {
|
||||||
|
setpgrp();
|
||||||
|
close(0);
|
||||||
|
open("/dev/null", O_RDWR);
|
||||||
|
close(2);
|
||||||
|
open("log", O_CREAT | O_TRUNC | O_WRONLY | O_APPEND, 0644);
|
||||||
close(pipefds[0]);
|
close(pipefds[0]);
|
||||||
dup2(pipefds[1], 1);
|
dup2(pipefds[1], 1);
|
||||||
sigprocmask(SIG_SETMASK, &savemask, NULL);
|
sigprocmask(SIG_SETMASK, &savemask, NULL);
|
||||||
execv("bin/redbean.com",
|
execv("bin/redbean.com",
|
||||||
(char *const[]){"bin/redbean.com", "-szp0", "-l127.0.0.1", 0});
|
(char *const[]){"bin/redbean.com", "-vvszp0", "-l127.0.0.1", 0});
|
||||||
_exit(127);
|
_exit(127);
|
||||||
}
|
}
|
||||||
EXPECT_NE(-1, close(pipefds[1]));
|
EXPECT_NE(-1, close(pipefds[1]));
|
||||||
|
@ -173,5 +185,6 @@ TEST(redbean, testPipeline) {
|
||||||
EXPECT_EQ(0, close(pipefds[0]));
|
EXPECT_EQ(0, close(pipefds[0]));
|
||||||
EXPECT_NE(-1, kill(pid, SIGTERM));
|
EXPECT_NE(-1, kill(pid, SIGTERM));
|
||||||
EXPECT_NE(-1, wait(0));
|
EXPECT_NE(-1, wait(0));
|
||||||
CHECK_NE(-1, sigprocmask(SIG_SETMASK, &savemask, 0));
|
EXPECT_NE(-1, sigprocmask(SIG_SETMASK, &savemask, 0));
|
||||||
|
if (g_testlib_failed) fputs(gc(xslurp("log", 0)), stderr);
|
||||||
}
|
}
|
||||||
|
|
|
@ -17,6 +17,7 @@
|
||||||
#include "libc/bits/weaken.h"
|
#include "libc/bits/weaken.h"
|
||||||
#include "libc/intrin/kprintf.h"
|
#include "libc/intrin/kprintf.h"
|
||||||
#include "libc/mem/mem.h"
|
#include "libc/mem/mem.h"
|
||||||
|
#include "third_party/dlmalloc/dlmalloc.h"
|
||||||
// clang-format off
|
// clang-format off
|
||||||
|
|
||||||
#define FOOTERS 0
|
#define FOOTERS 0
|
||||||
|
@ -100,7 +101,7 @@
|
||||||
#define FOOTERS 0
|
#define FOOTERS 0
|
||||||
#endif /* FOOTERS */
|
#endif /* FOOTERS */
|
||||||
#ifndef ABORT
|
#ifndef ABORT
|
||||||
#define ABORT abort()
|
#define ABORT dlmalloc_abort()
|
||||||
#endif /* ABORT */
|
#endif /* ABORT */
|
||||||
#ifndef ABORT_ON_ASSERT_FAILURE
|
#ifndef ABORT_ON_ASSERT_FAILURE
|
||||||
#define ABORT_ON_ASSERT_FAILURE 1
|
#define ABORT_ON_ASSERT_FAILURE 1
|
||||||
|
@ -215,588 +216,6 @@
|
||||||
#define FORCEINLINE forceinline
|
#define FORCEINLINE forceinline
|
||||||
#define NOINLINE dontinline
|
#define NOINLINE dontinline
|
||||||
|
|
||||||
#if !ONLY_MSPACES
|
|
||||||
|
|
||||||
/* ------------------- Declarations of public routines ------------------- */
|
|
||||||
|
|
||||||
/*
|
|
||||||
malloc(size_t n)
|
|
||||||
Returns a pointer to a newly allocated chunk of at least n bytes, or
|
|
||||||
null if no space is available, in which case errno is set to ENOMEM
|
|
||||||
on ANSI C systems.
|
|
||||||
|
|
||||||
If n is zero, malloc returns a minimum-sized chunk. (The minimum
|
|
||||||
size is 16 bytes on most 32bit systems, and 32 bytes on 64bit
|
|
||||||
systems.) Note that size_t is an unsigned type, so calls with
|
|
||||||
arguments that would be negative if signed are interpreted as
|
|
||||||
requests for huge amounts of space, which will often fail. The
|
|
||||||
maximum supported value of n differs across systems, but is in all
|
|
||||||
cases less than the maximum representable value of a size_t.
|
|
||||||
*/
|
|
||||||
DLMALLOC_EXPORT void* dlmalloc(size_t);
|
|
||||||
|
|
||||||
/*
|
|
||||||
free(void* p)
|
|
||||||
Releases the chunk of memory pointed to by p, that had been previously
|
|
||||||
allocated using malloc or a related routine such as realloc.
|
|
||||||
It has no effect if p is null. If p was not malloced or already
|
|
||||||
freed, free(p) will by default cause the current program to abort.
|
|
||||||
*/
|
|
||||||
DLMALLOC_EXPORT void dlfree(void*);
|
|
||||||
|
|
||||||
/*
|
|
||||||
calloc(size_t n_elements, size_t element_size);
|
|
||||||
Returns a pointer to n_elements * element_size bytes, with all locations
|
|
||||||
set to zero.
|
|
||||||
*/
|
|
||||||
DLMALLOC_EXPORT void* dlcalloc(size_t, size_t);
|
|
||||||
|
|
||||||
/*
|
|
||||||
realloc(void* p, size_t n)
|
|
||||||
Returns a pointer to a chunk of size n that contains the same data
|
|
||||||
as does chunk p up to the minimum of (n, p's size) bytes, or null
|
|
||||||
if no space is available.
|
|
||||||
|
|
||||||
The returned pointer may or may not be the same as p. The algorithm
|
|
||||||
prefers extending p in most cases when possible, otherwise it
|
|
||||||
employs the equivalent of a malloc-copy-free sequence.
|
|
||||||
|
|
||||||
If p is null, realloc is equivalent to malloc.
|
|
||||||
|
|
||||||
If space is not available, realloc returns null, errno is set (if on
|
|
||||||
ANSI) and p is NOT freed.
|
|
||||||
|
|
||||||
if n is for fewer bytes than already held by p, the newly unused
|
|
||||||
space is lopped off and freed if possible. realloc with a size
|
|
||||||
argument of zero (re)allocates a minimum-sized chunk.
|
|
||||||
|
|
||||||
The old unix realloc convention of allowing the last-free'd chunk
|
|
||||||
to be used as an argument to realloc is not supported.
|
|
||||||
*/
|
|
||||||
DLMALLOC_EXPORT void* dlrealloc(void*, size_t);
|
|
||||||
|
|
||||||
/*
|
|
||||||
realloc_in_place(void* p, size_t n)
|
|
||||||
Resizes the space allocated for p to size n, only if this can be
|
|
||||||
done without moving p (i.e., only if there is adjacent space
|
|
||||||
available if n is greater than p's current allocated size, or n is
|
|
||||||
less than or equal to p's size). This may be used instead of plain
|
|
||||||
realloc if an alternative allocation strategy is needed upon failure
|
|
||||||
to expand space; for example, reallocation of a buffer that must be
|
|
||||||
memory-aligned or cleared. You can use realloc_in_place to trigger
|
|
||||||
these alternatives only when needed.
|
|
||||||
|
|
||||||
Returns p if successful; otherwise null.
|
|
||||||
*/
|
|
||||||
DLMALLOC_EXPORT void* dlrealloc_in_place(void*, size_t);
|
|
||||||
|
|
||||||
/*
|
|
||||||
memalign(size_t alignment, size_t n);
|
|
||||||
Returns a pointer to a newly allocated chunk of n bytes, aligned
|
|
||||||
in accord with the alignment argument.
|
|
||||||
|
|
||||||
The alignment argument should be a power of two. If the argument is
|
|
||||||
not a power of two, the nearest greater power is used.
|
|
||||||
8-byte alignment is guaranteed by normal malloc calls, so don't
|
|
||||||
bother calling memalign with an argument of 8 or less.
|
|
||||||
|
|
||||||
Overreliance on memalign is a sure way to fragment space.
|
|
||||||
*/
|
|
||||||
DLMALLOC_EXPORT void* dlmemalign(size_t, size_t);
|
|
||||||
|
|
||||||
/*
|
|
||||||
int posix_memalign(void** pp, size_t alignment, size_t n);
|
|
||||||
Allocates a chunk of n bytes, aligned in accord with the alignment
|
|
||||||
argument. Differs from memalign only in that it (1) assigns the
|
|
||||||
allocated memory to *pp rather than returning it, (2) fails and
|
|
||||||
returns EINVAL if the alignment is not a power of two (3) fails and
|
|
||||||
returns ENOMEM if memory cannot be allocated.
|
|
||||||
*/
|
|
||||||
DLMALLOC_EXPORT int dlposix_memalign(void**, size_t, size_t);
|
|
||||||
|
|
||||||
/*
|
|
||||||
valloc(size_t n);
|
|
||||||
Equivalent to memalign(pagesize, n), where pagesize is the page
|
|
||||||
size of the system. If the pagesize is unknown, 4096 is used.
|
|
||||||
*/
|
|
||||||
DLMALLOC_EXPORT void* dlvalloc(size_t);
|
|
||||||
|
|
||||||
/*
|
|
||||||
mallopt(int parameter_number, int parameter_value)
|
|
||||||
Sets tunable parameters The format is to provide a
|
|
||||||
(parameter-number, parameter-value) pair. mallopt then sets the
|
|
||||||
corresponding parameter to the argument value if it can (i.e., so
|
|
||||||
long as the value is meaningful), and returns 1 if successful else
|
|
||||||
0. To workaround the fact that mallopt is specified to use int,
|
|
||||||
not size_t parameters, the value -1 is specially treated as the
|
|
||||||
maximum unsigned size_t value.
|
|
||||||
|
|
||||||
SVID/XPG/ANSI defines four standard param numbers for mallopt,
|
|
||||||
normally defined in malloc.h. None of these are use in this malloc,
|
|
||||||
so setting them has no effect. But this malloc also supports other
|
|
||||||
options in mallopt. See below for details. Briefly, supported
|
|
||||||
parameters are as follows (listed defaults are for "typical"
|
|
||||||
configurations).
|
|
||||||
|
|
||||||
Symbol param # default allowed param values
|
|
||||||
M_TRIM_THRESHOLD -1 2*1024*1024 any (-1 disables)
|
|
||||||
M_GRANULARITY -2 page size any power of 2 >= page size
|
|
||||||
M_MMAP_THRESHOLD -3 256*1024 any (or 0 if no MMAP support)
|
|
||||||
*/
|
|
||||||
DLMALLOC_EXPORT int dlmallopt(int, int);
|
|
||||||
|
|
||||||
/*
|
|
||||||
malloc_footprint();
|
|
||||||
Returns the number of bytes obtained from the system. The total
|
|
||||||
number of bytes allocated by malloc, realloc etc., is less than this
|
|
||||||
value. Unlike mallinfo, this function returns only a precomputed
|
|
||||||
result, so can be called frequently to monitor memory consumption.
|
|
||||||
Even if locks are otherwise defined, this function does not use them,
|
|
||||||
so results might not be up to date.
|
|
||||||
*/
|
|
||||||
DLMALLOC_EXPORT size_t dlmalloc_footprint(void);
|
|
||||||
|
|
||||||
/*
|
|
||||||
malloc_max_footprint();
|
|
||||||
Returns the maximum number of bytes obtained from the system. This
|
|
||||||
value will be greater than current footprint if deallocated space
|
|
||||||
has been reclaimed by the system. The peak number of bytes allocated
|
|
||||||
by malloc, realloc etc., is less than this value. Unlike mallinfo,
|
|
||||||
this function returns only a precomputed result, so can be called
|
|
||||||
frequently to monitor memory consumption. Even if locks are
|
|
||||||
otherwise defined, this function does not use them, so results might
|
|
||||||
not be up to date.
|
|
||||||
*/
|
|
||||||
DLMALLOC_EXPORT size_t dlmalloc_max_footprint(void);
|
|
||||||
|
|
||||||
/*
|
|
||||||
malloc_footprint_limit();
|
|
||||||
Returns the number of bytes that the heap is allowed to obtain from
|
|
||||||
the system, returning the last value returned by
|
|
||||||
malloc_set_footprint_limit, or the maximum size_t value if
|
|
||||||
never set. The returned value reflects a permission. There is no
|
|
||||||
guarantee that this number of bytes can actually be obtained from
|
|
||||||
the system.
|
|
||||||
*/
|
|
||||||
DLMALLOC_EXPORT size_t dlmalloc_footprint_limit();
|
|
||||||
|
|
||||||
/*
|
|
||||||
malloc_set_footprint_limit();
|
|
||||||
Sets the maximum number of bytes to obtain from the system, causing
|
|
||||||
failure returns from malloc and related functions upon attempts to
|
|
||||||
exceed this value. The argument value may be subject to page
|
|
||||||
rounding to an enforceable limit; this actual value is returned.
|
|
||||||
Using an argument of the maximum possible size_t effectively
|
|
||||||
disables checks. If the argument is less than or equal to the
|
|
||||||
current malloc_footprint, then all future allocations that require
|
|
||||||
additional system memory will fail. However, invocation cannot
|
|
||||||
retroactively deallocate existing used memory.
|
|
||||||
*/
|
|
||||||
DLMALLOC_EXPORT size_t dlmalloc_set_footprint_limit(size_t bytes);
|
|
||||||
|
|
||||||
#if MALLOC_INSPECT_ALL
|
|
||||||
/*
|
|
||||||
malloc_inspect_all(void(*handler)(void *start,
|
|
||||||
void *end,
|
|
||||||
size_t used_bytes,
|
|
||||||
void* callback_arg),
|
|
||||||
void* arg);
|
|
||||||
Traverses the heap and calls the given handler for each managed
|
|
||||||
region, skipping all bytes that are (or may be) used for bookkeeping
|
|
||||||
purposes. Traversal does not include include chunks that have been
|
|
||||||
directly memory mapped. Each reported region begins at the start
|
|
||||||
address, and continues up to but not including the end address. The
|
|
||||||
first used_bytes of the region contain allocated data. If
|
|
||||||
used_bytes is zero, the region is unallocated. The handler is
|
|
||||||
invoked with the given callback argument. If locks are defined, they
|
|
||||||
are held during the entire traversal. It is a bad idea to invoke
|
|
||||||
other malloc functions from within the handler.
|
|
||||||
|
|
||||||
For example, to count the number of in-use chunks with size greater
|
|
||||||
than 1000, you could write:
|
|
||||||
static int count = 0;
|
|
||||||
void count_chunks(void* start, void* end, size_t used, void* arg) {
|
|
||||||
if (used >= 1000) ++count;
|
|
||||||
}
|
|
||||||
then:
|
|
||||||
malloc_inspect_all(count_chunks, NULL);
|
|
||||||
|
|
||||||
malloc_inspect_all is compiled only if MALLOC_INSPECT_ALL is defined.
|
|
||||||
*/
|
|
||||||
DLMALLOC_EXPORT void dlmalloc_inspect_all(void(*handler)(void*, void *, size_t, void*),
|
|
||||||
void* arg);
|
|
||||||
|
|
||||||
#endif /* MALLOC_INSPECT_ALL */
|
|
||||||
|
|
||||||
/*
|
|
||||||
mallinfo()
|
|
||||||
Returns (by copy) a struct containing various summary statistics:
|
|
||||||
|
|
||||||
arena: current total non-mmapped bytes allocated from system
|
|
||||||
ordblks: the number of free chunks
|
|
||||||
smblks: always zero.
|
|
||||||
hblks: current number of mmapped regions
|
|
||||||
hblkhd: total bytes held in mmapped regions
|
|
||||||
usmblks: the maximum total allocated space. This will be greater
|
|
||||||
than current total if trimming has occurred.
|
|
||||||
fsmblks: always zero
|
|
||||||
uordblks: current total allocated space (normal or mmapped)
|
|
||||||
fordblks: total free space
|
|
||||||
keepcost: the maximum number of bytes that could ideally be released
|
|
||||||
back to system via malloc_trim. ("ideally" means that
|
|
||||||
it ignores page restrictions etc.)
|
|
||||||
|
|
||||||
Because these fields are ints, but internal bookkeeping may
|
|
||||||
be kept as longs, the reported values may wrap around zero and
|
|
||||||
thus be inaccurate.
|
|
||||||
*/
|
|
||||||
DLMALLOC_EXPORT struct mallinfo dlmallinfo(void);
|
|
||||||
|
|
||||||
/*
|
|
||||||
independent_calloc(size_t n_elements, size_t element_size, void* chunks[]);
|
|
||||||
|
|
||||||
independent_calloc is similar to calloc, but instead of returning a
|
|
||||||
single cleared space, it returns an array of pointers to n_elements
|
|
||||||
independent elements that can hold contents of size elem_size, each
|
|
||||||
of which starts out cleared, and can be independently freed,
|
|
||||||
realloc'ed etc. The elements are guaranteed to be adjacently
|
|
||||||
allocated (this is not guaranteed to occur with multiple callocs or
|
|
||||||
mallocs), which may also improve cache locality in some
|
|
||||||
applications.
|
|
||||||
|
|
||||||
The "chunks" argument is optional (i.e., may be null, which is
|
|
||||||
probably the most typical usage). If it is null, the returned array
|
|
||||||
is itself dynamically allocated and should also be freed when it is
|
|
||||||
no longer needed. Otherwise, the chunks array must be of at least
|
|
||||||
n_elements in length. It is filled in with the pointers to the
|
|
||||||
chunks.
|
|
||||||
|
|
||||||
In either case, independent_calloc returns this pointer array, or
|
|
||||||
null if the allocation failed. If n_elements is zero and "chunks"
|
|
||||||
is null, it returns a chunk representing an array with zero elements
|
|
||||||
(which should be freed if not wanted).
|
|
||||||
|
|
||||||
Each element must be freed when it is no longer needed. This can be
|
|
||||||
done all at once using bulk_free.
|
|
||||||
|
|
||||||
independent_calloc simplifies and speeds up implementations of many
|
|
||||||
kinds of pools. It may also be useful when constructing large data
|
|
||||||
structures that initially have a fixed number of fixed-sized nodes,
|
|
||||||
but the number is not known at compile time, and some of the nodes
|
|
||||||
may later need to be freed. For example:
|
|
||||||
|
|
||||||
struct Node { int item; struct Node* next; };
|
|
||||||
|
|
||||||
struct Node* build_list() {
|
|
||||||
struct Node** pool;
|
|
||||||
int n = read_number_of_nodes_needed();
|
|
||||||
if (n <= 0) return 0;
|
|
||||||
pool = (struct Node**)(independent_calloc(n, sizeof(struct Node), 0);
|
|
||||||
if (pool == 0) die();
|
|
||||||
// organize into a linked list...
|
|
||||||
struct Node* first = pool[0];
|
|
||||||
for (i = 0; i < n-1; ++i)
|
|
||||||
pool[i]->next = pool[i+1];
|
|
||||||
free(pool); // Can now free the array (or not, if it is needed later)
|
|
||||||
return first;
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
DLMALLOC_EXPORT void** dlindependent_calloc(size_t, size_t, void**);
|
|
||||||
|
|
||||||
/*
|
|
||||||
independent_comalloc(size_t n_elements, size_t sizes[], void* chunks[]);
|
|
||||||
|
|
||||||
independent_comalloc allocates, all at once, a set of n_elements
|
|
||||||
chunks with sizes indicated in the "sizes" array. It returns
|
|
||||||
an array of pointers to these elements, each of which can be
|
|
||||||
independently freed, realloc'ed etc. The elements are guaranteed to
|
|
||||||
be adjacently allocated (this is not guaranteed to occur with
|
|
||||||
multiple callocs or mallocs), which may also improve cache locality
|
|
||||||
in some applications.
|
|
||||||
|
|
||||||
The "chunks" argument is optional (i.e., may be null). If it is null
|
|
||||||
the returned array is itself dynamically allocated and should also
|
|
||||||
be freed when it is no longer needed. Otherwise, the chunks array
|
|
||||||
must be of at least n_elements in length. It is filled in with the
|
|
||||||
pointers to the chunks.
|
|
||||||
|
|
||||||
In either case, independent_comalloc returns this pointer array, or
|
|
||||||
null if the allocation failed. If n_elements is zero and chunks is
|
|
||||||
null, it returns a chunk representing an array with zero elements
|
|
||||||
(which should be freed if not wanted).
|
|
||||||
|
|
||||||
Each element must be freed when it is no longer needed. This can be
|
|
||||||
done all at once using bulk_free.
|
|
||||||
|
|
||||||
independent_comallac differs from independent_calloc in that each
|
|
||||||
element may have a different size, and also that it does not
|
|
||||||
automatically clear elements.
|
|
||||||
|
|
||||||
independent_comalloc can be used to speed up allocation in cases
|
|
||||||
where several structs or objects must always be allocated at the
|
|
||||||
same time. For example:
|
|
||||||
|
|
||||||
struct Head { ... }
|
|
||||||
struct Foot { ... }
|
|
||||||
|
|
||||||
void send_message(char* msg) {
|
|
||||||
int msglen = strlen(msg);
|
|
||||||
size_t sizes[3] = { sizeof(struct Head), msglen, sizeof(struct Foot) };
|
|
||||||
void* chunks[3];
|
|
||||||
if (independent_comalloc(3, sizes, chunks) == 0)
|
|
||||||
die();
|
|
||||||
struct Head* head = (struct Head*)(chunks[0]);
|
|
||||||
char* body = (char*)(chunks[1]);
|
|
||||||
struct Foot* foot = (struct Foot*)(chunks[2]);
|
|
||||||
// ...
|
|
||||||
}
|
|
||||||
|
|
||||||
In general though, independent_comalloc is worth using only for
|
|
||||||
larger values of n_elements. For small values, you probably won't
|
|
||||||
detect enough difference from series of malloc calls to bother.
|
|
||||||
|
|
||||||
Overuse of independent_comalloc can increase overall memory usage,
|
|
||||||
since it cannot reuse existing noncontiguous small chunks that
|
|
||||||
might be available for some of the elements.
|
|
||||||
*/
|
|
||||||
DLMALLOC_EXPORT void** dlindependent_comalloc(size_t, size_t*, void**);
|
|
||||||
|
|
||||||
/*
|
|
||||||
bulk_free(void* array[], size_t n_elements)
|
|
||||||
Frees and clears (sets to null) each non-null pointer in the given
|
|
||||||
array. This is likely to be faster than freeing them one-by-one.
|
|
||||||
If footers are used, pointers that have been allocated in different
|
|
||||||
mspaces are not freed or cleared, and the count of all such pointers
|
|
||||||
is returned. For large arrays of pointers with poor locality, it
|
|
||||||
may be worthwhile to sort this array before calling bulk_free.
|
|
||||||
*/
|
|
||||||
DLMALLOC_EXPORT size_t dlbulk_free(void**, size_t n_elements);
|
|
||||||
|
|
||||||
/*
|
|
||||||
pvalloc(size_t n);
|
|
||||||
Equivalent to valloc(minimum-page-that-holds(n)), that is,
|
|
||||||
round up n to nearest pagesize.
|
|
||||||
*/
|
|
||||||
DLMALLOC_EXPORT void* dlpvalloc(size_t);
|
|
||||||
|
|
||||||
/*
|
|
||||||
malloc_trim(size_t pad);
|
|
||||||
|
|
||||||
If possible, gives memory back to the system (via negative arguments
|
|
||||||
to sbrk) if there is unused memory at the `high' end of the malloc
|
|
||||||
pool or in unused MMAP segments. You can call this after freeing
|
|
||||||
large blocks of memory to potentially reduce the system-level memory
|
|
||||||
requirements of a program. However, it cannot guarantee to reduce
|
|
||||||
memory. Under some allocation patterns, some large free blocks of
|
|
||||||
memory will be locked between two used chunks, so they cannot be
|
|
||||||
given back to the system.
|
|
||||||
|
|
||||||
The `pad' argument to malloc_trim represents the amount of free
|
|
||||||
trailing space to leave untrimmed. If this argument is zero, only
|
|
||||||
the minimum amount of memory to maintain internal data structures
|
|
||||||
will be left. Non-zero arguments can be supplied to maintain enough
|
|
||||||
trailing space to service future expected allocations without having
|
|
||||||
to re-obtain memory from the system.
|
|
||||||
|
|
||||||
Malloc_trim returns 1 if it actually released any memory, else 0.
|
|
||||||
*/
|
|
||||||
DLMALLOC_EXPORT int dlmalloc_trim(size_t);
|
|
||||||
|
|
||||||
/*
|
|
||||||
malloc_stats();
|
|
||||||
Prints on stderr the amount of space obtained from the system (both
|
|
||||||
via sbrk and mmap), the maximum amount (which may be more than
|
|
||||||
current if malloc_trim and/or munmap got called), and the current
|
|
||||||
number of bytes allocated via malloc (or realloc, etc) but not yet
|
|
||||||
freed. Note that this is the number of bytes allocated, not the
|
|
||||||
number requested. It will be larger than the number requested
|
|
||||||
because of alignment and bookkeeping overhead. Because it includes
|
|
||||||
alignment wastage as being in use, this figure may be greater than
|
|
||||||
zero even when no user-level chunks are allocated.
|
|
||||||
|
|
||||||
The reported current and maximum system memory can be inaccurate if
|
|
||||||
a program makes other calls to system memory allocation functions
|
|
||||||
(normally sbrk) outside of malloc.
|
|
||||||
|
|
||||||
malloc_stats prints only the most commonly interesting statistics.
|
|
||||||
More information can be obtained by calling mallinfo.
|
|
||||||
*/
|
|
||||||
DLMALLOC_EXPORT void dlmalloc_stats(void);
|
|
||||||
|
|
||||||
/*
|
|
||||||
malloc_usable_size(void* p);
|
|
||||||
|
|
||||||
Returns the number of bytes you can actually use in
|
|
||||||
an allocated chunk, which may be more than you requested (although
|
|
||||||
often not) due to alignment and minimum size constraints.
|
|
||||||
You can use this many bytes without worrying about
|
|
||||||
overwriting other allocated objects. This is not a particularly great
|
|
||||||
programming practice. malloc_usable_size can be more useful in
|
|
||||||
debugging and assertions, for example:
|
|
||||||
|
|
||||||
p = malloc(n);
|
|
||||||
assert(malloc_usable_size(p) >= 256);
|
|
||||||
*/
|
|
||||||
size_t dlmalloc_usable_size(void*);
|
|
||||||
|
|
||||||
#endif /* ONLY_MSPACES */
|
|
||||||
|
|
||||||
#if MSPACES
|
|
||||||
|
|
||||||
/*
|
|
||||||
mspace is an opaque type representing an independent
|
|
||||||
region of space that supports mspace_malloc, etc.
|
|
||||||
*/
|
|
||||||
typedef void* mspace;
|
|
||||||
|
|
||||||
/*
|
|
||||||
create_mspace creates and returns a new independent space with the
|
|
||||||
given initial capacity, or, if 0, the default granularity size. It
|
|
||||||
returns null if there is no system memory available to create the
|
|
||||||
space. If argument locked is non-zero, the space uses a separate
|
|
||||||
lock to control access. The capacity of the space will grow
|
|
||||||
dynamically as needed to service mspace_malloc requests. You can
|
|
||||||
control the sizes of incremental increases of this space by
|
|
||||||
compiling with a different DEFAULT_GRANULARITY or dynamically
|
|
||||||
setting with mallopt(M_GRANULARITY, value).
|
|
||||||
*/
|
|
||||||
DLMALLOC_EXPORT mspace create_mspace(size_t capacity, int locked);
|
|
||||||
|
|
||||||
/*
|
|
||||||
destroy_mspace destroys the given space, and attempts to return all
|
|
||||||
of its memory back to the system, returning the total number of
|
|
||||||
bytes freed. After destruction, the results of access to all memory
|
|
||||||
used by the space become undefined.
|
|
||||||
*/
|
|
||||||
DLMALLOC_EXPORT size_t destroy_mspace(mspace msp);
|
|
||||||
|
|
||||||
/*
|
|
||||||
create_mspace_with_base uses the memory supplied as the initial base
|
|
||||||
of a new mspace. Part (less than 128*sizeof(size_t) bytes) of this
|
|
||||||
space is used for bookkeeping, so the capacity must be at least this
|
|
||||||
large. (Otherwise 0 is returned.) When this initial space is
|
|
||||||
exhausted, additional memory will be obtained from the system.
|
|
||||||
Destroying this space will deallocate all additionally allocated
|
|
||||||
space (if possible) but not the initial base.
|
|
||||||
*/
|
|
||||||
DLMALLOC_EXPORT mspace create_mspace_with_base(void* base, size_t capacity, int locked);
|
|
||||||
|
|
||||||
/*
|
|
||||||
mspace_track_large_chunks controls whether requests for large chunks
|
|
||||||
are allocated in their own untracked mmapped regions, separate from
|
|
||||||
others in this mspace. By default large chunks are not tracked,
|
|
||||||
which reduces fragmentation. However, such chunks are not
|
|
||||||
necessarily released to the system upon destroy_mspace. Enabling
|
|
||||||
tracking by setting to true may increase fragmentation, but avoids
|
|
||||||
leakage when relying on destroy_mspace to release all memory
|
|
||||||
allocated using this space. The function returns the previous
|
|
||||||
setting.
|
|
||||||
*/
|
|
||||||
DLMALLOC_EXPORT int mspace_track_large_chunks(mspace msp, int enable);
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
|
||||||
mspace_malloc behaves as malloc, but operates within
|
|
||||||
the given space.
|
|
||||||
*/
|
|
||||||
DLMALLOC_EXPORT void* mspace_malloc(mspace msp, size_t bytes);
|
|
||||||
|
|
||||||
/*
|
|
||||||
mspace_free behaves as free, but operates within
|
|
||||||
the given space.
|
|
||||||
|
|
||||||
If compiled with FOOTERS==1, mspace_free is not actually needed.
|
|
||||||
free may be called instead of mspace_free because freed chunks from
|
|
||||||
any space are handled by their originating spaces.
|
|
||||||
*/
|
|
||||||
DLMALLOC_EXPORT void mspace_free(mspace msp, void* mem);
|
|
||||||
|
|
||||||
/*
|
|
||||||
mspace_realloc behaves as realloc, but operates within
|
|
||||||
the given space.
|
|
||||||
|
|
||||||
If compiled with FOOTERS==1, mspace_realloc is not actually
|
|
||||||
needed. realloc may be called instead of mspace_realloc because
|
|
||||||
realloced chunks from any space are handled by their originating
|
|
||||||
spaces.
|
|
||||||
*/
|
|
||||||
DLMALLOC_EXPORT void* mspace_realloc(mspace msp, void* mem, size_t newsize);
|
|
||||||
|
|
||||||
/*
|
|
||||||
mspace_calloc behaves as calloc, but operates within
|
|
||||||
the given space.
|
|
||||||
*/
|
|
||||||
DLMALLOC_EXPORT void* mspace_calloc(mspace msp, size_t n_elements, size_t elem_size);
|
|
||||||
|
|
||||||
/*
|
|
||||||
mspace_memalign behaves as memalign, but operates within
|
|
||||||
the given space.
|
|
||||||
*/
|
|
||||||
DLMALLOC_EXPORT void* mspace_memalign(mspace msp, size_t alignment, size_t bytes);
|
|
||||||
|
|
||||||
/*
|
|
||||||
mspace_independent_calloc behaves as independent_calloc, but
|
|
||||||
operates within the given space.
|
|
||||||
*/
|
|
||||||
DLMALLOC_EXPORT void** mspace_independent_calloc(mspace msp, size_t n_elements,
|
|
||||||
size_t elem_size, void* chunks[]);
|
|
||||||
|
|
||||||
/*
|
|
||||||
mspace_independent_comalloc behaves as independent_comalloc, but
|
|
||||||
operates within the given space.
|
|
||||||
*/
|
|
||||||
DLMALLOC_EXPORT void** mspace_independent_comalloc(mspace msp, size_t n_elements,
|
|
||||||
size_t sizes[], void* chunks[]);
|
|
||||||
|
|
||||||
/*
|
|
||||||
mspace_footprint() returns the number of bytes obtained from the
|
|
||||||
system for this space.
|
|
||||||
*/
|
|
||||||
DLMALLOC_EXPORT size_t mspace_footprint(mspace msp);
|
|
||||||
|
|
||||||
/*
|
|
||||||
mspace_max_footprint() returns the peak number of bytes obtained from the
|
|
||||||
system for this space.
|
|
||||||
*/
|
|
||||||
DLMALLOC_EXPORT size_t mspace_max_footprint(mspace msp);
|
|
||||||
|
|
||||||
|
|
||||||
#if !NO_MALLINFO
|
|
||||||
/*
|
|
||||||
mspace_mallinfo behaves as mallinfo, but reports properties of
|
|
||||||
the given space.
|
|
||||||
*/
|
|
||||||
DLMALLOC_EXPORT struct mallinfo mspace_mallinfo(mspace msp);
|
|
||||||
#endif /* NO_MALLINFO */
|
|
||||||
|
|
||||||
/*
|
|
||||||
malloc_usable_size(void* p) behaves the same as malloc_usable_size;
|
|
||||||
*/
|
|
||||||
DLMALLOC_EXPORT size_t mspace_usable_size(const void* mem);
|
|
||||||
|
|
||||||
/*
|
|
||||||
mspace_malloc_stats behaves as malloc_stats, but reports
|
|
||||||
properties of the given space.
|
|
||||||
*/
|
|
||||||
DLMALLOC_EXPORT void mspace_malloc_stats(mspace msp);
|
|
||||||
|
|
||||||
/*
|
|
||||||
mspace_trim behaves as malloc_trim, but
|
|
||||||
operates within the given space.
|
|
||||||
*/
|
|
||||||
DLMALLOC_EXPORT int mspace_trim(mspace msp, size_t pad);
|
|
||||||
|
|
||||||
/*
|
|
||||||
An alias for mallopt.
|
|
||||||
*/
|
|
||||||
DLMALLOC_EXPORT int mspace_mallopt(int, int);
|
|
||||||
|
|
||||||
#endif /* MSPACES */
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
|
||||||
} /* end of extern "C" */
|
|
||||||
#endif /* __cplusplus */
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
========================================================================
|
========================================================================
|
||||||
To make a fully customizable malloc.h header file, cut everything
|
To make a fully customizable malloc.h header file, cut everything
|
||||||
|
@ -4364,7 +3783,7 @@ int dlmallopt(int param_number, int value) {
|
||||||
return change_mparam(param_number, value);
|
return change_mparam(param_number, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t dlmalloc_usable_size(void* mem) {
|
size_t dlmalloc_usable_size(const void* mem) {
|
||||||
mchunkptr p;
|
mchunkptr p;
|
||||||
size_t bytes;
|
size_t bytes;
|
||||||
if (mem) {
|
if (mem) {
|
2
third_party/dlmalloc/dlmalloc.h
vendored
2
third_party/dlmalloc/dlmalloc.h
vendored
|
@ -505,6 +505,8 @@ void mspace_inspect_all(mspace msp,
|
||||||
void (*handler)(void*, void*, size_t, void*),
|
void (*handler)(void*, void*, size_t, void*),
|
||||||
void* arg);
|
void* arg);
|
||||||
|
|
||||||
|
void dlmalloc_abort(void);
|
||||||
|
|
||||||
COSMOPOLITAN_C_END_
|
COSMOPOLITAN_C_END_
|
||||||
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
|
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
|
||||||
#endif /* COSMOPOLITAN_THIRD_PARTY_DLMALLOC_DLMALLOC_H_ */
|
#endif /* COSMOPOLITAN_THIRD_PARTY_DLMALLOC_DLMALLOC_H_ */
|
||||||
|
|
1
third_party/dlmalloc/dlmalloc.mk
vendored
1
third_party/dlmalloc/dlmalloc.mk
vendored
|
@ -52,6 +52,7 @@ $(THIRD_PARTY_DLMALLOC_A).pkg: \
|
||||||
$(THIRD_PARTY_DLMALLOC_A_OBJS): \
|
$(THIRD_PARTY_DLMALLOC_A_OBJS): \
|
||||||
OVERRIDE_CFLAGS += \
|
OVERRIDE_CFLAGS += \
|
||||||
$(NO_MAGIC) \
|
$(NO_MAGIC) \
|
||||||
|
-ffreestanding \
|
||||||
-ffunction-sections \
|
-ffunction-sections \
|
||||||
-fdata-sections
|
-fdata-sections
|
||||||
|
|
||||||
|
|
29
third_party/dlmalloc/dlmalloc_abort.greg.c
vendored
Normal file
29
third_party/dlmalloc/dlmalloc_abort.greg.c
vendored
Normal file
|
@ -0,0 +1,29 @@
|
||||||
|
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
|
||||||
|
│vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi│
|
||||||
|
╞══════════════════════════════════════════════════════════════════════════════╡
|
||||||
|
│ Copyright 2022 Justine Alexandra Roberts Tunney │
|
||||||
|
│ │
|
||||||
|
│ Permission to use, copy, modify, and/or distribute this software for │
|
||||||
|
│ any purpose with or without fee is hereby granted, provided that the │
|
||||||
|
│ above copyright notice and this permission notice appear in all copies. │
|
||||||
|
│ │
|
||||||
|
│ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL │
|
||||||
|
│ WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED │
|
||||||
|
│ WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE │
|
||||||
|
│ AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL │
|
||||||
|
│ DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR │
|
||||||
|
│ PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER │
|
||||||
|
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
||||||
|
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||||
|
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||||
|
#include "libc/bits/weaken.h"
|
||||||
|
#include "libc/intrin/kprintf.h"
|
||||||
|
#include "libc/log/log.h"
|
||||||
|
#include "libc/runtime/runtime.h"
|
||||||
|
#include "third_party/dlmalloc/dlmalloc.h"
|
||||||
|
|
||||||
|
void dlmalloc_abort(void) {
|
||||||
|
kprintf("dlmalloc_abort()%n");
|
||||||
|
if (weaken(__die)) weaken(__die)();
|
||||||
|
_Exit(44);
|
||||||
|
}
|
1027
third_party/linenoise/linenoise.c
vendored
1027
third_party/linenoise/linenoise.c
vendored
File diff suppressed because it is too large
Load diff
20
third_party/linenoise/linenoise.h
vendored
20
third_party/linenoise/linenoise.h
vendored
|
@ -1,8 +1,11 @@
|
||||||
#ifndef COSMOPOLITAN_THIRD_PARTY_LINENOISE_LINENOISE_H_
|
#ifndef COSMOPOLITAN_THIRD_PARTY_LINENOISE_LINENOISE_H_
|
||||||
#define COSMOPOLITAN_THIRD_PARTY_LINENOISE_LINENOISE_H_
|
#define COSMOPOLITAN_THIRD_PARTY_LINENOISE_LINENOISE_H_
|
||||||
|
#include "libc/calls/struct/winsize.h"
|
||||||
|
#include "libc/stdio/stdio.h"
|
||||||
#if !(__ASSEMBLER__ + __LINKER__ + 0)
|
#if !(__ASSEMBLER__ + __LINKER__ + 0)
|
||||||
COSMOPOLITAN_C_START_
|
COSMOPOLITAN_C_START_
|
||||||
|
|
||||||
|
struct linenoiseState;
|
||||||
typedef struct linenoiseCompletions {
|
typedef struct linenoiseCompletions {
|
||||||
size_t len;
|
size_t len;
|
||||||
char **cvec;
|
char **cvec;
|
||||||
|
@ -13,17 +16,14 @@ typedef char *(linenoiseHintsCallback)(const char *, const char **,
|
||||||
const char **);
|
const char **);
|
||||||
typedef void(linenoiseFreeHintsCallback)(void *);
|
typedef void(linenoiseFreeHintsCallback)(void *);
|
||||||
typedef wint_t(linenoiseXlatCallback)(wint_t);
|
typedef wint_t(linenoiseXlatCallback)(wint_t);
|
||||||
typedef int(linenoisePollCallback)(int, int);
|
|
||||||
|
|
||||||
void linenoiseSetCompletionCallback(linenoiseCompletionCallback *);
|
void linenoiseSetCompletionCallback(linenoiseCompletionCallback *);
|
||||||
void linenoiseSetHintsCallback(linenoiseHintsCallback *);
|
void linenoiseSetHintsCallback(linenoiseHintsCallback *);
|
||||||
void linenoiseSetFreeHintsCallback(linenoiseFreeHintsCallback *);
|
void linenoiseSetFreeHintsCallback(linenoiseFreeHintsCallback *);
|
||||||
void linenoiseAddCompletion(linenoiseCompletions *, const char *);
|
void linenoiseAddCompletion(linenoiseCompletions *, const char *);
|
||||||
void linenoiseSetXlatCallback(linenoiseXlatCallback *);
|
void linenoiseSetXlatCallback(linenoiseXlatCallback *);
|
||||||
void linenoiseSetPollCallback(linenoisePollCallback *);
|
|
||||||
|
|
||||||
char *linenoise(const char *) dontdiscard;
|
char *linenoise(const char *) dontdiscard;
|
||||||
char *linenoiseRaw(const char *, int, int) dontdiscard;
|
|
||||||
char *linenoiseWithHistory(const char *, const char *) dontdiscard;
|
char *linenoiseWithHistory(const char *, const char *) dontdiscard;
|
||||||
int linenoiseHistoryAdd(const char *);
|
int linenoiseHistoryAdd(const char *);
|
||||||
int linenoiseHistorySave(const char *);
|
int linenoiseHistorySave(const char *);
|
||||||
|
@ -33,8 +33,22 @@ void linenoiseHistoryFree(void);
|
||||||
void linenoiseClearScreen(int);
|
void linenoiseClearScreen(int);
|
||||||
void linenoiseMaskModeEnable(void);
|
void linenoiseMaskModeEnable(void);
|
||||||
void linenoiseMaskModeDisable(void);
|
void linenoiseMaskModeDisable(void);
|
||||||
|
int linenoiseEnableRawMode(int);
|
||||||
void linenoiseDisableRawMode(void);
|
void linenoiseDisableRawMode(void);
|
||||||
void linenoiseFree(void *);
|
void linenoiseFree(void *);
|
||||||
|
int linenoiseIsTerminal(void);
|
||||||
|
int linenoiseIsTeletype(void);
|
||||||
|
|
||||||
|
char *linenoiseGetHistoryPath(const char *);
|
||||||
|
struct linenoiseState *linenoiseBegin(const char *, int, int);
|
||||||
|
ssize_t linenoiseEdit(struct linenoiseState *, const char *, char **, bool);
|
||||||
|
int linenoiseGetInterrupt(void);
|
||||||
|
void linenoiseEnd(struct linenoiseState *);
|
||||||
|
|
||||||
|
char *linenoiseGetLine(FILE *);
|
||||||
|
struct winsize linenoiseGetTerminalSize(struct winsize, int, int);
|
||||||
|
void linenoiseRefreshLine(struct linenoiseState *);
|
||||||
|
char *linenoiseRaw(const char *, int, int) dontdiscard;
|
||||||
|
|
||||||
COSMOPOLITAN_C_END_
|
COSMOPOLITAN_C_END_
|
||||||
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
|
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
|
||||||
|
|
1
third_party/linenoise/linenoise.mk
vendored
1
third_party/linenoise/linenoise.mk
vendored
|
@ -25,6 +25,7 @@ THIRD_PARTY_LINENOISE_A_DIRECTDEPS = \
|
||||||
LIBC_SOCK \
|
LIBC_SOCK \
|
||||||
LIBC_STDIO \
|
LIBC_STDIO \
|
||||||
LIBC_RUNTIME \
|
LIBC_RUNTIME \
|
||||||
|
LIBC_LOG \
|
||||||
LIBC_SYSV_CALLS \
|
LIBC_SYSV_CALLS \
|
||||||
LIBC_STR \
|
LIBC_STR \
|
||||||
LIBC_UNICODE \
|
LIBC_UNICODE \
|
||||||
|
|
89
third_party/lua/lrepl.c
vendored
89
third_party/lua/lrepl.c
vendored
|
@ -1,6 +1,9 @@
|
||||||
#define lua_c
|
#define lua_c
|
||||||
#include "libc/calls/calls.h"
|
#include "libc/calls/calls.h"
|
||||||
#include "libc/calls/sigbits.h"
|
#include "libc/calls/sigbits.h"
|
||||||
|
#include "libc/intrin/kprintf.h"
|
||||||
|
#include "libc/intrin/nomultics.internal.h"
|
||||||
|
#include "libc/intrin/spinlock.h"
|
||||||
#include "libc/log/check.h"
|
#include "libc/log/check.h"
|
||||||
#include "libc/runtime/gc.h"
|
#include "libc/runtime/gc.h"
|
||||||
#include "libc/runtime/runtime.h"
|
#include "libc/runtime/runtime.h"
|
||||||
|
@ -13,8 +16,13 @@
|
||||||
#include "third_party/lua/lualib.h"
|
#include "third_party/lua/lualib.h"
|
||||||
// clang-format off
|
// clang-format off
|
||||||
|
|
||||||
|
bool lua_repl_blocking;
|
||||||
|
bool lua_repl_isterminal;
|
||||||
|
_Alignas(64) char lualock;
|
||||||
|
struct linenoiseState *lua_repl_linenoise;
|
||||||
static lua_State *globalL;
|
static lua_State *globalL;
|
||||||
static const char *g_progname;
|
static const char *g_progname;
|
||||||
|
static const char *g_historypath;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
** {==================================================================
|
** {==================================================================
|
||||||
|
@ -111,14 +119,35 @@ static int incomplete (lua_State *L, int status) {
|
||||||
/*
|
/*
|
||||||
** Prompt the user, read a line, and push it into the Lua stack.
|
** Prompt the user, read a line, and push it into the Lua stack.
|
||||||
*/
|
*/
|
||||||
static int pushline (lua_State *L, int firstline) {
|
static ssize_t pushline (lua_State *L, int firstline) {
|
||||||
char *b;
|
char *b;
|
||||||
size_t l;
|
size_t l;
|
||||||
|
ssize_t rc;
|
||||||
|
char *prmt;
|
||||||
globalL = L;
|
globalL = L;
|
||||||
const char *prmt = get_prompt(L, firstline);
|
if (lua_repl_isterminal) {
|
||||||
if (!(b = linenoiseWithHistory(prmt, g_progname)))
|
prmt = strdup(get_prompt(L, firstline));
|
||||||
return 0; /* no input (prompt will be popped by caller) */
|
lua_pop(L, 1); /* remove prompt */
|
||||||
lua_pop(L, 1); /* remove prompt */
|
_spunlock(&lualock);
|
||||||
|
rc = linenoiseEdit(lua_repl_linenoise, prmt, &b, !firstline || lua_repl_blocking);
|
||||||
|
free(prmt);
|
||||||
|
if (rc != -1) {
|
||||||
|
if (b && *b) {
|
||||||
|
linenoiseHistoryLoad(g_historypath);
|
||||||
|
linenoiseHistoryAdd(b);
|
||||||
|
linenoiseHistorySave(g_historypath);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_spinlock(&lualock);
|
||||||
|
} else {
|
||||||
|
_spunlock(&lualock);
|
||||||
|
b = linenoiseGetLine(stdin);
|
||||||
|
_spinlock(&lualock);
|
||||||
|
rc = b ? 1 : -1;
|
||||||
|
}
|
||||||
|
if (rc == -1 || (!rc && !b)) {
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
l = strlen(b);
|
l = strlen(b);
|
||||||
if (l > 0 && b[l-1] == '\n') /* line ends with newline? */
|
if (l > 0 && b[l-1] == '\n') /* line ends with newline? */
|
||||||
b[--l] = '\0'; /* remove it */
|
b[--l] = '\0'; /* remove it */
|
||||||
|
@ -164,9 +193,10 @@ static void lstop (lua_State *L, lua_Debug *ar) {
|
||||||
static int multiline (lua_State *L) {
|
static int multiline (lua_State *L) {
|
||||||
for (;;) { /* repeat until gets a complete statement */
|
for (;;) { /* repeat until gets a complete statement */
|
||||||
size_t len;
|
size_t len;
|
||||||
|
ssize_t rc;
|
||||||
const char *line = lua_tolstring(L, 1, &len); /* get what it has */
|
const char *line = lua_tolstring(L, 1, &len); /* get what it has */
|
||||||
int status = luaL_loadbuffer(L, line, len, "=stdin"); /* try it */
|
int status = luaL_loadbuffer(L, line, len, "=stdin"); /* try it */
|
||||||
if (!incomplete(L, status) || !pushline(L, 0)) {
|
if (!incomplete(L, status) || pushline(L, 0) != 1) {
|
||||||
return status; /* cannot or should not try to add continuation line */
|
return status; /* cannot or should not try to add continuation line */
|
||||||
}
|
}
|
||||||
lua_pushliteral(L, "\n"); /* add newline... */
|
lua_pushliteral(L, "\n"); /* add newline... */
|
||||||
|
@ -176,11 +206,38 @@ static int multiline (lua_State *L) {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void lua_initrepl(const char *progname) {
|
void lua_initrepl(lua_State *L, const char *progname) {
|
||||||
|
const char *prompt;
|
||||||
|
_spinlock(&lualock);
|
||||||
g_progname = progname;
|
g_progname = progname;
|
||||||
linenoiseSetCompletionCallback(lua_readline_completions);
|
if ((lua_repl_isterminal = linenoiseIsTerminal())) {
|
||||||
linenoiseSetHintsCallback(lua_readline_hint);
|
linenoiseSetCompletionCallback(lua_readline_completions);
|
||||||
linenoiseSetFreeHintsCallback(free);
|
linenoiseSetHintsCallback(lua_readline_hint);
|
||||||
|
linenoiseSetFreeHintsCallback(free);
|
||||||
|
prompt = get_prompt(L, 1);
|
||||||
|
if ((g_historypath = linenoiseGetHistoryPath(progname))) {
|
||||||
|
if (linenoiseHistoryLoad(g_historypath) == -1) {
|
||||||
|
kprintf("%r%s: failed to load history: %m%n", g_historypath);
|
||||||
|
free(g_historypath);
|
||||||
|
g_historypath = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
lua_repl_linenoise = linenoiseBegin(prompt, 0, 1);
|
||||||
|
lua_pop(L, 1); /* remove prompt */
|
||||||
|
__nomultics = 2;
|
||||||
|
__replmode = true;
|
||||||
|
}
|
||||||
|
_spunlock(&lualock);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void lua_freerepl(void) {
|
||||||
|
_spinlock(&lualock);
|
||||||
|
__nomultics = false;
|
||||||
|
__replmode = false;
|
||||||
|
linenoiseEnd(lua_repl_linenoise);
|
||||||
|
free(g_historypath);
|
||||||
|
_spunlock(&lualock);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -189,16 +246,24 @@ void lua_initrepl(const char *progname) {
|
||||||
** adding "return " in front of it) and second as a statement. Return
|
** adding "return " in front of it) and second as a statement. Return
|
||||||
** the final status of load/call with the resulting function (if any)
|
** the final status of load/call with the resulting function (if any)
|
||||||
** in the top of the stack.
|
** in the top of the stack.
|
||||||
|
**
|
||||||
|
** returns -1 on eof
|
||||||
|
** returns -2 on error
|
||||||
*/
|
*/
|
||||||
int lua_loadline (lua_State *L) {
|
int lua_loadline (lua_State *L) {
|
||||||
|
ssize_t rc;
|
||||||
int status;
|
int status;
|
||||||
lua_settop(L, 0);
|
lua_settop(L, 0);
|
||||||
if (!pushline(L, 1))
|
_spinlock(&lualock);
|
||||||
return -1; /* no input */
|
if ((rc = pushline(L, 1)) != 1) {
|
||||||
|
_spunlock(&lualock);
|
||||||
|
return rc - 1; /* eof or error */
|
||||||
|
}
|
||||||
if ((status = addreturn(L)) != LUA_OK) /* 'return ...' did not work? */
|
if ((status = addreturn(L)) != LUA_OK) /* 'return ...' did not work? */
|
||||||
status = multiline(L); /* try as command, maybe with continuation lines */
|
status = multiline(L); /* try as command, maybe with continuation lines */
|
||||||
lua_remove(L, 1); /* remove line from the stack */
|
lua_remove(L, 1); /* remove line from the stack */
|
||||||
lua_assert(lua_gettop(L) == 1);
|
lua_assert(lua_gettop(L) == 1);
|
||||||
|
_spunlock(&lualock);
|
||||||
return status;
|
return status;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
8
third_party/lua/lrepl.h
vendored
8
third_party/lua/lrepl.h
vendored
|
@ -5,9 +5,15 @@
|
||||||
#if !(__ASSEMBLER__ + __LINKER__ + 0)
|
#if !(__ASSEMBLER__ + __LINKER__ + 0)
|
||||||
COSMOPOLITAN_C_START_
|
COSMOPOLITAN_C_START_
|
||||||
|
|
||||||
|
extern char lualock;
|
||||||
|
extern bool lua_repl_blocking;
|
||||||
|
extern bool lua_repl_isterminal;
|
||||||
|
extern struct linenoiseState *lua_repl_linenoise;
|
||||||
|
|
||||||
|
void lua_freerepl(void);
|
||||||
int lua_loadline(lua_State *);
|
int lua_loadline(lua_State *);
|
||||||
void lua_l_print(lua_State *);
|
void lua_l_print(lua_State *);
|
||||||
void lua_initrepl(const char *);
|
void lua_initrepl(lua_State *, const char *);
|
||||||
int lua_report(lua_State *, int);
|
int lua_report(lua_State *, int);
|
||||||
int lua_runchunk(lua_State *, int, int);
|
int lua_runchunk(lua_State *, int, int);
|
||||||
void lua_l_message(const char *, const char *);
|
void lua_l_message(const char *, const char *);
|
||||||
|
|
31
third_party/lua/lua.main.c
vendored
31
third_party/lua/lua.main.c
vendored
|
@ -10,14 +10,19 @@
|
||||||
#include "libc/calls/sigbits.h"
|
#include "libc/calls/sigbits.h"
|
||||||
#include "libc/calls/struct/sigaction.h"
|
#include "libc/calls/struct/sigaction.h"
|
||||||
#include "libc/dce.h"
|
#include "libc/dce.h"
|
||||||
|
#include "libc/errno.h"
|
||||||
|
#include "libc/intrin/kprintf.h"
|
||||||
#include "libc/log/log.h"
|
#include "libc/log/log.h"
|
||||||
#include "libc/runtime/gc.h"
|
#include "libc/runtime/gc.h"
|
||||||
#include "libc/runtime/stack.h"
|
#include "libc/runtime/stack.h"
|
||||||
|
#include "libc/sock/sock.h"
|
||||||
#include "libc/str/str.h"
|
#include "libc/str/str.h"
|
||||||
#include "libc/sysv/consts/exit.h"
|
#include "libc/sysv/consts/exit.h"
|
||||||
|
#include "libc/sysv/consts/poll.h"
|
||||||
#include "libc/sysv/consts/sa.h"
|
#include "libc/sysv/consts/sa.h"
|
||||||
#include "libc/x/x.h"
|
#include "libc/x/x.h"
|
||||||
#include "third_party/linenoise/linenoise.h"
|
#include "third_party/linenoise/linenoise.h"
|
||||||
|
#include "third_party/lua/cosmo.h"
|
||||||
#include "third_party/lua/lauxlib.h"
|
#include "third_party/lua/lauxlib.h"
|
||||||
#include "third_party/lua/lprefix.h"
|
#include "third_party/lua/lprefix.h"
|
||||||
#include "third_party/lua/lrepl.h"
|
#include "third_party/lua/lrepl.h"
|
||||||
|
@ -275,8 +280,27 @@ static void doREPL (lua_State *L) {
|
||||||
int status;
|
int status;
|
||||||
const char *oldprogname = progname;
|
const char *oldprogname = progname;
|
||||||
progname = NULL; /* no 'progname' on errors in interactive mode */
|
progname = NULL; /* no 'progname' on errors in interactive mode */
|
||||||
lua_initrepl(LUA_PROGNAME);
|
lua_initrepl(L, LUA_PROGNAME);
|
||||||
while ((status = lua_loadline(L)) != -1) {
|
for (;;) {
|
||||||
|
linenoiseEnableRawMode(0);
|
||||||
|
TryAgain:
|
||||||
|
status = lua_loadline(L);
|
||||||
|
if (status == -2 && errno == EAGAIN) {
|
||||||
|
errno = 0;
|
||||||
|
poll(&(struct pollfd){0, POLLIN}, 1, -1);
|
||||||
|
goto TryAgain;
|
||||||
|
}
|
||||||
|
linenoiseDisableRawMode();
|
||||||
|
if (status == -1) {
|
||||||
|
break;
|
||||||
|
} else if (status == -2) {
|
||||||
|
lua_pushfstring(L, "read error: %s", strerror(errno));
|
||||||
|
lua_report(L, status);
|
||||||
|
lua_freerepl();
|
||||||
|
progname = oldprogname;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
lua_writeline();
|
||||||
if (status == LUA_OK)
|
if (status == LUA_OK)
|
||||||
status = lua_runchunk(L, 0, LUA_MULTRET);
|
status = lua_runchunk(L, 0, LUA_MULTRET);
|
||||||
if (status == LUA_OK) {
|
if (status == LUA_OK) {
|
||||||
|
@ -285,6 +309,7 @@ static void doREPL (lua_State *L) {
|
||||||
lua_report(L, status);
|
lua_report(L, status);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
lua_freerepl();
|
||||||
lua_settop(L, 0); /* clear stack */
|
lua_settop(L, 0); /* clear stack */
|
||||||
lua_writeline();
|
lua_writeline();
|
||||||
progname = oldprogname;
|
progname = oldprogname;
|
||||||
|
@ -343,7 +368,7 @@ static int pmain (lua_State *L) {
|
||||||
int main (int argc, char **argv) {
|
int main (int argc, char **argv) {
|
||||||
int status, result;
|
int status, result;
|
||||||
lua_State *L;
|
lua_State *L;
|
||||||
if (!IsModeDbg()) {
|
if (IsModeDbg()) {
|
||||||
ShowCrashReports();
|
ShowCrashReports();
|
||||||
}
|
}
|
||||||
/* if (IsModeDbg()) ShowCrashReports(); */
|
/* if (IsModeDbg()) ShowCrashReports(); */
|
||||||
|
|
|
@ -103,22 +103,21 @@ static void AppendArg(struct Args *l, char *s) {
|
||||||
static void MakeHeader(struct Header *h, const char *name, int ref, int mode,
|
static void MakeHeader(struct Header *h, const char *name, int ref, int mode,
|
||||||
int size) {
|
int size) {
|
||||||
size_t n;
|
size_t n;
|
||||||
char buf[24];
|
|
||||||
memset(h, ' ', sizeof(*h));
|
memset(h, ' ', sizeof(*h));
|
||||||
n = strlen(name);
|
n = strlen(name);
|
||||||
memcpy(h->name, name, n);
|
memcpy(h->name, name, n);
|
||||||
if (ref != -1) {
|
if (ref != -1) {
|
||||||
memcpy(h->name + n, buf, uint64toarray_radix10(ref, buf));
|
FormatUint32(h->name + n, ref);
|
||||||
}
|
}
|
||||||
if (strcmp(name, "//") != 0) {
|
if (strcmp(name, "//") != 0) {
|
||||||
h->date[0] = '0';
|
h->date[0] = '0';
|
||||||
h->uid[0] = '0';
|
h->uid[0] = '0';
|
||||||
h->gid[0] = '0';
|
h->gid[0] = '0';
|
||||||
memcpy(h->mode, buf, uint64toarray_radix8(mode & 0777, buf));
|
FormatOctal32(h->mode, mode & 0777, false);
|
||||||
}
|
}
|
||||||
h->fmag[0] = '`';
|
h->fmag[0] = '`';
|
||||||
h->fmag[1] = '\n';
|
h->fmag[1] = '\n';
|
||||||
memcpy(h->size, buf, uint64toarray_radix10(size, buf));
|
FormatUint32(h->size, size);
|
||||||
}
|
}
|
||||||
|
|
||||||
int main(int argc, char *argv[]) {
|
int main(int argc, char *argv[]) {
|
||||||
|
|
|
@ -1271,7 +1271,7 @@ static void DrawXmm(struct Panel *p, long i, long r) {
|
||||||
uint64toarray_fixed16(ival, buf, xmmtype.size[r] * 8);
|
uint64toarray_fixed16(ival, buf, xmmtype.size[r] * 8);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
int64toarray_radix10(SignExtend(ival, xmmtype.size[r] * 8), buf);
|
FormatInt64(buf, SignExtend(ival, xmmtype.size[r] * 8));
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
|
@ -2270,7 +2270,8 @@ static void OnVidyaServiceTeletypeOutput(void) {
|
||||||
char buf[12];
|
char buf[12];
|
||||||
n = 0 /* FormatCga(m->bx[0], buf) */;
|
n = 0 /* FormatCga(m->bx[0], buf) */;
|
||||||
w = tpenc(VidyaServiceXlatTeletype(m->ax[0]));
|
w = tpenc(VidyaServiceXlatTeletype(m->ax[0]));
|
||||||
do buf[n++] = w;
|
do
|
||||||
|
buf[n++] = w;
|
||||||
while ((w >>= 8));
|
while ((w >>= 8));
|
||||||
PtyWrite(pty, buf, n);
|
PtyWrite(pty, buf, n);
|
||||||
}
|
}
|
||||||
|
|
|
@ -30,9 +30,9 @@ size_t FormatCga(uint8_t bgfg, char buf[hasatleast 11]) {
|
||||||
char *p = buf;
|
char *p = buf;
|
||||||
*p++ = '\e';
|
*p++ = '\e';
|
||||||
*p++ = '[';
|
*p++ = '[';
|
||||||
p += uint64toarray_radix10(kCgaToAnsi[(bgfg & 0xF0) >> 4] + 10, p);
|
p = FormatUint32(p, kCgaToAnsi[(bgfg & 0xF0) >> 4] + 10);
|
||||||
*p++ = ';';
|
*p++ = ';';
|
||||||
p += uint64toarray_radix10(kCgaToAnsi[bgfg & 0x0F], p);
|
p = FormatUint32(p, kCgaToAnsi[bgfg & 0x0F]);
|
||||||
*p++ = 'm';
|
*p++ = 'm';
|
||||||
*p = '\0';
|
*p = '\0';
|
||||||
return p - buf;
|
return p - buf;
|
||||||
|
|
|
@ -128,7 +128,7 @@ static char *DisRegisterWord(struct Dis *d, uint32_t rde, char *p, bool g,
|
||||||
|
|
||||||
static char *DisInt(char *p, int64_t x) {
|
static char *DisInt(char *p, int64_t x) {
|
||||||
if (-15 <= x && x <= 15) {
|
if (-15 <= x && x <= 15) {
|
||||||
p += int64toarray_radix10(x, p);
|
p = FormatInt64(p, x);
|
||||||
} else if (x == INT64_MIN) {
|
} else if (x == INT64_MIN) {
|
||||||
p = stpcpy(p, "-0x");
|
p = stpcpy(p, "-0x");
|
||||||
p += uint64toarray_radix16(INT64_MIN, p);
|
p += uint64toarray_radix16(INT64_MIN, p);
|
||||||
|
@ -319,7 +319,8 @@ static char *DisRegMem(struct Dis *d, uint32_t rde, char *p,
|
||||||
}
|
}
|
||||||
|
|
||||||
static dontinline char *DisE(struct Dis *d, uint32_t rde, char *p,
|
static dontinline char *DisE(struct Dis *d, uint32_t rde, char *p,
|
||||||
char *f(struct Dis *, uint32_t, char *, bool, int)) {
|
char *f(struct Dis *, uint32_t, char *, bool,
|
||||||
|
int)) {
|
||||||
if (IsModrmRegister(rde)) {
|
if (IsModrmRegister(rde)) {
|
||||||
return f(d, rde, p, Rexb(rde), ModrmRm(rde));
|
return f(d, rde, p, Rexb(rde), ModrmRm(rde));
|
||||||
} else {
|
} else {
|
||||||
|
@ -471,13 +472,13 @@ static char *DisOne(struct Dis *d, uint32_t rde, char *p) {
|
||||||
|
|
||||||
static char *DisJbs(struct Dis *d, uint32_t rde, char *p) {
|
static char *DisJbs(struct Dis *d, uint32_t rde, char *p) {
|
||||||
if (d->xedd->op.disp > 0) *p++ = '+';
|
if (d->xedd->op.disp > 0) *p++ = '+';
|
||||||
p += int64toarray_radix10(d->xedd->op.disp, p);
|
p = FormatInt64(p, d->xedd->op.disp);
|
||||||
return p;
|
return p;
|
||||||
}
|
}
|
||||||
|
|
||||||
static char *DisJb(struct Dis *d, uint32_t rde, char *p) {
|
static char *DisJb(struct Dis *d, uint32_t rde, char *p) {
|
||||||
if (d->xedd->op.disp > 0) *p++ = '+';
|
if (d->xedd->op.disp > 0) *p++ = '+';
|
||||||
p += uint64toarray_radix10(d->xedd->op.disp & 0xff, p);
|
p = FormatUint32(p, d->xedd->op.disp & 0xff);
|
||||||
return p;
|
return p;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -522,7 +523,7 @@ static char *DisXmm(struct Dis *d, uint32_t rde, char *p, const char *s,
|
||||||
p = HighStart(p, g_high.reg);
|
p = HighStart(p, g_high.reg);
|
||||||
*p++ = '%';
|
*p++ = '%';
|
||||||
p = stpcpy(p, s);
|
p = stpcpy(p, s);
|
||||||
p += uint64toarray_radix10(reg, p);
|
p = FormatUint32(p, reg);
|
||||||
p = HighEnd(p);
|
p = HighEnd(p);
|
||||||
return p;
|
return p;
|
||||||
}
|
}
|
||||||
|
|
|
@ -25,7 +25,7 @@ struct High g_high;
|
||||||
char *HighStart(char *p, int h) {
|
char *HighStart(char *p, int h) {
|
||||||
if (h) {
|
if (h) {
|
||||||
p = stpcpy(p, "\e[38;5;");
|
p = stpcpy(p, "\e[38;5;");
|
||||||
p += uint64toarray_radix10(h, p);
|
p = FormatUint32(p, h);
|
||||||
p = stpcpy(p, "m");
|
p = stpcpy(p, "m");
|
||||||
g_high.active = true;
|
g_high.active = true;
|
||||||
}
|
}
|
||||||
|
|
|
@ -693,9 +693,9 @@ static void PtyReportCursorPosition(struct Pty *pty) {
|
||||||
p = buf;
|
p = buf;
|
||||||
*p++ = '\e';
|
*p++ = '\e';
|
||||||
*p++ = '[';
|
*p++ = '[';
|
||||||
p += uint64toarray_radix10((pty->y + 1) & 0x7fff, p);
|
p = FormatInt32(p, (pty->y + 1) & 0x7fff);
|
||||||
*p++ = ';';
|
*p++ = ';';
|
||||||
p += uint64toarray_radix10((pty->x + 1) & 0x7fff, p);
|
p = FormatInt32(p, (pty->x + 1) & 0x7fff);
|
||||||
*p++ = 'R';
|
*p++ = 'R';
|
||||||
PtyWriteInput(pty, buf, p - buf);
|
PtyWriteInput(pty, buf, p - buf);
|
||||||
}
|
}
|
||||||
|
@ -1178,7 +1178,8 @@ ssize_t PtyWriteInput(struct Pty *pty, const void *data, size_t n) {
|
||||||
m = pty->input.n;
|
m = pty->input.n;
|
||||||
if (i + n * 2 + 1 > m) {
|
if (i + n * 2 + 1 > m) {
|
||||||
m = MAX(m, 8);
|
m = MAX(m, 8);
|
||||||
do m += m >> 1;
|
do
|
||||||
|
m += m >> 1;
|
||||||
while (i + n * 2 + 1 > m);
|
while (i + n * 2 + 1 > m);
|
||||||
if (!(p = realloc(p, m))) {
|
if (!(p = realloc(p, m))) {
|
||||||
return -1;
|
return -1;
|
||||||
|
@ -1229,18 +1230,18 @@ ssize_t PtyRead(struct Pty *pty, void *buf, size_t size) {
|
||||||
static char *PtyEncodeRgb(char *p, int rgb) {
|
static char *PtyEncodeRgb(char *p, int rgb) {
|
||||||
*p++ = '2';
|
*p++ = '2';
|
||||||
*p++ = ';';
|
*p++ = ';';
|
||||||
p += uint64toarray_radix10((rgb & 0x0000ff) >> 000, p);
|
p = FormatUint32(p, (rgb & 0x0000ff) >> 000);
|
||||||
*p++ = ';';
|
*p++ = ';';
|
||||||
p += uint64toarray_radix10((rgb & 0x00ff00) >> 010, p);
|
p = FormatUint32(p, (rgb & 0x00ff00) >> 010);
|
||||||
*p++ = ';';
|
*p++ = ';';
|
||||||
p += uint64toarray_radix10((rgb & 0xff0000) >> 020, p);
|
p = FormatUint32(p, (rgb & 0xff0000) >> 020);
|
||||||
return p;
|
return p;
|
||||||
}
|
}
|
||||||
|
|
||||||
static char *PtyEncodeXterm256(char *p, int xt) {
|
static char *PtyEncodeXterm256(char *p, int xt) {
|
||||||
*p++ = '5';
|
*p++ = '5';
|
||||||
*p++ = ';';
|
*p++ = ';';
|
||||||
p += uint64toarray_radix10(xt, p);
|
p = FormatUint32(p, xt);
|
||||||
return p;
|
return p;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -661,7 +661,7 @@ static const char *GetErrnoName(int x) {
|
||||||
const char *s;
|
const char *s;
|
||||||
static char buf[16];
|
static char buf[16];
|
||||||
if ((s = strerror_short(x))) return s;
|
if ((s = strerror_short(x))) return s;
|
||||||
int64toarray_radix10(x, buf);
|
FormatInt64(buf, x);
|
||||||
return buf;
|
return buf;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -58,7 +58,7 @@ void PrintClosure(struct Closure *c, const char *name, int indent, FILE *f) {
|
||||||
fputs(": ", f);
|
fputs(": ", f);
|
||||||
Print(c->term, 0, GetDepth(c->envp), f);
|
Print(c->term, 0, GetDepth(c->envp), f);
|
||||||
fputs(" +", f);
|
fputs(" +", f);
|
||||||
int64toarray_radix10(c->refs, ibuf);
|
FormatInt64(ibuf, c->refs);
|
||||||
fputs(ibuf, f);
|
fputs(ibuf, f);
|
||||||
fputc('\n', f);
|
fputc('\n', f);
|
||||||
PrintClosure(c->envp, "envp", indent + 1, f);
|
PrintClosure(c->envp, "envp", indent + 1, f);
|
||||||
|
|
|
@ -632,7 +632,7 @@ void PrintVar(int i, FILE* f) {
|
||||||
char ibuf[22];
|
char ibuf[22];
|
||||||
switch (style) {
|
switch (style) {
|
||||||
case 0:
|
case 0:
|
||||||
int64toarray_radix10(i, ibuf);
|
FormatInt64(ibuf, i);
|
||||||
fputs(ibuf, f);
|
fputs(ibuf, f);
|
||||||
break;
|
break;
|
||||||
case 1:
|
case 1:
|
||||||
|
@ -642,7 +642,7 @@ void PrintVar(int i, FILE* f) {
|
||||||
fputwc(FREEBIES[~i], f);
|
fputwc(FREEBIES[~i], f);
|
||||||
} else {
|
} else {
|
||||||
ibuf[0] = '?';
|
ibuf[0] = '?';
|
||||||
int64toarray_radix10(i, ibuf + 1);
|
FormatInt64(ibuf + 1, i);
|
||||||
fputs(ibuf, f);
|
fputs(ibuf, f);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
@ -889,7 +889,7 @@ void PrintDebruijn(int x, int head, int depth, FILE* f) {
|
||||||
PrintVar(mem[x + 1], f);
|
PrintVar(mem[x + 1], f);
|
||||||
} else {
|
} else {
|
||||||
fputc(L'‼', f);
|
fputc(L'‼', f);
|
||||||
int64toarray_radix10(x, ibuf);
|
FormatInt64(ibuf, x);
|
||||||
fputs(ibuf, f);
|
fputs(ibuf, f);
|
||||||
}
|
}
|
||||||
} else if (mem[x] == IOP) {
|
} else if (mem[x] == IOP) {
|
||||||
|
@ -905,19 +905,19 @@ void PrintDebruijn(int x, int head, int depth, FILE* f) {
|
||||||
fputs(asciiname ? "gro" : "⋯", f);
|
fputs(asciiname ? "gro" : "⋯", f);
|
||||||
} else {
|
} else {
|
||||||
fputc(L'!', f);
|
fputc(L'!', f);
|
||||||
int64toarray_radix10(x, ibuf);
|
FormatInt64(ibuf, x);
|
||||||
fputs(ibuf, f);
|
fputs(ibuf, f);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
fputc(L'!', f);
|
fputc(L'!', f);
|
||||||
int64toarray_radix10(x, ibuf);
|
FormatInt64(ibuf, x);
|
||||||
fputs(ibuf, f);
|
fputs(ibuf, f);
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
Overflow:
|
Overflow:
|
||||||
fputc(L'‼', f);
|
fputc(L'‼', f);
|
||||||
int64toarray_radix10(x, ibuf);
|
FormatInt64(ibuf, x);
|
||||||
fputs(ibuf, f);
|
fputs(ibuf, f);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1172,7 +1172,7 @@ void PrintLambda(int x, int head, int depth, int apps, FILE* f) {
|
||||||
PrintVar(depth - 1 - mem[x + 1], f);
|
PrintVar(depth - 1 - mem[x + 1], f);
|
||||||
} else {
|
} else {
|
||||||
fputc(L'‼', f);
|
fputc(L'‼', f);
|
||||||
int64toarray_radix10(x, ibuf);
|
FormatInt64(ibuf, x);
|
||||||
fputs(ibuf, f);
|
fputs(ibuf, f);
|
||||||
}
|
}
|
||||||
} else if (mem[x] == APP) {
|
} else if (mem[x] == APP) {
|
||||||
|
@ -1198,12 +1198,12 @@ void PrintLambda(int x, int head, int depth, int apps, FILE* f) {
|
||||||
fputs(asciiname ? "gro" : "⋯", f);
|
fputs(asciiname ? "gro" : "⋯", f);
|
||||||
} else {
|
} else {
|
||||||
fputc(L'!', f);
|
fputc(L'!', f);
|
||||||
int64toarray_radix10(x, ibuf);
|
FormatInt64(ibuf, x);
|
||||||
fputs(ibuf, f);
|
fputs(ibuf, f);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
fputc(L'!', f);
|
fputc(L'!', f);
|
||||||
int64toarray_radix10(x, ibuf);
|
FormatInt64(ibuf, x);
|
||||||
fputs(ibuf, f);
|
fputs(ibuf, f);
|
||||||
}
|
}
|
||||||
if (close) {
|
if (close) {
|
||||||
|
@ -1213,7 +1213,7 @@ void PrintLambda(int x, int head, int depth, int apps, FILE* f) {
|
||||||
}
|
}
|
||||||
Overflow:
|
Overflow:
|
||||||
fputc(L'‼', f);
|
fputc(L'‼', f);
|
||||||
int64toarray_radix10(x, ibuf);
|
FormatInt64(ibuf, x);
|
||||||
fputs(ibuf, f);
|
fputs(ibuf, f);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1239,7 +1239,7 @@ void PrintBinary(int x, int head, int depth, FILE* f) {
|
||||||
PrintVar(mem[x + 1], f);
|
PrintVar(mem[x + 1], f);
|
||||||
} else {
|
} else {
|
||||||
fputc(L'‼', f);
|
fputc(L'‼', f);
|
||||||
int64toarray_radix10(x, ibuf);
|
FormatInt64(ibuf, x);
|
||||||
fputs(ibuf, f);
|
fputs(ibuf, f);
|
||||||
}
|
}
|
||||||
} else if (mem[x] == APP) {
|
} else if (mem[x] == APP) {
|
||||||
|
@ -1263,14 +1263,14 @@ void PrintBinary(int x, int head, int depth, FILE* f) {
|
||||||
fputwc(L'⋯', f);
|
fputwc(L'⋯', f);
|
||||||
} else {
|
} else {
|
||||||
fputc(L'!', f);
|
fputc(L'!', f);
|
||||||
int64toarray_radix10(x, ibuf);
|
FormatInt64(ibuf, x);
|
||||||
fputs(ibuf, f);
|
fputs(ibuf, f);
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
Overflow:
|
Overflow:
|
||||||
fputc(L'‼', f);
|
fputc(L'‼', f);
|
||||||
int64toarray_radix10(x, ibuf);
|
FormatInt64(ibuf, x);
|
||||||
fputs(ibuf, f);
|
fputs(ibuf, f);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -20,17 +20,17 @@ db:exec[[
|
||||||
INSERT INTO test (content) VALUES ('Hello Sqlite3');
|
INSERT INTO test (content) VALUES ('Hello Sqlite3');
|
||||||
]]
|
]]
|
||||||
|
|
||||||
-- this intercepts all requests if it's defined
|
-- -- this intercepts all requests if it's defined
|
||||||
function OnHttpRequest()
|
-- function OnHttpRequest()
|
||||||
if HasParam('magic') then
|
-- if HasParam('magic') then
|
||||||
Write('<p>\r\n')
|
-- Write('<p>\r\n')
|
||||||
Write('OnHttpRequest() has intercepted your request<br>\r\n')
|
-- Write('OnHttpRequest() has intercepted your request<br>\r\n')
|
||||||
Write('because you specified the magic parameter\r\n')
|
-- Write('because you specified the magic parameter\r\n')
|
||||||
Write('<pre>\r\n')
|
-- Write('<pre>\r\n')
|
||||||
Write(EscapeHtml(LoadAsset('/.init.lua')))
|
-- Write(EscapeHtml(LoadAsset('/.init.lua')))
|
||||||
Write('</pre>\r\n')
|
-- Write('</pre>\r\n')
|
||||||
else
|
-- else
|
||||||
Route() -- this asks redbean to do the default thing
|
-- Route() -- this asks redbean to do the default thing
|
||||||
end
|
-- end
|
||||||
SetHeader('Server', 'redbean!')
|
-- SetHeader('Server', 'redbean!')
|
||||||
end
|
-- end
|
||||||
|
|
|
@ -90,7 +90,7 @@ o/$(MODE)/tool/net/%.com.dbg: \
|
||||||
|
|
||||||
o/$(MODE)/tool/net/redbean.com.dbg: \
|
o/$(MODE)/tool/net/redbean.com.dbg: \
|
||||||
$(TOOL_NET_DEPS) \
|
$(TOOL_NET_DEPS) \
|
||||||
o/$(MODE)/tool/net/redbean.o \
|
o/$(MODE)/tool/net/redbean.o \
|
||||||
o/$(MODE)/tool/net/lre.o \
|
o/$(MODE)/tool/net/lre.o \
|
||||||
o/$(MODE)/tool/net/lunix.o \
|
o/$(MODE)/tool/net/lunix.o \
|
||||||
o/$(MODE)/tool/net/lmaxmind.o \
|
o/$(MODE)/tool/net/lmaxmind.o \
|
||||||
|
@ -208,7 +208,7 @@ o/$(MODE)/tool/net/demo/virtualbean.html.zip.o: \
|
||||||
|
|
||||||
o/$(MODE)/tool/net/redbean-demo.com.dbg: \
|
o/$(MODE)/tool/net/redbean-demo.com.dbg: \
|
||||||
$(TOOL_NET_DEPS) \
|
$(TOOL_NET_DEPS) \
|
||||||
o/$(MODE)/tool/net/redbean.o \
|
o/$(MODE)/tool/net/redbean.o \
|
||||||
o/$(MODE)/tool/net/lre.o \
|
o/$(MODE)/tool/net/lre.o \
|
||||||
o/$(MODE)/tool/net/lunix.o \
|
o/$(MODE)/tool/net/lunix.o \
|
||||||
o/$(MODE)/tool/net/lmaxmind.o \
|
o/$(MODE)/tool/net/lmaxmind.o \
|
||||||
|
|
|
@ -39,6 +39,7 @@
|
||||||
#include "libc/fmt/conv.h"
|
#include "libc/fmt/conv.h"
|
||||||
#include "libc/fmt/itoa.h"
|
#include "libc/fmt/itoa.h"
|
||||||
#include "libc/intrin/nomultics.internal.h"
|
#include "libc/intrin/nomultics.internal.h"
|
||||||
|
#include "libc/intrin/spinlock.h"
|
||||||
#include "libc/log/backtrace.internal.h"
|
#include "libc/log/backtrace.internal.h"
|
||||||
#include "libc/log/check.h"
|
#include "libc/log/check.h"
|
||||||
#include "libc/log/log.h"
|
#include "libc/log/log.h"
|
||||||
|
@ -50,10 +51,12 @@
|
||||||
#include "libc/nexgen32e/bsf.h"
|
#include "libc/nexgen32e/bsf.h"
|
||||||
#include "libc/nexgen32e/bsr.h"
|
#include "libc/nexgen32e/bsr.h"
|
||||||
#include "libc/nexgen32e/crc32.h"
|
#include "libc/nexgen32e/crc32.h"
|
||||||
|
#include "libc/nexgen32e/nt2sysv.h"
|
||||||
#include "libc/nexgen32e/rdtsc.h"
|
#include "libc/nexgen32e/rdtsc.h"
|
||||||
#include "libc/nexgen32e/rdtscp.h"
|
#include "libc/nexgen32e/rdtscp.h"
|
||||||
#include "libc/nt/enum/fileflagandattributes.h"
|
#include "libc/nt/enum/fileflagandattributes.h"
|
||||||
#include "libc/nt/runtime.h"
|
#include "libc/nt/runtime.h"
|
||||||
|
#include "libc/nt/thread.h"
|
||||||
#include "libc/rand/rand.h"
|
#include "libc/rand/rand.h"
|
||||||
#include "libc/runtime/clktck.h"
|
#include "libc/runtime/clktck.h"
|
||||||
#include "libc/runtime/directmap.internal.h"
|
#include "libc/runtime/directmap.internal.h"
|
||||||
|
@ -362,6 +365,7 @@ static bool printport;
|
||||||
static bool daemonize;
|
static bool daemonize;
|
||||||
static bool logrusage;
|
static bool logrusage;
|
||||||
static bool logbodies;
|
static bool logbodies;
|
||||||
|
static bool isterminal;
|
||||||
static bool sslcliused;
|
static bool sslcliused;
|
||||||
static bool loglatency;
|
static bool loglatency;
|
||||||
static bool terminated;
|
static bool terminated;
|
||||||
|
@ -835,12 +839,13 @@ static void DescribeAddress(char buf[40], uint32_t addr, uint16_t port) {
|
||||||
char *p;
|
char *p;
|
||||||
const char *s;
|
const char *s;
|
||||||
p = buf;
|
p = buf;
|
||||||
p += uint64toarray_radix10((addr & 0xFF000000) >> 030, p), *p++ = '.';
|
p = FormatUint64(p, (addr & 0xFF000000) >> 030), *p++ = '.';
|
||||||
p += uint64toarray_radix10((addr & 0x00FF0000) >> 020, p), *p++ = '.';
|
p = FormatUint64(p, (addr & 0x00FF0000) >> 020), *p++ = '.';
|
||||||
p += uint64toarray_radix10((addr & 0x0000FF00) >> 010, p), *p++ = '.';
|
p = FormatUint64(p, (addr & 0x0000FF00) >> 010), *p++ = '.';
|
||||||
p += uint64toarray_radix10((addr & 0x000000FF) >> 000, p), *p++ = ':';
|
p = FormatUint64(p, (addr & 0x000000FF) >> 000), *p++ = ':';
|
||||||
p += uint64toarray_radix10(port, p);
|
p = FormatUint64(p, port);
|
||||||
*p++ = '\0';
|
*p = '\0';
|
||||||
|
assert(p - buf < 40);
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline void GetServerAddr(uint32_t *ip, uint16_t *port) {
|
static inline void GetServerAddr(uint32_t *ip, uint16_t *port) {
|
||||||
|
@ -1029,7 +1034,7 @@ static void Daemonize(void) {
|
||||||
umask(0);
|
umask(0);
|
||||||
if (pidpath) {
|
if (pidpath) {
|
||||||
fd = open(pidpath, O_CREAT | O_WRONLY, 0644);
|
fd = open(pidpath, O_CREAT | O_WRONLY, 0644);
|
||||||
WRITE(fd, ibuf, uint64toarray_radix10(getpid(), ibuf));
|
WRITE(fd, ibuf, FormatInt32(ibuf, getpid()) - ibuf);
|
||||||
close(fd);
|
close(fd);
|
||||||
}
|
}
|
||||||
if (!logpath) ProgramLogPath("/dev/null");
|
if (!logpath) ProgramLogPath("/dev/null");
|
||||||
|
@ -1486,6 +1491,7 @@ static void CertsDestroy(void) {
|
||||||
|
|
||||||
static void WipeServingKeys(void) {
|
static void WipeServingKeys(void) {
|
||||||
size_t i;
|
size_t i;
|
||||||
|
long double t = nowl();
|
||||||
if (uniprocess) return;
|
if (uniprocess) return;
|
||||||
mbedtls_ssl_ticket_free(&ssltick);
|
mbedtls_ssl_ticket_free(&ssltick);
|
||||||
mbedtls_ssl_key_cert_free(conf.key_cert), conf.key_cert = 0;
|
mbedtls_ssl_key_cert_free(conf.key_cert), conf.key_cert = 0;
|
||||||
|
@ -2083,7 +2089,7 @@ static char *AppendExpires(char *p, int64_t t) {
|
||||||
static char *AppendCache(char *p, int64_t seconds) {
|
static char *AppendCache(char *p, int64_t seconds) {
|
||||||
if (seconds < 0) return p;
|
if (seconds < 0) return p;
|
||||||
p = stpcpy(p, "Cache-Control: max-age=");
|
p = stpcpy(p, "Cache-Control: max-age=");
|
||||||
p += uint64toarray_radix10(seconds, p);
|
p = FormatUint64(p, seconds);
|
||||||
if (seconds) {
|
if (seconds) {
|
||||||
p = stpcpy(p, ", public");
|
p = stpcpy(p, ", public");
|
||||||
} else {
|
} else {
|
||||||
|
@ -2095,21 +2101,21 @@ static char *AppendCache(char *p, int64_t seconds) {
|
||||||
|
|
||||||
static inline char *AppendContentLength(char *p, size_t n) {
|
static inline char *AppendContentLength(char *p, size_t n) {
|
||||||
p = stpcpy(p, "Content-Length: ");
|
p = stpcpy(p, "Content-Length: ");
|
||||||
p += uint64toarray_radix10(n, p);
|
p = FormatUint64(p, n);
|
||||||
return AppendCrlf(p);
|
return AppendCrlf(p);
|
||||||
}
|
}
|
||||||
|
|
||||||
static char *AppendContentRange(char *p, long a, long b, long c) {
|
static char *AppendContentRange(char *p, long a, long b, long c) {
|
||||||
p = stpcpy(p, "Content-Range: bytes ");
|
p = stpcpy(p, "Content-Range: bytes ");
|
||||||
if (a >= 0 && b > 0) {
|
if (a >= 0 && b > 0) {
|
||||||
p += uint64toarray_radix10(a, p);
|
p = FormatUint64(p, a);
|
||||||
*p++ = '-';
|
*p++ = '-';
|
||||||
p += uint64toarray_radix10(a + b - 1, p);
|
p = FormatUint64(p, a + b - 1);
|
||||||
} else {
|
} else {
|
||||||
*p++ = '*';
|
*p++ = '*';
|
||||||
}
|
}
|
||||||
*p++ = '/';
|
*p++ = '/';
|
||||||
p += uint64toarray_radix10(c, p);
|
p = FormatUint64(p, c);
|
||||||
return AppendCrlf(p);
|
return AppendCrlf(p);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -6396,6 +6402,7 @@ static bool StreamResponse(char *p) {
|
||||||
static bool HandleMessageActual(void) {
|
static bool HandleMessageActual(void) {
|
||||||
int rc;
|
int rc;
|
||||||
char *p;
|
char *p;
|
||||||
|
long double now;
|
||||||
if ((rc = ParseHttpMessage(&msg, inbuf.p, amtread)) != -1) {
|
if ((rc = ParseHttpMessage(&msg, inbuf.p, amtread)) != -1) {
|
||||||
if (!rc) return false;
|
if (!rc) return false;
|
||||||
hdrsize = rc;
|
hdrsize = rc;
|
||||||
|
@ -6437,8 +6444,11 @@ static bool HandleMessageActual(void) {
|
||||||
LockInc(&shared->c.messageshandled);
|
LockInc(&shared->c.messageshandled);
|
||||||
++messageshandled;
|
++messageshandled;
|
||||||
if (loglatency || LOGGABLE(kLogDebug)) {
|
if (loglatency || LOGGABLE(kLogDebug)) {
|
||||||
LOGF(kLogDebug, "(stat) %`'.*s latency %,ldµs", msg.uri.b - msg.uri.a,
|
now = nowl();
|
||||||
inbuf.p + msg.uri.a, (long)((nowl() - startrequest) * 1e6L));
|
LOGF(kLogDebug, "(stat) %`'.*s latency r: %,ldµs c: %,ldµs",
|
||||||
|
msg.uri.b - msg.uri.a, inbuf.p + msg.uri.a,
|
||||||
|
(long)((now - startrequest) * 1e6L),
|
||||||
|
(long)((now - startconnection) * 1e6L));
|
||||||
}
|
}
|
||||||
if (!generator) {
|
if (!generator) {
|
||||||
return TransmitResponse(p);
|
return TransmitResponse(p);
|
||||||
|
@ -6702,7 +6712,6 @@ static int EnableSandbox(void) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// returns 0 otherwise -1 if worker needs to unwind stack and exit
|
|
||||||
static int HandleConnection(size_t i) {
|
static int HandleConnection(size_t i) {
|
||||||
int pid, rc = 0;
|
int pid, rc = 0;
|
||||||
clientaddrsize = sizeof(clientaddr);
|
clientaddrsize = sizeof(clientaddr);
|
||||||
|
@ -6731,10 +6740,16 @@ static int HandleConnection(size_t i) {
|
||||||
__kbirth = rdtsc();
|
__kbirth = rdtsc();
|
||||||
}
|
}
|
||||||
if (funtrace) {
|
if (funtrace) {
|
||||||
ftrace_install();
|
if (ftrace_install() != -1) {
|
||||||
|
g_ftrace = 1;
|
||||||
|
} else {
|
||||||
|
WARNF("ftrace failed to install %m");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
CHECK_NE(-1, EnableSandbox());
|
if (sandboxed) {
|
||||||
|
CHECK_NE(-1, EnableSandbox());
|
||||||
|
}
|
||||||
if (hasonworkerstart) {
|
if (hasonworkerstart) {
|
||||||
CallSimpleHook("OnWorkerStart");
|
CallSimpleHook("OnWorkerStart");
|
||||||
}
|
}
|
||||||
|
@ -6824,45 +6839,6 @@ static int HandleConnection(size_t i) {
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
// returns 2 if we should stay in the redbean event loop
|
|
||||||
// returns 1 if poll() says stdin has user input available
|
|
||||||
// returns 0 if poll() timed out after ms
|
|
||||||
// returns -1 if worker is unwinding exit
|
|
||||||
static int HandlePoll(int ms) {
|
|
||||||
size_t i;
|
|
||||||
int nfds;
|
|
||||||
if ((nfds = poll(polls, 1 + servers.n, ms)) != -1) {
|
|
||||||
for (i = 0; i < servers.n; ++i) {
|
|
||||||
if (polls[1 + i].revents) {
|
|
||||||
serveraddr = &servers.p[i].addr;
|
|
||||||
ishandlingconnection = true;
|
|
||||||
if (HandleConnection(i) == -1) return -1;
|
|
||||||
ishandlingconnection = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// are we polling stdin for the repl?
|
|
||||||
if (polls[0].fd >= 0) {
|
|
||||||
if (polls[0].revents) {
|
|
||||||
return 1; // user entered a keystroke
|
|
||||||
} else if (!nfds) {
|
|
||||||
return 0; // let linenoise know it timed out
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if (errno == EINTR || errno == EAGAIN) {
|
|
||||||
LockInc(&shared->c.pollinterrupts);
|
|
||||||
} else if (errno == ENOMEM) {
|
|
||||||
LockInc(&shared->c.enomems);
|
|
||||||
WARNF("(srvr) %s ran out of memory");
|
|
||||||
meltdown = true;
|
|
||||||
} else {
|
|
||||||
DIEF("(srvr) poll error: %m");
|
|
||||||
}
|
|
||||||
errno = 0;
|
|
||||||
}
|
|
||||||
return 2;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void RestoreApe(void) {
|
static void RestoreApe(void) {
|
||||||
char *p;
|
char *p;
|
||||||
size_t n;
|
size_t n;
|
||||||
|
@ -6883,6 +6859,97 @@ static void RestoreApe(void) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int HandleReadline(void) {
|
||||||
|
int status;
|
||||||
|
for (;;) {
|
||||||
|
status = lua_loadline(GL);
|
||||||
|
if (status < 0) {
|
||||||
|
if (status == -1) {
|
||||||
|
OnTerm(SIGHUP); // eof
|
||||||
|
INFOF("got repl eof");
|
||||||
|
write(1, "\r\n", 2);
|
||||||
|
return -1;
|
||||||
|
} else if (errno == EINTR) {
|
||||||
|
errno = 0;
|
||||||
|
OnInt(SIGINT);
|
||||||
|
INFOF("got repl interrupt");
|
||||||
|
return 0;
|
||||||
|
} else if (errno == EAGAIN) {
|
||||||
|
errno = 0;
|
||||||
|
return 0;
|
||||||
|
} else {
|
||||||
|
OnTerm(SIGIO); // error
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
write(1, "\r\n", 2);
|
||||||
|
linenoiseDisableRawMode();
|
||||||
|
_spinlock(&lualock);
|
||||||
|
if (status == LUA_OK) {
|
||||||
|
status = lua_runchunk(GL, 0, LUA_MULTRET);
|
||||||
|
}
|
||||||
|
if (status == LUA_OK) {
|
||||||
|
lua_l_print(GL);
|
||||||
|
} else {
|
||||||
|
lua_report(GL, status);
|
||||||
|
}
|
||||||
|
_spunlock(&lualock);
|
||||||
|
if (lua_repl_isterminal) {
|
||||||
|
linenoiseEnableRawMode(0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static int HandlePoll(int ms) {
|
||||||
|
int rc, nfds;
|
||||||
|
size_t pollid, serverid;
|
||||||
|
if ((nfds = poll(polls, 1 + servers.n, ms)) != -1) {
|
||||||
|
if (nfds) {
|
||||||
|
// handle pollid/o events
|
||||||
|
for (pollid = 0; pollid < 1 + servers.n; ++pollid) {
|
||||||
|
if (!polls[pollid].revents) continue;
|
||||||
|
if (polls[pollid].fd < 0) continue;
|
||||||
|
if (polls[pollid].fd) {
|
||||||
|
// handle listen socket
|
||||||
|
serverid = pollid - 1;
|
||||||
|
assert(0 <= serverid && serverid < servers.n);
|
||||||
|
serveraddr = &servers.p[serverid].addr;
|
||||||
|
ishandlingconnection = true;
|
||||||
|
_spinlock(&lualock);
|
||||||
|
rc = HandleConnection(serverid);
|
||||||
|
_spunlock(&lualock);
|
||||||
|
ishandlingconnection = false;
|
||||||
|
if (rc == -1) return -1;
|
||||||
|
} else {
|
||||||
|
// handle standard input
|
||||||
|
rc = HandleReadline();
|
||||||
|
if (rc == -1) return rc;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else if (__replmode) {
|
||||||
|
// handle refresh repl line
|
||||||
|
if (!IsWindows()) {
|
||||||
|
rc = HandleReadline();
|
||||||
|
if (rc < 0) return rc;
|
||||||
|
} else {
|
||||||
|
linenoiseRefreshLine(lua_repl_linenoise);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (errno == EINTR || errno == EAGAIN) {
|
||||||
|
LockInc(&shared->c.pollinterrupts);
|
||||||
|
} else if (errno == ENOMEM) {
|
||||||
|
LockInc(&shared->c.enomems);
|
||||||
|
WARNF("(srvr) %s ran out of memory");
|
||||||
|
meltdown = true;
|
||||||
|
} else {
|
||||||
|
DIEF("(srvr) poll error: %m");
|
||||||
|
}
|
||||||
|
errno = 0;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
static void Listen(void) {
|
static void Listen(void) {
|
||||||
char ipbuf[16];
|
char ipbuf[16];
|
||||||
size_t i, j, n;
|
size_t i, j, n;
|
||||||
|
@ -6960,10 +7027,9 @@ static void HandleShutdown(void) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// this function coroutines with linenoise
|
// this function coroutines with linenoise
|
||||||
static int EventLoop(int fd, int ms) {
|
static int EventLoop(int ms) {
|
||||||
int rc;
|
|
||||||
long double t;
|
long double t;
|
||||||
rc = -1;
|
VERBOSEF("EventLoop()");
|
||||||
while (!terminated) {
|
while (!terminated) {
|
||||||
errno = 0;
|
errno = 0;
|
||||||
if (zombied) {
|
if (zombied) {
|
||||||
|
@ -6977,54 +7043,47 @@ static int EventLoop(int fd, int ms) {
|
||||||
} else if ((t = nowl()) - lastheartbeat > HEARTBEAT / 1000.) {
|
} else if ((t = nowl()) - lastheartbeat > HEARTBEAT / 1000.) {
|
||||||
lastheartbeat = t;
|
lastheartbeat = t;
|
||||||
HandleHeartbeat();
|
HandleHeartbeat();
|
||||||
} else if ((rc = HandlePoll(ms)) != 2) {
|
} else if (HandlePoll(ms) == -1) {
|
||||||
break; // return control to linenoise
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return rc;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void ReplEventLoop(void) {
|
static void ReplEventLoop(void) {
|
||||||
int status;
|
DEBUGF("ReplEventLoop()");
|
||||||
long double t;
|
|
||||||
lua_State *L = GL;
|
|
||||||
polls[0].fd = 0;
|
polls[0].fd = 0;
|
||||||
__nomultics = 2;
|
lua_initrepl(GL, "redbean");
|
||||||
__replmode = true;
|
if (lua_repl_isterminal) {
|
||||||
lua_initrepl("redbean");
|
linenoiseEnableRawMode(0);
|
||||||
linenoiseSetPollCallback(EventLoop);
|
|
||||||
for (;;) {
|
|
||||||
if ((status = lua_loadline(L)) == -1) {
|
|
||||||
if (errno == EINTR) {
|
|
||||||
LockInc(&shared->c.pollinterrupts);
|
|
||||||
if (terminated) {
|
|
||||||
break;
|
|
||||||
} else {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (status == LUA_OK) {
|
|
||||||
status = lua_runchunk(L, 0, LUA_MULTRET);
|
|
||||||
}
|
|
||||||
if (status == LUA_OK) {
|
|
||||||
lua_l_print(L);
|
|
||||||
} else {
|
|
||||||
lua_report(L, status);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
if (!terminated && !isexitingworker) {
|
EventLoop(100);
|
||||||
OnTerm(SIGHUP); // eof event
|
linenoiseDisableRawMode();
|
||||||
}
|
lua_freerepl();
|
||||||
lua_settop(L, 0); // clear stack
|
lua_settop(GL, 0); // clear stack
|
||||||
lua_writeline();
|
|
||||||
__replmode = false;
|
|
||||||
__nomultics = 0;
|
|
||||||
polls[0].fd = -1;
|
polls[0].fd = -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static uint32_t WindowsReplThread(void *arg) {
|
||||||
|
DEBUGF("WindowsReplThread()");
|
||||||
|
lua_repl_blocking = true;
|
||||||
|
lua_initrepl(GL, "redbean");
|
||||||
|
if (lua_repl_isterminal) {
|
||||||
|
linenoiseEnableRawMode(0);
|
||||||
|
}
|
||||||
|
for (;;) {
|
||||||
|
if (HandleReadline() == -1) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
linenoiseDisableRawMode();
|
||||||
|
lua_freerepl();
|
||||||
|
_spinlock(&lualock);
|
||||||
|
lua_settop(GL, 0); // clear stack
|
||||||
|
_spunlock(&lualock);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
static void SigInit(void) {
|
static void SigInit(void) {
|
||||||
xsigaction(SIGINT, OnInt, 0, 0, 0);
|
xsigaction(SIGINT, OnInt, 0, 0, 0);
|
||||||
xsigaction(SIGHUP, OnHup, 0, 0, 0);
|
xsigaction(SIGHUP, OnHup, 0, 0, 0);
|
||||||
|
@ -7217,13 +7276,6 @@ void RedBean(int argc, char *argv[]) {
|
||||||
if (daemonize) {
|
if (daemonize) {
|
||||||
Daemonize();
|
Daemonize();
|
||||||
} else {
|
} else {
|
||||||
// xxx: create process group to make it easier to propagate SIGTERM
|
|
||||||
// to children. the downside to doing this seems to be that
|
|
||||||
// ctrl-c isn't propagating as expected when running redbean
|
|
||||||
// underneath strace.com :|
|
|
||||||
if (!IsWindows()) {
|
|
||||||
setpgrp();
|
|
||||||
}
|
|
||||||
if (logpath) {
|
if (logpath) {
|
||||||
close(2);
|
close(2);
|
||||||
open(logpath, O_APPEND | O_WRONLY | O_CREAT, 0640);
|
open(logpath, O_APPEND | O_WRONLY | O_CREAT, 0640);
|
||||||
|
@ -7240,14 +7292,18 @@ void RedBean(int argc, char *argv[]) {
|
||||||
isinitialized = true;
|
isinitialized = true;
|
||||||
CallSimpleHookIfDefined("OnServerStart");
|
CallSimpleHookIfDefined("OnServerStart");
|
||||||
#ifdef STATIC
|
#ifdef STATIC
|
||||||
EventLoop(-1, HEARTBEAT);
|
EventLoop(HEARTBEAT);
|
||||||
#else
|
#else
|
||||||
GetResolvConf(); // for effect
|
|
||||||
GetHostsTxt(); // for effect
|
GetHostsTxt(); // for effect
|
||||||
if (!IsWindows() && isatty(0)) {
|
GetResolvConf(); // for effect
|
||||||
ReplEventLoop();
|
if (daemonize || !linenoiseIsTerminal()) {
|
||||||
|
EventLoop(HEARTBEAT);
|
||||||
|
} else if (IsWindows()) {
|
||||||
|
uint32_t tid;
|
||||||
|
CreateThread(0, 0, NT2SYSV(WindowsReplThread), 0, 0, &tid);
|
||||||
|
EventLoop(100);
|
||||||
} else {
|
} else {
|
||||||
EventLoop(-1, HEARTBEAT);
|
ReplEventLoop();
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
if (!isexitingworker) {
|
if (!isexitingworker) {
|
||||||
|
|
|
@ -83,7 +83,7 @@ void bf(int fd) {
|
||||||
obuf[n++] = ';';
|
obuf[n++] = ';';
|
||||||
obuf[n++] = '5';
|
obuf[n++] = '5';
|
||||||
obuf[n++] = ';';
|
obuf[n++] = ';';
|
||||||
n += int64toarray_radix10(fg, obuf + n);
|
n = FormatInt64(obuf + n, fg) - (obuf + n);
|
||||||
obuf[n++] = 'm';
|
obuf[n++] = 'm';
|
||||||
}
|
}
|
||||||
obuf[n++] = "0123456789abcdef"[c >> 4];
|
obuf[n++] = "0123456789abcdef"[c >> 4];
|
||||||
|
|
|
@ -79,7 +79,7 @@ static const char *GetStorageSpecifier(const char *type, int *out_width,
|
||||||
static void EmitSection(long yn, long xn, int w, int arrayalign, int emit(),
|
static void EmitSection(long yn, long xn, int w, int arrayalign, int emit(),
|
||||||
void *a) {
|
void *a) {
|
||||||
char alignstr[21];
|
char alignstr[21];
|
||||||
uint64toarray_radix10(arrayalign, alignstr);
|
FormatUint32(alignstr, arrayalign);
|
||||||
if (arrayalign <= 8 && yn * xn * w == 8) {
|
if (arrayalign <= 8 && yn * xn * w == 8) {
|
||||||
emit("\t.rodata.cst", a);
|
emit("\t.rodata.cst", a);
|
||||||
emit("8\n", a);
|
emit("8\n", a);
|
||||||
|
@ -108,8 +108,8 @@ void *FormatStringTableAsAssembly(long yn, long xn, const char *const T[yn][xn],
|
||||||
char ynstr[21], xnstr[21];
|
char ynstr[21], xnstr[21];
|
||||||
name = firstnonnull(name, "M");
|
name = firstnonnull(name, "M");
|
||||||
storage = GetStorageSpecifier(firstnonnull(type, "long"), &w, &align);
|
storage = GetStorageSpecifier(firstnonnull(type, "long"), &w, &align);
|
||||||
uint64toarray_radix10(yn, ynstr);
|
FormatUint64(ynstr, yn);
|
||||||
uint64toarray_radix10(xn, xnstr);
|
FormatUint64(xnstr, xn);
|
||||||
EmitSection(yn, xn, w, GetArrayAlignment(yn, xn, w, align), emit, a);
|
EmitSection(yn, xn, w, GetArrayAlignment(yn, xn, w, align), emit, a);
|
||||||
emit(name, a);
|
emit(name, a);
|
||||||
emit(":", a);
|
emit(":", a);
|
||||||
|
|
|
@ -24,8 +24,8 @@ void *FormatStringTableAsCode(long yn, long xn, const char *const T[yn][xn],
|
||||||
int emit(), void *arg, const char *type,
|
int emit(), void *arg, const char *type,
|
||||||
const char *name, const char *ignored) {
|
const char *name, const char *ignored) {
|
||||||
char ynstr[21], xnstr[21];
|
char ynstr[21], xnstr[21];
|
||||||
uint64toarray_radix10(yn, ynstr);
|
FormatUint64(ynstr, yn);
|
||||||
uint64toarray_radix10(xn, xnstr);
|
FormatUint64(xnstr, xn);
|
||||||
emit(type, arg);
|
emit(type, arg);
|
||||||
emit(" ", arg);
|
emit(" ", arg);
|
||||||
emit(firstnonnull(name, "M"), arg);
|
emit(firstnonnull(name, "M"), arg);
|
||||||
|
|
|
@ -341,7 +341,7 @@ static void AppendChar(char c) {
|
||||||
|
|
||||||
static void AppendInt(long x) {
|
static void AppendInt(long x) {
|
||||||
char ibuf[21];
|
char ibuf[21];
|
||||||
AppendData(ibuf, int64toarray_radix10(x, ibuf));
|
AppendData(ibuf, FormatInt64(ibuf, x) - ibuf);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*───────────────────────────────────────────────────────────────────────────│─╗
|
/*───────────────────────────────────────────────────────────────────────────│─╗
|
||||||
|
|
|
@ -743,7 +743,7 @@ static void Render(void) {
|
||||||
fg = InvertXtermGreyscale(fg);
|
fg = InvertXtermGreyscale(fg);
|
||||||
}
|
}
|
||||||
p = stpcpy(p, "\e[38;5;");
|
p = stpcpy(p, "\e[38;5;");
|
||||||
p += int64toarray_radix10(fg, p);
|
p = FormatInt64(p, fg);
|
||||||
*p++ = 'm';
|
*p++ = 'm';
|
||||||
}
|
}
|
||||||
w = tpenc(kCp437[c]);
|
w = tpenc(kCp437[c]);
|
||||||
|
@ -769,14 +769,14 @@ static void Render(void) {
|
||||||
}
|
}
|
||||||
p = stpcpy(p, " memzoom\e[0m ");
|
p = stpcpy(p, " memzoom\e[0m ");
|
||||||
if (!pid) {
|
if (!pid) {
|
||||||
p += uint64toarray_radix10(MIN(offset / (long double)size * 100, 100), p);
|
p = FormatUint32(p, MIN(offset / (long double)size * 100, 100));
|
||||||
p = stpcpy(p, "%-");
|
p = stpcpy(p, "%-");
|
||||||
p += uint64toarray_radix10(
|
p = FormatUint32(
|
||||||
MIN((offset + ((tyn * txn) << zoom)) / (long double)size * 100, 100),
|
p,
|
||||||
p);
|
MIN((offset + ((tyn * txn) << zoom)) / (long double)size * 100, 100));
|
||||||
p = stpcpy(p, "% ");
|
p = stpcpy(p, "% ");
|
||||||
}
|
}
|
||||||
p += uint64toarray_radix10(1L << zoom, p);
|
p = FormatUint32(p, 1L << zoom);
|
||||||
p = stpcpy(p, "x\e[J");
|
p = stpcpy(p, "x\e[J");
|
||||||
PreventBufferbloat();
|
PreventBufferbloat();
|
||||||
for (i = 0, n = p - buffer; i < n; i += got) {
|
for (i = 0, n = p - buffer; i < n; i += got) {
|
||||||
|
@ -910,10 +910,10 @@ static void GetOpts(int argc, char *argv[]) {
|
||||||
}
|
}
|
||||||
if (pid) {
|
if (pid) {
|
||||||
p = stpcpy(path, "/proc/");
|
p = stpcpy(path, "/proc/");
|
||||||
p += int64toarray_radix10(pid, p);
|
p = FormatInt64(p, pid);
|
||||||
stpcpy(p, "/mem");
|
stpcpy(p, "/mem");
|
||||||
p = stpcpy(mapspath, "/proc/");
|
p = stpcpy(mapspath, "/proc/");
|
||||||
p += int64toarray_radix10(pid, p);
|
p = FormatInt64(p, pid);
|
||||||
stpcpy(p, "/maps");
|
stpcpy(p, "/maps");
|
||||||
} else {
|
} else {
|
||||||
if (optind == argc) {
|
if (optind == argc) {
|
||||||
|
|
|
@ -857,8 +857,8 @@ static void OpenVideo(void) {
|
||||||
plm_set_video_decode_callback(plm_, OnVideo, NULL);
|
plm_set_video_decode_callback(plm_, OnVideo, NULL);
|
||||||
plm_set_audio_decode_callback(plm_, OnAudio, NULL);
|
plm_set_audio_decode_callback(plm_, OnAudio, NULL);
|
||||||
plm_set_loop(plm_, false);
|
plm_set_loop(plm_, false);
|
||||||
int64toarray_radix10((chans_ = 2), chansstr_);
|
FormatInt64(chansstr_, (chans_ = 2));
|
||||||
int64toarray_radix10((srate_ = plm_get_samplerate(plm_)), sratestr_);
|
FormatInt64(sratestr_, (srate_ = plm_get_samplerate(plm_)));
|
||||||
if (plm_get_num_audio_streams(plm_) && OpenSpeaker()) {
|
if (plm_get_num_audio_streams(plm_) && OpenSpeaker()) {
|
||||||
plm_set_audio_enabled(plm_, true, 0);
|
plm_set_audio_enabled(plm_, true, 0);
|
||||||
} else {
|
} else {
|
||||||
|
|
Loading…
Reference in a new issue