mirror of
https://github.com/jart/cosmopolitan.git
synced 2025-05-23 05:42:29 +00:00
Fix some issues and do some code cleanup
This commit is contained in:
parent
1f229e4efc
commit
312ed5c67c
72 changed files with 880 additions and 982 deletions
|
@ -18,6 +18,7 @@
|
||||||
#include "libc/fmt/conv.h"
|
#include "libc/fmt/conv.h"
|
||||||
#include "libc/fmt/itoa.h"
|
#include "libc/fmt/itoa.h"
|
||||||
#include "libc/intrin/kprintf.h"
|
#include "libc/intrin/kprintf.h"
|
||||||
|
#include "libc/limits.h"
|
||||||
#include "libc/log/check.h"
|
#include "libc/log/check.h"
|
||||||
#include "libc/log/log.h"
|
#include "libc/log/log.h"
|
||||||
#include "libc/macros.internal.h"
|
#include "libc/macros.internal.h"
|
||||||
|
@ -96,11 +97,12 @@
|
||||||
"Referrer-Policy: origin\r\n" \
|
"Referrer-Policy: origin\r\n" \
|
||||||
"Cache-Control: private; max-age=0\r\n"
|
"Cache-Control: private; max-age=0\r\n"
|
||||||
|
|
||||||
int workers;
|
_Atomic(int) workers;
|
||||||
int messages;
|
_Atomic(int) messages;
|
||||||
int connections;
|
_Atomic(int) listening;
|
||||||
const char *status;
|
_Atomic(int) connections;
|
||||||
_Atomic(int) closingtime;
|
_Atomic(int) closingtime;
|
||||||
|
const char *volatile status;
|
||||||
|
|
||||||
int Worker(void *id) {
|
int Worker(void *id) {
|
||||||
int server, yes = 1;
|
int server, yes = 1;
|
||||||
|
@ -132,6 +134,7 @@ int Worker(void *id) {
|
||||||
listen(server, 1);
|
listen(server, 1);
|
||||||
|
|
||||||
// connection loop
|
// connection loop
|
||||||
|
++listening;
|
||||||
while (!closingtime) {
|
while (!closingtime) {
|
||||||
struct tm tm;
|
struct tm tm;
|
||||||
int64_t unixts;
|
int64_t unixts;
|
||||||
|
@ -167,7 +170,7 @@ int Worker(void *id) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
asm volatile("lock incl\t%0" : "+m"(connections));
|
++connections;
|
||||||
|
|
||||||
// message loop
|
// message loop
|
||||||
do {
|
do {
|
||||||
|
@ -177,12 +180,12 @@ int Worker(void *id) {
|
||||||
if ((got = read(client, inbuf, sizeof(inbuf))) <= 0) break;
|
if ((got = read(client, inbuf, sizeof(inbuf))) <= 0) break;
|
||||||
// check that client message wasn't fragmented into more reads
|
// check that client message wasn't fragmented into more reads
|
||||||
if (!(inmsglen = ParseHttpMessage(&msg, inbuf, got))) break;
|
if (!(inmsglen = ParseHttpMessage(&msg, inbuf, got))) break;
|
||||||
asm volatile("lock incl\t%0" : "+m"(messages));
|
++messages;
|
||||||
|
|
||||||
#if LOGGING
|
#if LOGGING
|
||||||
// log the incoming http message
|
// log the incoming http message
|
||||||
clientip = ntohl(clientaddr.sin_addr.s_addr);
|
clientip = ntohl(clientaddr.sin_addr.s_addr);
|
||||||
kprintf("#%.4x get some %d.%d.%d.%d:%d %#.*s\n", (intptr_t)id,
|
kprintf("%6P get some %d.%d.%d.%d:%d %#.*s\n",
|
||||||
(clientip & 0xff000000) >> 030, (clientip & 0x00ff0000) >> 020,
|
(clientip & 0xff000000) >> 030, (clientip & 0x00ff0000) >> 020,
|
||||||
(clientip & 0x0000ff00) >> 010, (clientip & 0x000000ff) >> 000,
|
(clientip & 0x0000ff00) >> 010, (clientip & 0x000000ff) >> 000,
|
||||||
ntohs(clientaddr.sin_port), msg.uri.b - msg.uri.a,
|
ntohs(clientaddr.sin_port), msg.uri.b - msg.uri.a,
|
||||||
|
@ -200,7 +203,7 @@ int Worker(void *id) {
|
||||||
p = stpcpy(outbuf, "HTTP/1.1 200 OK\r\n" STANDARD_RESPONSE_HEADERS
|
p = stpcpy(outbuf, "HTTP/1.1 200 OK\r\n" STANDARD_RESPONSE_HEADERS
|
||||||
"Content-Type: text/html; charset=utf-8\r\n"
|
"Content-Type: text/html; charset=utf-8\r\n"
|
||||||
"Date: ");
|
"Date: ");
|
||||||
clock_gettime(CLOCK_REALTIME, &ts), unixts = ts.tv_sec;
|
clock_gettime(0, &ts), unixts = ts.tv_sec;
|
||||||
p = FormatHttpDateTime(p, gmtime_r(&unixts, &tm));
|
p = FormatHttpDateTime(p, gmtime_r(&unixts, &tm));
|
||||||
p = stpcpy(p, "\r\nContent-Length: ");
|
p = stpcpy(p, "\r\nContent-Length: ");
|
||||||
p = FormatInt32(p, strlen(q));
|
p = FormatInt32(p, strlen(q));
|
||||||
|
@ -218,7 +221,7 @@ int Worker(void *id) {
|
||||||
"HTTP/1.1 404 Not Found\r\n" STANDARD_RESPONSE_HEADERS
|
"HTTP/1.1 404 Not Found\r\n" STANDARD_RESPONSE_HEADERS
|
||||||
"Content-Type: text/html; charset=utf-8\r\n"
|
"Content-Type: text/html; charset=utf-8\r\n"
|
||||||
"Date: ");
|
"Date: ");
|
||||||
clock_gettime(CLOCK_REALTIME, &ts), unixts = ts.tv_sec;
|
clock_gettime(0, &ts), unixts = ts.tv_sec;
|
||||||
p = FormatHttpDateTime(p, gmtime_r(&unixts, &tm));
|
p = FormatHttpDateTime(p, gmtime_r(&unixts, &tm));
|
||||||
p = stpcpy(p, "\r\nContent-Length: ");
|
p = stpcpy(p, "\r\nContent-Length: ");
|
||||||
p = FormatInt32(p, strlen(q));
|
p = FormatInt32(p, strlen(q));
|
||||||
|
@ -238,13 +241,14 @@ int Worker(void *id) {
|
||||||
(msg.method == kHttpGet || msg.method == kHttpHead));
|
(msg.method == kHttpGet || msg.method == kHttpHead));
|
||||||
DestroyHttpMessage(&msg);
|
DestroyHttpMessage(&msg);
|
||||||
close(client);
|
close(client);
|
||||||
asm volatile("lock decl\t%0" : "+m"(connections));
|
--connections;
|
||||||
}
|
}
|
||||||
|
--listening;
|
||||||
|
|
||||||
// inform the parent that this clone has finished
|
// inform the parent that this clone has finished
|
||||||
WorkerFinished:
|
WorkerFinished:
|
||||||
close(server);
|
close(server);
|
||||||
asm volatile("lock decl\t%0" : "+m"(workers));
|
--workers;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -253,35 +257,85 @@ void OnCtrlC(int sig) {
|
||||||
status = " shutting down...";
|
status = " shutting down...";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void PrintStatus(void) {
|
||||||
|
kprintf("\r\e[K\e[32mgreenbean\e[0m "
|
||||||
|
"workers=%d "
|
||||||
|
"listening=%d "
|
||||||
|
"connections=%d "
|
||||||
|
"messages=%d%s ",
|
||||||
|
workers, listening, connections, messages, status);
|
||||||
|
}
|
||||||
|
|
||||||
int main(int argc, char *argv[]) {
|
int main(int argc, char *argv[]) {
|
||||||
|
char **tls;
|
||||||
|
char **stack;
|
||||||
int i, threads;
|
int i, threads;
|
||||||
uint32_t *hostips;
|
uint32_t *hostips;
|
||||||
// ShowCrashReports();
|
// ShowCrashReports();
|
||||||
sigaction(SIGINT, &(struct sigaction){.sa_handler = OnCtrlC}, 0);
|
|
||||||
|
// listen for ctrl-c, hangup, and kill which shut down greenbean
|
||||||
|
status = "";
|
||||||
|
struct sigaction sa = {.sa_handler = OnCtrlC};
|
||||||
|
sigaction(SIGHUP, &sa, 0);
|
||||||
|
sigaction(SIGINT, &sa, 0);
|
||||||
|
sigaction(SIGTERM, &sa, 0);
|
||||||
|
|
||||||
|
// print all the ips that 0.0.0.0 will bind
|
||||||
for (hostips = GetHostIps(), i = 0; hostips[i]; ++i) {
|
for (hostips = GetHostIps(), i = 0; hostips[i]; ++i) {
|
||||||
kprintf("listening on http://%d.%d.%d.%d:%d\n",
|
kprintf("listening on http://%d.%d.%d.%d:%d\n",
|
||||||
(hostips[i] & 0xff000000) >> 030, (hostips[i] & 0x00ff0000) >> 020,
|
(hostips[i] & 0xff000000) >> 030, (hostips[i] & 0x00ff0000) >> 020,
|
||||||
(hostips[i] & 0x0000ff00) >> 010, (hostips[i] & 0x000000ff) >> 000,
|
(hostips[i] & 0x0000ff00) >> 010, (hostips[i] & 0x000000ff) >> 000,
|
||||||
PORT);
|
PORT);
|
||||||
}
|
}
|
||||||
threads = argc > 1 ? atoi(argv[1]) : 0;
|
|
||||||
|
// spawn over 9,000 worker threads
|
||||||
|
tls = 0;
|
||||||
|
stack = 0;
|
||||||
|
threads = argc > 1 ? atoi(argv[1]) : GetCpuCount();
|
||||||
|
if ((1 <= threads && threads <= INT_MAX) &&
|
||||||
|
(tls = malloc(threads * sizeof(*tls))) &&
|
||||||
|
(stack = malloc(threads * sizeof(*stack)))) {
|
||||||
if (!threads) threads = GetCpuCount();
|
if (!threads) threads = GetCpuCount();
|
||||||
workers = threads;
|
|
||||||
for (i = 0; i < threads; ++i) {
|
for (i = 0; i < threads; ++i) {
|
||||||
char *tls = __initialize_tls(malloc(64));
|
if ((tls[i] = __initialize_tls(malloc(64))) &&
|
||||||
void *stack = mmap(0, GetStackSize(), PROT_READ | PROT_WRITE,
|
(stack[i] = mmap(0, GetStackSize(), PROT_READ | PROT_WRITE,
|
||||||
MAP_STACK | MAP_ANONYMOUS, -1, 0);
|
MAP_STACK | MAP_ANONYMOUS, -1, 0)) != MAP_FAILED) {
|
||||||
CHECK_NE(-1, clone(Worker, stack, GetStackSize(),
|
++workers;
|
||||||
|
if (clone(Worker, stack[i], GetStackSize(),
|
||||||
CLONE_THREAD | CLONE_VM | CLONE_FS | CLONE_FILES |
|
CLONE_THREAD | CLONE_VM | CLONE_FS | CLONE_FILES |
|
||||||
CLONE_SIGHAND | CLONE_SETTLS,
|
CLONE_SIGHAND | CLONE_SETTLS | CLONE_CHILD_SETTID |
|
||||||
(void *)(intptr_t)i, 0, tls, 64, 0));
|
CLONE_CHILD_CLEARTID,
|
||||||
|
(void *)(intptr_t)i, 0, tls[i], 64,
|
||||||
|
(int *)(tls[i] + 0x38)) == -1) {
|
||||||
|
--workers;
|
||||||
|
kprintf("error: clone(%d) failed %m\n", i);
|
||||||
}
|
}
|
||||||
status = "";
|
} else {
|
||||||
|
kprintf("error: mmap(%d) failed %m\n", i);
|
||||||
|
}
|
||||||
|
if (!(i % 500)) {
|
||||||
|
PrintStatus();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
kprintf("error: invalid number of threads\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
// wait for workers to terminate
|
||||||
while (workers) {
|
while (workers) {
|
||||||
kprintf(
|
PrintStatus();
|
||||||
"\r\e[K\e[32mgreenbean\e[0m workers=%d connections=%d messages=%d%s ",
|
|
||||||
workers, connections, messages, status);
|
|
||||||
usleep(HEARTBEAT * 1000);
|
usleep(HEARTBEAT * 1000);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// clean up terminal line
|
||||||
kprintf("\r\e[K");
|
kprintf("\r\e[K");
|
||||||
|
|
||||||
|
// clean up memory
|
||||||
|
for (i = 0; i < threads; ++i) {
|
||||||
|
if (stack) munmap(stack[i], GetStackSize());
|
||||||
|
if (tls) free(tls[i]);
|
||||||
|
}
|
||||||
|
free(hostips);
|
||||||
|
free(stack);
|
||||||
|
free(tls);
|
||||||
}
|
}
|
||||||
|
|
|
@ -130,18 +130,18 @@ int geteuid(void) nosideeffect;
|
||||||
int getgid(void) nosideeffect;
|
int getgid(void) nosideeffect;
|
||||||
int gethostname(char *, size_t);
|
int gethostname(char *, size_t);
|
||||||
int getloadavg(double *, int);
|
int getloadavg(double *, int);
|
||||||
int getpgid(int);
|
int getpgid(int) nosideeffect libcesque;
|
||||||
int getpgrp(void) nosideeffect;
|
int getpgrp(void) nosideeffect;
|
||||||
int getpid(void);
|
int getpid(void) nosideeffect libcesque;
|
||||||
int getppid(void);
|
int getppid(void);
|
||||||
int getpriority(int, unsigned);
|
int getpriority(int, unsigned);
|
||||||
int getresgid(uint32_t *, uint32_t *, uint32_t *);
|
int getresgid(uint32_t *, uint32_t *, uint32_t *);
|
||||||
int getresuid(uint32_t *, uint32_t *, uint32_t *);
|
int getresuid(uint32_t *, uint32_t *, uint32_t *);
|
||||||
int getrlimit(int, struct rlimit *);
|
int getrlimit(int, struct rlimit *);
|
||||||
int getrusage(int, struct rusage *);
|
int getrusage(int, struct rusage *);
|
||||||
int getsid(int) nosideeffect;
|
int getsid(int) nosideeffect libcesque;
|
||||||
int gettid(void);
|
int gettid(void) libcesque;
|
||||||
int getuid(void) nosideeffect;
|
int getuid(void) nosideeffect libcesque;
|
||||||
int kill(int, int);
|
int kill(int, int);
|
||||||
int killpg(int, int);
|
int killpg(int, int);
|
||||||
int link(const char *, const char *) dontthrow;
|
int link(const char *, const char *) dontthrow;
|
||||||
|
|
|
@ -80,8 +80,6 @@ noinstrument int clock_gettime(int clockid, struct timespec *ts) {
|
||||||
* Returns fast system clock_gettime() if it exists.
|
* Returns fast system clock_gettime() if it exists.
|
||||||
*/
|
*/
|
||||||
void *__get_clock_gettime(void) {
|
void *__get_clock_gettime(void) {
|
||||||
// TODO(jart): Re-enable this.
|
|
||||||
return 0;
|
|
||||||
void *vdso;
|
void *vdso;
|
||||||
static bool once;
|
static bool once;
|
||||||
static void *result;
|
static void *result;
|
||||||
|
|
|
@ -24,6 +24,7 @@
|
||||||
#include "libc/nt/console.h"
|
#include "libc/nt/console.h"
|
||||||
#include "libc/nt/enum/consolemodeflags.h"
|
#include "libc/nt/enum/consolemodeflags.h"
|
||||||
#include "libc/nt/enum/version.h"
|
#include "libc/nt/enum/version.h"
|
||||||
|
#include "libc/nt/version.h"
|
||||||
#include "libc/sysv/consts/o.h"
|
#include "libc/sysv/consts/o.h"
|
||||||
#include "libc/sysv/consts/termios.h"
|
#include "libc/sysv/consts/termios.h"
|
||||||
#include "libc/sysv/errfuns.h"
|
#include "libc/sysv/errfuns.h"
|
||||||
|
@ -57,7 +58,7 @@ textwindows int ioctl_tcsets_nt(int ignored, uint64_t request,
|
||||||
if (tio->c_lflag & (IEXTEN | ISIG)) {
|
if (tio->c_lflag & (IEXTEN | ISIG)) {
|
||||||
inmode |= kNtEnableProcessedInput;
|
inmode |= kNtEnableProcessedInput;
|
||||||
}
|
}
|
||||||
if (NtGetVersion() >= kNtVersionWindows10) {
|
if (IsAtLeastWindows10()) {
|
||||||
inmode |= kNtEnableVirtualTerminalInput;
|
inmode |= kNtEnableVirtualTerminalInput;
|
||||||
}
|
}
|
||||||
ok = SetConsoleMode(in, inmode);
|
ok = SetConsoleMode(in, inmode);
|
||||||
|
@ -71,7 +72,7 @@ textwindows int ioctl_tcsets_nt(int ignored, uint64_t request,
|
||||||
if (!(tio->c_oflag & ONLCR)) {
|
if (!(tio->c_oflag & ONLCR)) {
|
||||||
outmode |= kNtDisableNewlineAutoReturn;
|
outmode |= kNtDisableNewlineAutoReturn;
|
||||||
}
|
}
|
||||||
if (NtGetVersion() >= kNtVersionWindows10) {
|
if (IsAtLeastWindows10()) {
|
||||||
outmode |= kNtEnableVirtualTerminalProcessing;
|
outmode |= kNtEnableVirtualTerminalProcessing;
|
||||||
}
|
}
|
||||||
ok = SetConsoleMode(out, outmode);
|
ok = SetConsoleMode(out, outmode);
|
||||||
|
|
|
@ -16,17 +16,13 @@
|
||||||
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
||||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||||
#include "libc/bits/weaken.h"
|
|
||||||
#include "libc/calls/calls.h"
|
#include "libc/calls/calls.h"
|
||||||
#include "libc/calls/internal.h"
|
#include "libc/calls/internal.h"
|
||||||
#include "libc/calls/struct/metastat.internal.h"
|
#include "libc/calls/struct/metastat.internal.h"
|
||||||
#include "libc/calls/struct/stat.h"
|
|
||||||
#include "libc/dce.h"
|
#include "libc/dce.h"
|
||||||
#include "libc/errno.h"
|
#include "libc/errno.h"
|
||||||
#include "libc/nt/enum/filetype.h"
|
#include "libc/nt/enum/filetype.h"
|
||||||
#include "libc/nt/files.h"
|
#include "libc/nt/files.h"
|
||||||
#include "libc/sysv/errfuns.h"
|
|
||||||
#include "libc/zipos/zipos.internal.h"
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns true if file descriptor is backed by character i/o.
|
* Returns true if file descriptor is backed by character i/o.
|
||||||
|
@ -44,15 +40,7 @@ bool32 ischardev(int fd) {
|
||||||
int e;
|
int e;
|
||||||
union metastat st;
|
union metastat st;
|
||||||
if (__isfdkind(fd, kFdZip)) {
|
if (__isfdkind(fd, kFdZip)) {
|
||||||
e = errno;
|
|
||||||
if (weaken(__zipos_fstat)(
|
|
||||||
(struct ZiposHandle *)(intptr_t)g_fds.p[fd].handle, &st.cosmo) !=
|
|
||||||
-1) {
|
|
||||||
return S_ISCHR(st.cosmo.st_mode);
|
|
||||||
} else {
|
|
||||||
errno = e;
|
|
||||||
return false;
|
return false;
|
||||||
}
|
|
||||||
} else if (IsMetal()) {
|
} else if (IsMetal()) {
|
||||||
return true;
|
return true;
|
||||||
} else if (!IsWindows()) {
|
} else if (!IsWindows()) {
|
||||||
|
|
|
@ -97,7 +97,8 @@ static long double nowl_vdso(void) {
|
||||||
|
|
||||||
long double nowl_setup(void) {
|
long double nowl_setup(void) {
|
||||||
uint64_t ticks;
|
uint64_t ticks;
|
||||||
if ((g_now.clock_gettime = __get_clock_gettime())) {
|
if (0 && (g_now.clock_gettime = __get_clock_gettime())) {
|
||||||
|
// TODO(jart): Re-enable this.
|
||||||
nowl = nowl_vdso;
|
nowl = nowl_vdso;
|
||||||
} else if (X86_HAVE(INVTSC)) {
|
} else if (X86_HAVE(INVTSC)) {
|
||||||
RefreshTime();
|
RefreshTime();
|
||||||
|
@ -107,5 +108,3 @@ long double nowl_setup(void) {
|
||||||
}
|
}
|
||||||
return nowl();
|
return nowl();
|
||||||
}
|
}
|
||||||
|
|
||||||
long double (*nowl)(void) = nowl_setup;
|
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
|
/*-*- mode:unix-assembly; indent-tabs-mode:t; tab-width:8; coding:utf-8 -*-│
|
||||||
│vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi│
|
│vi: set et ft=asm ts=8 tw=8 fenc=utf-8 :vi│
|
||||||
╞══════════════════════════════════════════════════════════════════════════════╡
|
╞══════════════════════════════════════════════════════════════════════════════╡
|
||||||
│ Copyright 2022 Justine Alexandra Roberts Tunney │
|
│ Copyright 2022 Justine Alexandra Roberts Tunney │
|
||||||
│ │
|
│ │
|
||||||
|
@ -16,13 +16,14 @@
|
||||||
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
||||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||||
#include "libc/calls/calls.h"
|
#include "libc/macros.internal.h"
|
||||||
|
|
||||||
/**
|
.initbss 201,_init_nowl
|
||||||
* Maximum amount of virtual memory in bytes.
|
nowl: .quad 0
|
||||||
*
|
.endobj nowl,globl
|
||||||
* mmap() will return ENOMEM once this is reached.
|
.previous
|
||||||
*
|
|
||||||
* By default no limit is imposed.
|
.init.start 201,_init_nowl
|
||||||
*/
|
ezlea nowl_setup,ax
|
||||||
size_t __virtualmax = -1;
|
stosq
|
||||||
|
.init.end 201,_init_nowl
|
|
@ -81,7 +81,13 @@ textwindows void _check_sigalrm(void) {
|
||||||
textwindows int sys_setitimer_nt(int which, const struct itimerval *newvalue,
|
textwindows int sys_setitimer_nt(int which, const struct itimerval *newvalue,
|
||||||
struct itimerval *out_opt_oldvalue) {
|
struct itimerval *out_opt_oldvalue) {
|
||||||
long double elapsed, untilnext;
|
long double elapsed, untilnext;
|
||||||
if (which != ITIMER_REAL) return einval();
|
if (which != ITIMER_REAL ||
|
||||||
|
(newvalue && (!(0 <= newvalue->it_value.tv_usec &&
|
||||||
|
newvalue->it_value.tv_usec < 1000000) ||
|
||||||
|
!(0 <= newvalue->it_interval.tv_usec &&
|
||||||
|
newvalue->it_interval.tv_usec < 1000000)))) {
|
||||||
|
return einval();
|
||||||
|
}
|
||||||
if (out_opt_oldvalue) {
|
if (out_opt_oldvalue) {
|
||||||
if (__hastimer) {
|
if (__hastimer) {
|
||||||
elapsed = nowl() - __lastalrm;
|
elapsed = nowl() - __lastalrm;
|
||||||
|
|
|
@ -48,7 +48,7 @@ static inline textwindows noasan int NtGetBuildNumber(void) {
|
||||||
* @return 0 on success, or -1 w/ errno
|
* @return 0 on success, or -1 w/ errno
|
||||||
*/
|
*/
|
||||||
int uname(struct utsname *lool) {
|
int uname(struct utsname *lool) {
|
||||||
int rc, v;
|
int rc;
|
||||||
char *out, *p;
|
char *out, *p;
|
||||||
size_t i, j, len;
|
size_t i, j, len;
|
||||||
char tmp[sizeof(struct utsname)];
|
char tmp[sizeof(struct utsname)];
|
||||||
|
@ -87,7 +87,6 @@ int uname(struct utsname *lool) {
|
||||||
rc = enosys();
|
rc = enosys();
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
v = NtGetVersion();
|
|
||||||
p = lool->release;
|
p = lool->release;
|
||||||
p = FormatUint32(p, NtGetMajorVersion()), *p++ = '.';
|
p = FormatUint32(p, NtGetMajorVersion()), *p++ = '.';
|
||||||
p = FormatUint32(p, NtGetMinorVersion()), *p++ = '-';
|
p = FormatUint32(p, NtGetMinorVersion()), *p++ = '-';
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
/*-*- mode:unix-assembly; indent-tabs-mode:t; tab-width:8; coding:utf-8 -*-│
|
/*-*- mode:unix-assembly; indent-tabs-mode:t; tab-width:8; coding:utf-8 -*-│
|
||||||
│vi: set et ft=asm ts=8 tw=8 fenc=utf-8 :vi│
|
│vi: set et ft=asm ts=8 tw=8 fenc=utf-8 :vi│
|
||||||
╞══════════════════════════════════════════════════════════════════════════════╡
|
╞══════════════════════════════════════════════════════════════════════════════╡
|
||||||
│ Copyright 2020 Justine Alexandra Roberts Tunney │
|
│ Copyright 2022 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 │
|
||||||
|
@ -18,16 +18,20 @@
|
||||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||||
#include "libc/macros.internal.h"
|
#include "libc/macros.internal.h"
|
||||||
|
|
||||||
// Blocks until data from stream buffer is written out.
|
.initbss 201,_init___virtualmax
|
||||||
|
|
||||||
|
// Maximum amount of virtual memory in bytes.
|
||||||
//
|
//
|
||||||
// @param rdi is the stream handle, or 0 for all streams
|
// mmap() will return ENOMEM once this is reached.
|
||||||
// @return 0 on success or -1 w/ errno
|
//
|
||||||
// @see fflush_unlocked()
|
// By default no limit is imposed.
|
||||||
// @threadsafe
|
__virtualmax:
|
||||||
fflush: ezlea fflush_unlocked,ax
|
.quad 0
|
||||||
test %rdi,%rdi
|
.endobj __virtualmax,globl
|
||||||
jz 1f
|
.previous
|
||||||
mov %rdi,%r11
|
|
||||||
jmp stdio_unlock
|
.init.start 201,_init___virtualmax
|
||||||
1: jmp *%rax
|
push $-1
|
||||||
.endfn fflush,globl
|
pop %rax
|
||||||
|
stosq
|
||||||
|
.init.end 201,_init___virtualmax
|
|
@ -199,7 +199,7 @@ static char *__asan_utf8cpy(char *p, unsigned c) {
|
||||||
return p;
|
return p;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void *__asan_memset(void *p, char c, size_t n) {
|
static void __asan_memset(void *p, char c, size_t n) {
|
||||||
char *b;
|
char *b;
|
||||||
size_t i;
|
size_t i;
|
||||||
uint64_t x;
|
uint64_t x;
|
||||||
|
@ -207,29 +207,29 @@ static void *__asan_memset(void *p, char c, size_t n) {
|
||||||
x = 0x0101010101010101ul * (c & 255);
|
x = 0x0101010101010101ul * (c & 255);
|
||||||
switch (n) {
|
switch (n) {
|
||||||
case 0:
|
case 0:
|
||||||
return p;
|
break;
|
||||||
case 1:
|
case 1:
|
||||||
__builtin_memcpy(b, &x, 1);
|
__builtin_memcpy(b, &x, 1);
|
||||||
return p;
|
break;
|
||||||
case 2:
|
case 2:
|
||||||
__builtin_memcpy(b, &x, 2);
|
__builtin_memcpy(b, &x, 2);
|
||||||
return p;
|
break;
|
||||||
case 3:
|
case 3:
|
||||||
__builtin_memcpy(b, &x, 2);
|
__builtin_memcpy(b, &x, 2);
|
||||||
__builtin_memcpy(b + 1, &x, 2);
|
__builtin_memcpy(b + 1, &x, 2);
|
||||||
return p;
|
break;
|
||||||
case 4:
|
case 4:
|
||||||
__builtin_memcpy(b, &x, 4);
|
__builtin_memcpy(b, &x, 4);
|
||||||
return p;
|
break;
|
||||||
case 5:
|
case 5:
|
||||||
case 6:
|
case 6:
|
||||||
case 7:
|
case 7:
|
||||||
__builtin_memcpy(b, &x, 4);
|
__builtin_memcpy(b, &x, 4);
|
||||||
__builtin_memcpy(b + n - 4, &x, 4);
|
__builtin_memcpy(b + n - 4, &x, 4);
|
||||||
return p;
|
break;
|
||||||
case 8:
|
case 8:
|
||||||
__builtin_memcpy(b, &x, 8);
|
__builtin_memcpy(b, &x, 8);
|
||||||
return p;
|
break;
|
||||||
case 9:
|
case 9:
|
||||||
case 10:
|
case 10:
|
||||||
case 11:
|
case 11:
|
||||||
|
@ -240,7 +240,7 @@ static void *__asan_memset(void *p, char c, size_t n) {
|
||||||
case 16:
|
case 16:
|
||||||
__builtin_memcpy(b, &x, 8);
|
__builtin_memcpy(b, &x, 8);
|
||||||
__builtin_memcpy(b + n - 8, &x, 8);
|
__builtin_memcpy(b + n - 8, &x, 8);
|
||||||
return p;
|
break;
|
||||||
default:
|
default:
|
||||||
if (n <= 64) {
|
if (n <= 64) {
|
||||||
i = 0;
|
i = 0;
|
||||||
|
@ -253,83 +253,10 @@ static void *__asan_memset(void *p, char c, size_t n) {
|
||||||
} else {
|
} else {
|
||||||
__repstosb(p, c, n);
|
__repstosb(p, c, n);
|
||||||
}
|
}
|
||||||
return p;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void *__asan_mempcpy(void *dst, const void *src, size_t n) {
|
|
||||||
size_t i;
|
|
||||||
char *d;
|
|
||||||
const char *s;
|
|
||||||
uint64_t a, b;
|
|
||||||
d = dst;
|
|
||||||
s = src;
|
|
||||||
switch (n) {
|
|
||||||
case 0:
|
|
||||||
return d;
|
|
||||||
case 1:
|
|
||||||
*d = *s;
|
|
||||||
return d + 1;
|
|
||||||
case 2:
|
|
||||||
__builtin_memcpy(&a, s, 2);
|
|
||||||
__builtin_memcpy(d, &a, 2);
|
|
||||||
return d + 2;
|
|
||||||
case 3:
|
|
||||||
__builtin_memcpy(&a, s, 2);
|
|
||||||
__builtin_memcpy(&b, s + 1, 2);
|
|
||||||
__builtin_memcpy(d, &a, 2);
|
|
||||||
__builtin_memcpy(d + 1, &b, 2);
|
|
||||||
return d + 3;
|
|
||||||
case 4:
|
|
||||||
__builtin_memcpy(&a, s, 4);
|
|
||||||
__builtin_memcpy(d, &a, 4);
|
|
||||||
return d + 4;
|
|
||||||
case 5:
|
|
||||||
case 6:
|
|
||||||
case 7:
|
|
||||||
__builtin_memcpy(&a, s, 4);
|
|
||||||
__builtin_memcpy(&b, s + n - 4, 4);
|
|
||||||
__builtin_memcpy(d, &a, 4);
|
|
||||||
__builtin_memcpy(d + n - 4, &b, 4);
|
|
||||||
return d + n;
|
|
||||||
case 8:
|
|
||||||
__builtin_memcpy(&a, s, 8);
|
|
||||||
__builtin_memcpy(d, &a, 8);
|
|
||||||
return d + 8;
|
|
||||||
case 9:
|
|
||||||
case 10:
|
|
||||||
case 11:
|
|
||||||
case 12:
|
|
||||||
case 13:
|
|
||||||
case 14:
|
|
||||||
case 15:
|
|
||||||
case 16:
|
|
||||||
__builtin_memcpy(&a, s, 8);
|
|
||||||
__builtin_memcpy(&b, s + n - 8, 8);
|
|
||||||
__builtin_memcpy(d, &a, 8);
|
|
||||||
__builtin_memcpy(d + n - 8, &b, 8);
|
|
||||||
return d + n;
|
|
||||||
default:
|
|
||||||
if (n <= 64) {
|
|
||||||
i = 0;
|
|
||||||
do {
|
|
||||||
__builtin_memcpy(&a, s + i, 8);
|
|
||||||
asm volatile("" ::: "memory");
|
|
||||||
__builtin_memcpy(d + i, &a, 8);
|
|
||||||
} while ((i += 8) + 8 <= n);
|
|
||||||
for (; i < n; ++i) d[i] = s[i];
|
|
||||||
return d + i;
|
|
||||||
} else {
|
|
||||||
return __repmovsb(d, s, n);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static void *__asan_memcpy(void *dst, const void *src, size_t n) {
|
|
||||||
__asan_mempcpy(dst, src, n);
|
|
||||||
return dst;
|
|
||||||
}
|
|
||||||
|
|
||||||
static char *__asan_hexcpy(char *p, uint64_t x, uint8_t k) {
|
static char *__asan_hexcpy(char *p, uint64_t x, uint8_t k) {
|
||||||
while (k) *p++ = "0123456789abcdef"[(x >> (k -= 4)) & 15];
|
while (k) *p++ = "0123456789abcdef"[(x >> (k -= 4)) & 15];
|
||||||
return p;
|
return p;
|
||||||
|
@ -736,7 +663,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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -946,7 +873,7 @@ static void __asan_trace(struct AsanTrace *bt, const struct StackFrame *bp) {
|
||||||
|
|
||||||
#define __asan_trace __asan_rawtrace
|
#define __asan_trace __asan_rawtrace
|
||||||
|
|
||||||
static void *__asan_allocate(size_t a, size_t n, int underrun, int overrun,
|
void *__asan_allocate(size_t a, size_t n, int underrun, int overrun,
|
||||||
struct AsanTrace *bt) {
|
struct AsanTrace *bt) {
|
||||||
char *p;
|
char *p;
|
||||||
size_t c;
|
size_t c;
|
||||||
|
@ -960,7 +887,7 @@ static void *__asan_allocate(size_t a, size_t n, int underrun, int overrun,
|
||||||
__asan_poison(p + n, c - n, overrun);
|
__asan_poison(p + n, c - n, overrun);
|
||||||
__asan_memset(p, 0xF9, n);
|
__asan_memset(p, 0xF9, n);
|
||||||
__asan_write48(&e->size, n);
|
__asan_write48(&e->size, n);
|
||||||
__asan_memcpy(&e->bt, bt, sizeof(*bt));
|
__builtin_memcpy(&e->bt, bt, sizeof(*bt));
|
||||||
}
|
}
|
||||||
return p;
|
return p;
|
||||||
}
|
}
|
||||||
|
@ -1082,7 +1009,7 @@ static void *__asan_realloc_grow(void *p, size_t n, size_t m,
|
||||||
struct AsanTrace *bt) {
|
struct AsanTrace *bt) {
|
||||||
char *q;
|
char *q;
|
||||||
if ((q = __asan_allocate(16, n, kAsanHeapUnderrun, kAsanHeapOverrun, bt))) {
|
if ((q = __asan_allocate(16, n, kAsanHeapUnderrun, kAsanHeapOverrun, bt))) {
|
||||||
__asan_memcpy(q, p, m);
|
__builtin_memcpy(q, p, m);
|
||||||
__asan_deallocate(p, kAsanHeapRelocated);
|
__asan_deallocate(p, kAsanHeapRelocated);
|
||||||
}
|
}
|
||||||
return q;
|
return q;
|
||||||
|
|
|
@ -46,7 +46,6 @@ relegated wontreturn void __assert_fail(const char *expr, const char *file,
|
||||||
} else {
|
} else {
|
||||||
rc = 24;
|
rc = 24;
|
||||||
}
|
}
|
||||||
if (weaken(__die)) weaken(__die)();
|
|
||||||
__restorewintty();
|
__restorewintty();
|
||||||
_Exit(rc);
|
_Exit(rc);
|
||||||
}
|
}
|
||||||
|
|
|
@ -23,6 +23,7 @@ const char *DescribeMapFlags(int);
|
||||||
const char *DescribeProtFlags(int);
|
const char *DescribeProtFlags(int);
|
||||||
const char *DescribeRemapFlags(int);
|
const char *DescribeRemapFlags(int);
|
||||||
const char *DescribeRlimitName(int);
|
const char *DescribeRlimitName(int);
|
||||||
|
const char *DescribePersonalityFlags(int);
|
||||||
const char *DescribeSeccompOperationFlags(int);
|
const char *DescribeSeccompOperationFlags(int);
|
||||||
const char *DescribePollFlags(char *, size_t, int);
|
const char *DescribePollFlags(char *, size_t, int);
|
||||||
const char *DescribeStat(int, const struct stat *);
|
const char *DescribeStat(int, const struct stat *);
|
||||||
|
|
43
libc/intrin/describepersonalityflags.c
Normal file
43
libc/intrin/describepersonalityflags.c
Normal file
|
@ -0,0 +1,43 @@
|
||||||
|
/*-*- 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/intrin/describeflags.internal.h"
|
||||||
|
#include "libc/macros.internal.h"
|
||||||
|
#include "libc/nt/enum/accessmask.h"
|
||||||
|
#include "libc/nt/enum/filesharemode.h"
|
||||||
|
#include "libc/sysv/consts/personality.h"
|
||||||
|
|
||||||
|
static const struct DescribeFlags kPersonalityFlags[] = {
|
||||||
|
{ADDR_COMPAT_LAYOUT, "ADDR_COMPAT_LAYOUT"}, //
|
||||||
|
{READ_IMPLIES_EXEC, "READ_IMPLIES_EXEC"}, //
|
||||||
|
{ADDR_LIMIT_3GB, "ADDR_LIMIT_3GB"}, //
|
||||||
|
{FDPIC_FUNCPTRS, "FDPIC_FUNCPTRS"}, //
|
||||||
|
{STICKY_TIMEOUTS, "STICKY_TIMEOUTS"}, //
|
||||||
|
{MMAP_PAGE_ZERO, "MMAP_PAGE_ZERO"}, //
|
||||||
|
{ADDR_LIMIT_32BIT, "ADDR_LIMIT_32BIT"}, //
|
||||||
|
{WHOLE_SECONDS, "WHOLE_SECONDS"}, //
|
||||||
|
{ADDR_NO_RANDOMIZE, "ADDR_NO_RANDOMIZE"}, //
|
||||||
|
{SHORT_INODE, "SHORT_INODE"}, //
|
||||||
|
{UNAME26, "UNAME26"}, //
|
||||||
|
};
|
||||||
|
|
||||||
|
const char *DescribePersonalityFlags(int x) {
|
||||||
|
_Alignas(char) static char personalityflags[128];
|
||||||
|
return DescribeFlags(personalityflags, sizeof(personalityflags),
|
||||||
|
kPersonalityFlags, ARRAYLEN(kPersonalityFlags), "", x);
|
||||||
|
}
|
|
@ -22,7 +22,17 @@
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns process id.
|
* Returns process id.
|
||||||
|
*
|
||||||
|
* This function does not need to issue a system call. The PID is
|
||||||
|
* tracked by a global variable which is updated atfork(). The only
|
||||||
|
* exception is when the process is vfork()'d in which case a system
|
||||||
|
* call shall be issued.
|
||||||
|
*
|
||||||
|
* On Linux, and only Linux, the process id is guaranteed to be the same
|
||||||
|
* as gettid() for the main thread.
|
||||||
|
*
|
||||||
* @asyncsignalsafe
|
* @asyncsignalsafe
|
||||||
|
* @threadsafe
|
||||||
* @vforksafe
|
* @vforksafe
|
||||||
*/
|
*/
|
||||||
int getpid(void) {
|
int getpid(void) {
|
||||||
|
|
|
@ -32,8 +32,25 @@ __msabi extern typeof(GetCurrentThreadId) *const __imp_GetCurrentThreadId;
|
||||||
* if this is the main thread. On NetBSD, gettid() for the main thread
|
* if this is the main thread. On NetBSD, gettid() for the main thread
|
||||||
* is always 1.
|
* is always 1.
|
||||||
*
|
*
|
||||||
|
* This function issues a system call. That stops being the case as soon
|
||||||
|
* as __install_tls() is called. That'll happen automatically, when you
|
||||||
|
* call clone() and provide the TLS parameter. We assume that when a TLS
|
||||||
|
* block exists, then
|
||||||
|
*
|
||||||
|
* *(int *)(__get_tls() + 0x38)
|
||||||
|
*
|
||||||
|
* will contain the thread id. Therefore when issuing clone() calls, the
|
||||||
|
* `CLONE_CHILD_SETTID` and `CLONE_CHILD_CLEARTID` flags should use that
|
||||||
|
* index as its `ctid` memory.
|
||||||
|
*
|
||||||
|
* gettid (single threaded) l: 126𝑐 41𝑛𝑠
|
||||||
|
* gettid (tls enabled) l: 2𝑐 1𝑛𝑠
|
||||||
|
*
|
||||||
|
* The TLS convention is important for reentrant lock performance.
|
||||||
|
*
|
||||||
* @return thread id greater than zero or -1 w/ errno
|
* @return thread id greater than zero or -1 w/ errno
|
||||||
* @asyncsignalsafe
|
* @asyncsignalsafe
|
||||||
|
* @threadsafe
|
||||||
*/
|
*/
|
||||||
privileged int gettid(void) {
|
privileged int gettid(void) {
|
||||||
int rc;
|
int rc;
|
||||||
|
@ -42,10 +59,8 @@ privileged int gettid(void) {
|
||||||
|
|
||||||
if (__tls_enabled) {
|
if (__tls_enabled) {
|
||||||
rc = *(int *)(__get_tls() + 0x38);
|
rc = *(int *)(__get_tls() + 0x38);
|
||||||
if (rc && rc != -1) {
|
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
if (IsWindows()) {
|
if (IsWindows()) {
|
||||||
return __imp_GetCurrentThreadId();
|
return __imp_GetCurrentThreadId();
|
||||||
|
|
|
@ -46,9 +46,14 @@ $(LIBC_INTRIN_A_OBJS): \
|
||||||
OVERRIDE_CFLAGS += \
|
OVERRIDE_CFLAGS += \
|
||||||
-foptimize-sibling-calls
|
-foptimize-sibling-calls
|
||||||
|
|
||||||
|
# we can't use asan and ubsan because:
|
||||||
|
# this is asan and ubsan
|
||||||
|
# we need -ffreestanding because:
|
||||||
|
# we don't want __builtin_memcpy() calling memcpy()
|
||||||
o/$(MODE)/libc/intrin/asan.o \
|
o/$(MODE)/libc/intrin/asan.o \
|
||||||
o/$(MODE)/libc/intrin/ubsan.o: \
|
o/$(MODE)/libc/intrin/ubsan.o: \
|
||||||
OVERRIDE_CFLAGS += \
|
OVERRIDE_CFLAGS += \
|
||||||
|
-ffreestanding \
|
||||||
-fno-sanitize=all \
|
-fno-sanitize=all \
|
||||||
-fno-stack-protector
|
-fno-stack-protector
|
||||||
|
|
||||||
|
@ -145,12 +150,6 @@ o/$(MODE)/libc/intrin/describeopenflags.greg.o: \
|
||||||
OVERRIDE_CPPFLAGS += \
|
OVERRIDE_CPPFLAGS += \
|
||||||
-DSTACK_FRAME_UNLIMITED
|
-DSTACK_FRAME_UNLIMITED
|
||||||
|
|
||||||
o/$(MODE)/libc/intrin/asan.o \
|
|
||||||
o/$(MODE)/libc/intrin/ubsan.o: \
|
|
||||||
OVERRIDE_CFLAGS += \
|
|
||||||
-fno-sanitize=all \
|
|
||||||
-fno-stack-protector
|
|
||||||
|
|
||||||
o//libc/intrin/memmove.o: \
|
o//libc/intrin/memmove.o: \
|
||||||
OVERRIDE_CFLAGS += \
|
OVERRIDE_CFLAGS += \
|
||||||
-fno-toplevel-reorder
|
-fno-toplevel-reorder
|
||||||
|
|
|
@ -857,7 +857,6 @@ privileged void kvprintf(const char *fmt, va_list v) {
|
||||||
*
|
*
|
||||||
* Specifiers:
|
* Specifiers:
|
||||||
*
|
*
|
||||||
* - `P` pid
|
|
||||||
* - `c` char
|
* - `c` char
|
||||||
* - `o` octal
|
* - `o` octal
|
||||||
* - `b` binary
|
* - `b` binary
|
||||||
|
@ -873,6 +872,7 @@ privileged void kvprintf(const char *fmt, va_list v) {
|
||||||
* - `X` uppercase
|
* - `X` uppercase
|
||||||
* - `T` timestamp
|
* - `T` timestamp
|
||||||
* - `x` hexadecimal
|
* - `x` hexadecimal
|
||||||
|
* - `P` pid (or tid if threaded)
|
||||||
*
|
*
|
||||||
* Types:
|
* Types:
|
||||||
*
|
*
|
||||||
|
|
|
@ -22,9 +22,9 @@
|
||||||
/**
|
/**
|
||||||
* Returns New Technology version, e.g.
|
* Returns New Technology version, e.g.
|
||||||
*
|
*
|
||||||
* if (IsWindows() && NtGetVersion() >=k NtVersionWindows10) {...}
|
|
||||||
*
|
|
||||||
* This can only be called on Windows.
|
* This can only be called on Windows.
|
||||||
|
*
|
||||||
|
* @see IsAtLeastWindows10()
|
||||||
*/
|
*/
|
||||||
textwindows noasan int NtGetVersion(void) {
|
textwindows noasan int NtGetVersion(void) {
|
||||||
return (NtGetPeb()->OSMajorVersion & 0xff) << 8 | NtGetPeb()->OSMinorVersion;
|
return (NtGetPeb()->OSMajorVersion & 0xff) << 8 | NtGetPeb()->OSMinorVersion;
|
||||||
|
|
|
@ -25,16 +25,8 @@
|
||||||
//
|
//
|
||||||
// @return 0 on success, or -1 w/ errno
|
// @return 0 on success, or -1 w/ errno
|
||||||
sched_yield:
|
sched_yield:
|
||||||
push %rbp
|
|
||||||
mov %rsp,%rbp
|
|
||||||
testb IsWindows()
|
|
||||||
jnz 1f
|
|
||||||
|
|
||||||
// UNIX Support
|
|
||||||
mov __NR_sched_yield,%eax
|
|
||||||
syscall
|
|
||||||
jmp 2f
|
|
||||||
|
|
||||||
|
#if SupportsWindows()
|
||||||
// Windows Support
|
// Windows Support
|
||||||
//
|
//
|
||||||
// A value of zero, together with the bAlertable parameter set to
|
// A value of zero, together with the bAlertable parameter set to
|
||||||
|
@ -44,12 +36,34 @@ sched_yield:
|
||||||
// threads ready to run and no user APCs are queued, the function
|
// threads ready to run and no user APCs are queued, the function
|
||||||
// returns immediately, and the thread continues execution.
|
// returns immediately, and the thread continues execution.
|
||||||
// ──Quoth MSDN
|
// ──Quoth MSDN
|
||||||
1: xor %ecx,%ecx
|
testb IsWindows()
|
||||||
|
jz 1f
|
||||||
|
push %rbp
|
||||||
|
mov %rsp,%rbp
|
||||||
|
xor %ecx,%ecx
|
||||||
xor %edx,%edx
|
xor %edx,%edx
|
||||||
ntcall __imp_SleepEx
|
ntcall __imp_SleepEx
|
||||||
xor %eax,%eax
|
xor %eax,%eax
|
||||||
|
pop %rbp
|
||||||
2: pop %rbp
|
|
||||||
ret
|
ret
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if SupportsSystemv()
|
||||||
|
// UNIX Support
|
||||||
|
1: mov __NR_sched_yield,%eax
|
||||||
|
#if SupportsBsd() && SupportsLinux()
|
||||||
|
clc
|
||||||
|
#endif
|
||||||
|
syscall
|
||||||
|
#if SupportsBsd()
|
||||||
|
jc systemfive_errno
|
||||||
|
#endif
|
||||||
|
#if SupportsLinux()
|
||||||
|
cmp $-4095,%rax
|
||||||
|
jae systemfive_error
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
2: ret
|
||||||
.endfn sched_yield,globl
|
.endfn sched_yield,globl
|
||||||
.previous
|
.previous
|
||||||
|
|
|
@ -44,23 +44,28 @@
|
||||||
* 0x003c 0x04 errno
|
* 0x003c 0x04 errno
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
privileged void *__initialize_tls(char tib[hasatleast 64]) {
|
privileged void *__initialize_tls(char tib[64]) {
|
||||||
|
if (tib) {
|
||||||
*(intptr_t *)tib = (intptr_t)tib;
|
*(intptr_t *)tib = (intptr_t)tib;
|
||||||
*(intptr_t *)(tib + 0x08) = 0;
|
*(intptr_t *)(tib + 0x08) = 0;
|
||||||
*(int *)(tib + 0x10) = -1; // exit code
|
*(int *)(tib + 0x10) = -1; // exit code
|
||||||
*(intptr_t *)(tib + 0x30) = (intptr_t)tib;
|
*(intptr_t *)(tib + 0x30) = (intptr_t)tib;
|
||||||
*(int *)(tib + 0x38) = -1; // tid
|
*(int *)(tib + 0x38) = -1; // tid
|
||||||
*(int *)(tib + 0x3c) = __errno;
|
*(int *)(tib + 0x3c) = 0;
|
||||||
|
}
|
||||||
return tib;
|
return tib;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Installs thread information block on main process.
|
* Installs thread information block on main process.
|
||||||
*/
|
*/
|
||||||
privileged void __install_tls(char tib[hasatleast 64]) {
|
privileged void __install_tls(char tib[64]) {
|
||||||
int ax, dx;
|
int ax, dx;
|
||||||
uint64_t magic;
|
uint64_t magic;
|
||||||
unsigned char *p;
|
unsigned char *p;
|
||||||
|
assert(tib);
|
||||||
|
assert(!__tls_enabled);
|
||||||
|
assert(*(int *)(tib + 0x38) != -1);
|
||||||
if (IsWindows()) {
|
if (IsWindows()) {
|
||||||
if (!__tls_index) {
|
if (!__tls_index) {
|
||||||
__tls_index = TlsAlloc();
|
__tls_index = TlsAlloc();
|
||||||
|
|
|
@ -8,8 +8,8 @@ extern bool __threaded;
|
||||||
extern bool __tls_enabled;
|
extern bool __tls_enabled;
|
||||||
extern unsigned __tls_index;
|
extern unsigned __tls_index;
|
||||||
|
|
||||||
void *__initialize_tls(char[hasatleast 64]);
|
void *__initialize_tls(char[64]);
|
||||||
void __install_tls(char[hasatleast 64]);
|
void __install_tls(char[64]);
|
||||||
|
|
||||||
#if defined(__GNUC__) && defined(__x86_64__) && !defined(__STRICT_ANSI__)
|
#if defined(__GNUC__) && defined(__x86_64__) && !defined(__STRICT_ANSI__)
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -4,6 +4,7 @@
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Known versions of the New Technology executive.
|
* Known versions of the New Technology executive.
|
||||||
|
* @see IsAtLeastWindows10()
|
||||||
* @see NtGetVersion()
|
* @see NtGetVersion()
|
||||||
*/
|
*/
|
||||||
#define kNtVersionWindows10 0x0a00
|
#define kNtVersionWindows10 0x0a00
|
||||||
|
|
|
@ -8,16 +8,14 @@ bool IsAtLeastWindows10(void) pureconst;
|
||||||
bool32 GetVersionEx(struct NtOsVersionInfo *lpVersionInformation);
|
bool32 GetVersionEx(struct NtOsVersionInfo *lpVersionInformation);
|
||||||
|
|
||||||
#if defined(__GCC_ASM_FLAG_OUTPUTS__) && !defined(__STRICT_ANSI__)
|
#if defined(__GCC_ASM_FLAG_OUTPUTS__) && !defined(__STRICT_ANSI__)
|
||||||
#define IsAtLeastWindows10() \
|
#define IsAtLeastWindows10() (GetNtMajorVersion() >= 10)
|
||||||
({ \
|
static pureconst inline unsigned char GetNtMajorVersion(void) {
|
||||||
long ReG; \
|
uintptr_t _x;
|
||||||
bool NoTbelow; \
|
asm("mov\t%%gs:96,%q0\r\n"
|
||||||
asm("mov\t%%gs:96,%1\r\n" \
|
"mov\t280(%q0),%b0"
|
||||||
"cmpb\t%2,280(%1)" \
|
: "=q"(_x));
|
||||||
: "=@ccnb"(NoTbelow), "=l"(ReG) \
|
return _x;
|
||||||
: "i"(10)); \
|
}
|
||||||
NoTbelow; \
|
|
||||||
})
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
COSMOPOLITAN_C_END_
|
COSMOPOLITAN_C_END_
|
||||||
|
|
55
libc/runtime/clone-linux.S
Normal file
55
libc/runtime/clone-linux.S
Normal file
|
@ -0,0 +1,55 @@
|
||||||
|
/*-*- mode:unix-assembly; indent-tabs-mode:t; tab-width:8; coding:utf-8 -*-│
|
||||||
|
│vi: set et ft=asm ts=8 tw=8 fenc=utf-8 :vi│
|
||||||
|
╞══════════════════════════════════════════════════════════════════════════════╡
|
||||||
|
│ Copyright 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/macros.internal.h"
|
||||||
|
|
||||||
|
// Invokes clone() system call on GNU/Systemd.
|
||||||
|
//
|
||||||
|
// @param rdi is flags
|
||||||
|
// @param rsi is top of stack
|
||||||
|
// @param rdx is ptid
|
||||||
|
// @param rcx is ctid
|
||||||
|
// @param r8 is tls
|
||||||
|
// @param r9 is func
|
||||||
|
// @param 8(rsp) is arg
|
||||||
|
// @return tid of child on success, or -1 w/ errno
|
||||||
|
sys_clone_linux:
|
||||||
|
push %rbp
|
||||||
|
mov %rsp,%rbp
|
||||||
|
.profilable
|
||||||
|
push %rbx
|
||||||
|
mov %rcx,%r10
|
||||||
|
mov 16(%rbp),%rbx
|
||||||
|
mov $56,%eax # __NR_clone
|
||||||
|
syscall
|
||||||
|
test %rax,%rax
|
||||||
|
jz 2f
|
||||||
|
cmp $-4095,%rax
|
||||||
|
jae 1f
|
||||||
|
0: pop %rbx
|
||||||
|
pop %rbp
|
||||||
|
ret
|
||||||
|
1: call systemfive_error
|
||||||
|
jmp 0b
|
||||||
|
2: xor %ebp,%ebp # child thread
|
||||||
|
mov %rbx,%rdi # arg
|
||||||
|
call *%r9 # func(arg)
|
||||||
|
xchg %eax,%edi # func(arg) → exitcode
|
||||||
|
mov $60,%eax # __NR_exit(exitcode)
|
||||||
|
syscall
|
||||||
|
.endfn sys_clone_linux,globl,hidden
|
|
@ -419,40 +419,8 @@ static int CloneNetbsd(int (*func)(void *), char *stk, size_t stksz, int flags,
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
// GNU/SYSTEMD
|
// GNU/SYSTEMD
|
||||||
|
|
||||||
int CloneLinux(int (*func)(void *), char *stk, size_t stksz, int flags,
|
int sys_clone_linux(int flags, char *stk, int *ptid, int *ctid, void *tls,
|
||||||
void *arg, int *ptid, void *tls, size_t tlssz, int *ctid) {
|
int (*func)(void *), void *arg);
|
||||||
#ifdef __chibicc__
|
|
||||||
return -1; // TODO
|
|
||||||
#else
|
|
||||||
int ax;
|
|
||||||
intptr_t *stack = (intptr_t *)(stk + stksz);
|
|
||||||
*--stack = (intptr_t)arg;
|
|
||||||
// %rax = syscall(%rax = __NR_clone,
|
|
||||||
// %rdi = flags,
|
|
||||||
// %rsi = child_stack,
|
|
||||||
// %rdx = parent_tidptr,
|
|
||||||
// %r10 = child_tidptr,
|
|
||||||
// %r8 = new_tls);
|
|
||||||
asm volatile("mov\t%4,%%r10\n\t" // ctid
|
|
||||||
"mov\t%5,%%r8\n\t" // tls
|
|
||||||
"mov\t%6,%%r9\n\t" // func
|
|
||||||
"syscall\n\t"
|
|
||||||
"test\t%0,%0\n\t"
|
|
||||||
"jnz\t1f\n\t"
|
|
||||||
"xor\t%%ebp,%%ebp\n\t"
|
|
||||||
"pop\t%%rdi\n\t" // arg
|
|
||||||
"call\t*%%r9\n\t" // func
|
|
||||||
"xchg\t%%eax,%%edi\n\t"
|
|
||||||
"mov\t$0x3c,%%eax\n\t"
|
|
||||||
"syscall\n1:"
|
|
||||||
: "=a"(ax)
|
|
||||||
: "0"(__NR_clone_linux), "D"(flags), "S"(stack), "g"(ctid),
|
|
||||||
"g"(tls), "g"(func), "d"(ptid)
|
|
||||||
: "rcx", "r8", "r9", "r10", "r11", "memory");
|
|
||||||
if (ax > -4096u) errno = -ax, ax = -1;
|
|
||||||
return ax;
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
// COSMOPOLITAN
|
// COSMOPOLITAN
|
||||||
|
@ -542,13 +510,23 @@ int clone(int (*func)(void *), void *stk, size_t stksz, int flags, void *arg,
|
||||||
int rc;
|
int rc;
|
||||||
struct CloneArgs *wt;
|
struct CloneArgs *wt;
|
||||||
|
|
||||||
if (flags & CLONE_THREAD) {
|
// transition program to threaded state
|
||||||
__threaded = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
if ((flags & CLONE_SETTLS) && !__tls_enabled) {
|
if ((flags & CLONE_SETTLS) && !__tls_enabled) {
|
||||||
|
if (~flags & CLONE_THREAD) {
|
||||||
|
STRACE("clone() tls w/o thread");
|
||||||
|
return einval();
|
||||||
|
}
|
||||||
|
if (__threaded) {
|
||||||
|
STRACE("clone() tls/non-tls mixed order");
|
||||||
|
return einval();
|
||||||
|
}
|
||||||
__initialize_tls(tibdefault);
|
__initialize_tls(tibdefault);
|
||||||
|
*(int *)((char *)tibdefault + 0x38) = gettid();
|
||||||
|
*(int *)((char *)tibdefault + 0x3c) = __errno;
|
||||||
__install_tls(tibdefault);
|
__install_tls(tibdefault);
|
||||||
|
__threaded = true;
|
||||||
|
} else if (flags & CLONE_THREAD) {
|
||||||
|
__threaded = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (IsAsan() &&
|
if (IsAsan() &&
|
||||||
|
@ -566,7 +544,8 @@ int clone(int (*func)(void *), void *stk, size_t stksz, int flags, void *arg,
|
||||||
((flags & CLONE_SETTLS) && (tlssz < 64 || (tlssz & 7))))) {
|
((flags & CLONE_SETTLS) && (tlssz < 64 || (tlssz & 7))))) {
|
||||||
rc = einval();
|
rc = einval();
|
||||||
} else if (IsLinux()) {
|
} else if (IsLinux()) {
|
||||||
rc = CloneLinux(func, stk, stksz, flags, arg, ptid, tls, tlssz, ctid);
|
rc =
|
||||||
|
sys_clone_linux(flags, (char *)stk + stksz, ptid, ctid, tls, func, arg);
|
||||||
} else if (!IsTiny() &&
|
} else if (!IsTiny() &&
|
||||||
(flags & ~(CLONE_SETTLS | CLONE_PARENT_SETTID |
|
(flags & ~(CLONE_SETTLS | CLONE_PARENT_SETTID |
|
||||||
CLONE_CHILD_SETTID | CLONE_CHILD_CLEARTID)) !=
|
CLONE_CHILD_SETTID | CLONE_CHILD_CLEARTID)) !=
|
||||||
|
|
|
@ -26,7 +26,9 @@
|
||||||
* @assume stack addresses are always greater than heap addresses
|
* @assume stack addresses are always greater than heap addresses
|
||||||
* @assume stack memory isn't stored beneath %rsp (-mno-red-zone)
|
* @assume stack memory isn't stored beneath %rsp (-mno-red-zone)
|
||||||
*/
|
*/
|
||||||
noasan bool _isheap(void *p) {
|
optimizesize noasan bool _isheap(void *p) {
|
||||||
return kAutomapStart <= (intptr_t)p &&
|
intptr_t x, y;
|
||||||
(intptr_t)p < kAutomapStart + kAutomapSize;
|
x = kAutomapStart;
|
||||||
|
y = x + kAutomapSize;
|
||||||
|
return x <= (intptr_t)p && (intptr_t)p < y;
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,8 +4,7 @@
|
||||||
#include "libc/bits/midpoint.h"
|
#include "libc/bits/midpoint.h"
|
||||||
#include "libc/dce.h"
|
#include "libc/dce.h"
|
||||||
#include "libc/macros.internal.h"
|
#include "libc/macros.internal.h"
|
||||||
#include "libc/nt/enum/version.h"
|
#include "libc/nt/version.h"
|
||||||
#include "libc/runtime/runtime.h"
|
|
||||||
#include "libc/runtime/stack.h"
|
#include "libc/runtime/stack.h"
|
||||||
#include "libc/sysv/consts/ss.h"
|
#include "libc/sysv/consts/ss.h"
|
||||||
#if !(__ASSEMBLER__ + __LINKER__ + 0)
|
#if !(__ASSEMBLER__ + __LINKER__ + 0)
|
||||||
|
@ -29,7 +28,7 @@ COSMOPOLITAN_C_START_
|
||||||
ROUNDUP(VSPACE / FRAMESIZE * (intptr_t)sizeof(struct MemoryInterval), \
|
ROUNDUP(VSPACE / FRAMESIZE * (intptr_t)sizeof(struct MemoryInterval), \
|
||||||
FRAMESIZE)
|
FRAMESIZE)
|
||||||
#define _kMem(NORMAL, WIN7) \
|
#define _kMem(NORMAL, WIN7) \
|
||||||
(!(IsWindows() && NtGetVersion() < kNtVersionWindows10) ? NORMAL : WIN7)
|
(!IsWindows() || IsAtLeastWindows10() ? NORMAL : WIN7)
|
||||||
|
|
||||||
struct MemoryInterval {
|
struct MemoryInterval {
|
||||||
int x;
|
int x;
|
||||||
|
|
|
@ -16,59 +16,11 @@
|
||||||
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
||||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||||
#include "libc/bits/pushpop.h"
|
#include "libc/intrin/kprintf.h"
|
||||||
#include "libc/nt/enum/version.h"
|
|
||||||
#include "libc/nt/runtime.h"
|
|
||||||
#include "libc/runtime/internal.h"
|
#include "libc/runtime/internal.h"
|
||||||
#include "libc/sysv/consts/fileno.h"
|
|
||||||
#include "libc/sysv/consts/nr.h"
|
|
||||||
|
|
||||||
#define STACK_SMASH_MESSAGE "stack smashed\n"
|
privileged noasan noinstrument void __stack_chk_fail(void) {
|
||||||
|
kprintf("stack smashed\n");
|
||||||
/**
|
__restorewintty();
|
||||||
* Aborts program under enemy fire to avoid being taken alive.
|
_Exit(207);
|
||||||
*/
|
|
||||||
privileged noasan void __stack_chk_fail(void) {
|
|
||||||
size_t len;
|
|
||||||
const char *msg;
|
|
||||||
int64_t ax, cx, si;
|
|
||||||
if (!IsWindows()) {
|
|
||||||
msg = STACK_SMASH_MESSAGE;
|
|
||||||
len = pushpop(sizeof(STACK_SMASH_MESSAGE) - 1);
|
|
||||||
if (!IsMetal()) {
|
|
||||||
asm volatile("syscall"
|
|
||||||
: "=a"(ax)
|
|
||||||
: "0"(__NR_write), "D"(pushpop(STDERR_FILENO)), "S"(msg),
|
|
||||||
"d"(len)
|
|
||||||
: "rcx", "r11", "cc", "memory");
|
|
||||||
asm volatile("syscall"
|
|
||||||
: "=a"(ax)
|
|
||||||
: "0"(__NR_exit_group), "D"(pushpop(23))
|
|
||||||
: "rcx", "r11", "cc", "memory");
|
|
||||||
}
|
|
||||||
asm volatile("rep outsb"
|
|
||||||
: "=S"(si), "=c"(cx)
|
|
||||||
: "0"(msg), "1"(len), "d"(0x3F8 /* COM1 */)
|
|
||||||
: "memory");
|
|
||||||
asm("push\t$0\n\t"
|
|
||||||
"push\t$0\n\t"
|
|
||||||
"cli\n\t"
|
|
||||||
"lidt\t(%rsp)");
|
|
||||||
for (;;) asm("ud2");
|
|
||||||
}
|
|
||||||
if (NtGetVersion() < kNtVersionFuture) {
|
|
||||||
do {
|
|
||||||
asm volatile("syscall"
|
|
||||||
: "=a"(ax), "=c"(cx)
|
|
||||||
: "0"(NtGetVersion() < kNtVersionWindows8 ? 0x0029
|
|
||||||
: NtGetVersion() < kNtVersionWindows81 ? 0x002a
|
|
||||||
: NtGetVersion() < kNtVersionWindows10 ? 0x002b
|
|
||||||
: 0x002c),
|
|
||||||
"1"(pushpop(-1L)), "d"(42)
|
|
||||||
: "r11", "cc", "memory");
|
|
||||||
} while (!ax);
|
|
||||||
}
|
|
||||||
for (;;) {
|
|
||||||
TerminateProcess(GetCurrentProcess(), 42);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -39,6 +39,7 @@ int fclose(FILE *f) {
|
||||||
if (!f) return 0;
|
if (!f) return 0;
|
||||||
__fflush_unregister(f);
|
__fflush_unregister(f);
|
||||||
fflush(f);
|
fflush(f);
|
||||||
|
free_s(&f->getln);
|
||||||
if (!f->nofree) {
|
if (!f->nofree) {
|
||||||
free_s(&f->buf);
|
free_s(&f->buf);
|
||||||
}
|
}
|
||||||
|
|
|
@ -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=8 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 2022 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,83 +16,19 @@
|
||||||
│ 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/arraylist.internal.h"
|
|
||||||
#include "libc/bits/bits.h"
|
|
||||||
#include "libc/bits/pushpop.h"
|
|
||||||
#include "libc/calls/calls.h"
|
|
||||||
#include "libc/errno.h"
|
|
||||||
#include "libc/intrin/spinlock.h"
|
|
||||||
#include "libc/macros.internal.h"
|
|
||||||
#include "libc/mem/mem.h"
|
|
||||||
#include "libc/runtime/runtime.h"
|
|
||||||
#include "libc/stdio/fflush.internal.h"
|
|
||||||
#include "libc/stdio/internal.h"
|
|
||||||
#include "libc/stdio/stdio.h"
|
#include "libc/stdio/stdio.h"
|
||||||
#include "libc/sysv/consts/o.h"
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Blocks until data from stream buffer is written out.
|
* Blocks until data from stream buffer is written out.
|
||||||
*
|
*
|
||||||
* @param f is the stream handle, or 0 for all streams
|
* @param f is the stream handle, or 0 for all streams
|
||||||
* @return is 0 on success or -1 on error
|
* @return is 0 on success or -1 on error
|
||||||
|
* @threadsafe
|
||||||
*/
|
*/
|
||||||
int fflush_unlocked(FILE *f) {
|
int fflush(FILE *f) {
|
||||||
int rc = 0;
|
|
||||||
size_t i;
|
|
||||||
if (!f) {
|
|
||||||
_spinlock(&__fflush.lock);
|
|
||||||
for (i = __fflush.handles.i; i; --i) {
|
|
||||||
if ((f = __fflush.handles.p[i - 1])) {
|
|
||||||
if (fflush(f) == -1) {
|
|
||||||
rc = -1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
_spunlock(&__fflush.lock);
|
|
||||||
} else if (f->fd != -1) {
|
|
||||||
if (__fflush_impl(f) == -1) {
|
|
||||||
rc = -1;
|
|
||||||
}
|
|
||||||
} else if (f->beg && f->beg < f->size) {
|
|
||||||
f->buf[f->beg] = 0;
|
|
||||||
}
|
|
||||||
return rc;
|
|
||||||
}
|
|
||||||
|
|
||||||
textstartup int __fflush_register(FILE *f) {
|
|
||||||
int rc;
|
int rc;
|
||||||
size_t i;
|
if (f) flockfile(f);
|
||||||
struct StdioFlush *sf;
|
rc = fflush_unlocked(f);
|
||||||
_spinlock(&__fflush.lock);
|
if (f) funlockfile(f);
|
||||||
sf = &__fflush;
|
|
||||||
if (!sf->handles.p) {
|
|
||||||
sf->handles.p = sf->handles_initmem;
|
|
||||||
pushmov(&sf->handles.n, ARRAYLEN(sf->handles_initmem));
|
|
||||||
__cxa_atexit(fflush_unlocked, 0, 0);
|
|
||||||
}
|
|
||||||
for (i = sf->handles.i; i; --i) {
|
|
||||||
if (!sf->handles.p[i - 1]) {
|
|
||||||
sf->handles.p[i - 1] = f;
|
|
||||||
_spunlock(&__fflush.lock);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
rc = append(&sf->handles, &f);
|
|
||||||
_spunlock(&__fflush.lock);
|
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
void __fflush_unregister(FILE *f) {
|
|
||||||
size_t i;
|
|
||||||
struct StdioFlush *sf;
|
|
||||||
_spinlock(&__fflush.lock);
|
|
||||||
sf = &__fflush;
|
|
||||||
sf = pushpop(sf);
|
|
||||||
for (i = sf->handles.i; i; --i) {
|
|
||||||
if (sf->handles.p[i - 1] == f) {
|
|
||||||
pushmov(&sf->handles.p[i - 1], 0);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
_spunlock(&__fflush.lock);
|
|
||||||
}
|
|
||||||
|
|
98
libc/stdio/fflush_unlocked.c
Normal file
98
libc/stdio/fflush_unlocked.c
Normal file
|
@ -0,0 +1,98 @@
|
||||||
|
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
|
||||||
|
│vi: set net ft=c ts=8 sts=2 sw=2 fenc=utf-8 :vi│
|
||||||
|
╞══════════════════════════════════════════════════════════════════════════════╡
|
||||||
|
│ Copyright 2020 Justine Alexandra Roberts Tunney │
|
||||||
|
│ │
|
||||||
|
│ Permission to use, copy, modify, and/or distribute this software for │
|
||||||
|
│ any purpose with or without fee is hereby granted, provided that the │
|
||||||
|
│ above copyright notice and this permission notice appear in all copies. │
|
||||||
|
│ │
|
||||||
|
│ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL │
|
||||||
|
│ WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED │
|
||||||
|
│ WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE │
|
||||||
|
│ AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL │
|
||||||
|
│ DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR │
|
||||||
|
│ PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER │
|
||||||
|
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
||||||
|
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||||
|
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||||
|
#include "libc/alg/arraylist.internal.h"
|
||||||
|
#include "libc/bits/bits.h"
|
||||||
|
#include "libc/bits/pushpop.h"
|
||||||
|
#include "libc/calls/calls.h"
|
||||||
|
#include "libc/errno.h"
|
||||||
|
#include "libc/intrin/spinlock.h"
|
||||||
|
#include "libc/macros.internal.h"
|
||||||
|
#include "libc/mem/mem.h"
|
||||||
|
#include "libc/runtime/runtime.h"
|
||||||
|
#include "libc/stdio/fflush.internal.h"
|
||||||
|
#include "libc/stdio/internal.h"
|
||||||
|
#include "libc/stdio/stdio.h"
|
||||||
|
#include "libc/sysv/consts/o.h"
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Blocks until data from stream buffer is written out.
|
||||||
|
*
|
||||||
|
* @param f is the stream handle, or 0 for all streams
|
||||||
|
* @return is 0 on success or -1 on error
|
||||||
|
*/
|
||||||
|
int fflush_unlocked(FILE *f) {
|
||||||
|
int rc = 0;
|
||||||
|
size_t i;
|
||||||
|
if (!f) {
|
||||||
|
_spinlock(&__fflush.lock);
|
||||||
|
for (i = __fflush.handles.i; i; --i) {
|
||||||
|
if ((f = __fflush.handles.p[i - 1])) {
|
||||||
|
if (fflush(f) == -1) {
|
||||||
|
rc = -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_spunlock(&__fflush.lock);
|
||||||
|
} else if (f->fd != -1) {
|
||||||
|
if (__fflush_impl(f) == -1) {
|
||||||
|
rc = -1;
|
||||||
|
}
|
||||||
|
} else if (f->beg && f->beg < f->size) {
|
||||||
|
f->buf[f->beg] = 0;
|
||||||
|
}
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
textstartup int __fflush_register(FILE *f) {
|
||||||
|
int rc;
|
||||||
|
size_t i;
|
||||||
|
struct StdioFlush *sf;
|
||||||
|
_spinlock(&__fflush.lock);
|
||||||
|
sf = &__fflush;
|
||||||
|
if (!sf->handles.p) {
|
||||||
|
sf->handles.p = sf->handles_initmem;
|
||||||
|
pushmov(&sf->handles.n, ARRAYLEN(sf->handles_initmem));
|
||||||
|
__cxa_atexit(fflush_unlocked, 0, 0);
|
||||||
|
}
|
||||||
|
for (i = sf->handles.i; i; --i) {
|
||||||
|
if (!sf->handles.p[i - 1]) {
|
||||||
|
sf->handles.p[i - 1] = f;
|
||||||
|
_spunlock(&__fflush.lock);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
rc = append(&sf->handles, &f);
|
||||||
|
_spunlock(&__fflush.lock);
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
void __fflush_unregister(FILE *f) {
|
||||||
|
size_t i;
|
||||||
|
struct StdioFlush *sf;
|
||||||
|
_spinlock(&__fflush.lock);
|
||||||
|
sf = &__fflush;
|
||||||
|
sf = pushpop(sf);
|
||||||
|
for (i = sf->handles.i; i; --i) {
|
||||||
|
if (sf->handles.p[i - 1] == f) {
|
||||||
|
pushmov(&sf->handles.p[i - 1], 0);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_spunlock(&__fflush.lock);
|
||||||
|
}
|
|
@ -18,12 +18,14 @@
|
||||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||||
#include "libc/calls/calls.h"
|
#include "libc/calls/calls.h"
|
||||||
#include "libc/errno.h"
|
#include "libc/errno.h"
|
||||||
|
#include "libc/runtime/runtime.h"
|
||||||
#include "libc/stdio/internal.h"
|
#include "libc/stdio/internal.h"
|
||||||
#include "libc/sysv/consts/o.h"
|
#include "libc/sysv/consts/o.h"
|
||||||
|
|
||||||
int __fflush_impl(FILE *f) {
|
int __fflush_impl(FILE *f) {
|
||||||
size_t i;
|
size_t i;
|
||||||
ssize_t rc;
|
ssize_t rc;
|
||||||
|
free_s(&f->getln);
|
||||||
if (f->beg && !f->end && (f->iomode & O_ACCMODE) != O_RDONLY) {
|
if (f->beg && !f->end && (f->iomode & O_ACCMODE) != O_RDONLY) {
|
||||||
for (i = 0; i < f->beg; i += rc) {
|
for (i = 0; i < f->beg; i += rc) {
|
||||||
if ((rc = write(f->fd, f->buf + i, f->beg - i)) == -1) {
|
if ((rc = write(f->fd, f->buf + i, f->beg - i)) == -1) {
|
||||||
|
|
|
@ -18,13 +18,35 @@
|
||||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||||
#include "libc/stdio/stdio.h"
|
#include "libc/stdio/stdio.h"
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retrieves line from stream, e.g.
|
||||||
|
*
|
||||||
|
* char *line;
|
||||||
|
* while ((line = _chomp(fgetln(stdin, 0)))) {
|
||||||
|
* printf("%s\n", line);
|
||||||
|
* }
|
||||||
|
*
|
||||||
|
* The returned memory is owned by the stream. It'll be reused when
|
||||||
|
* fgetln() is called again. It's free()'d upon fclose() / fflush()
|
||||||
|
*
|
||||||
|
* @param stream specifies non-null open input stream
|
||||||
|
* @param len optionally receives byte length of line
|
||||||
|
* @return nul-terminated line string, including the `\n` character
|
||||||
|
* unless a line happened before EOF without `\n`, otherwise it
|
||||||
|
* returns `NULL` and feof() and ferror() can examine the state
|
||||||
|
* @see getdelim()
|
||||||
|
*/
|
||||||
char *fgetln(FILE *stream, size_t *len) {
|
char *fgetln(FILE *stream, size_t *len) {
|
||||||
|
char *res;
|
||||||
ssize_t rc;
|
ssize_t rc;
|
||||||
size_t n = 0;
|
size_t n = 0;
|
||||||
if ((rc = getdelim(&stream->getln, &n, '\n', stream)) > 0) {
|
flockfile(stream);
|
||||||
*len = rc;
|
if ((rc = getdelim_unlocked(&stream->getln, &n, '\n', stream)) > 0) {
|
||||||
return stream->getln;
|
if (len) *len = rc;
|
||||||
|
res = stream->getln;
|
||||||
} else {
|
} else {
|
||||||
return 0;
|
res = 0;
|
||||||
}
|
}
|
||||||
|
funlockfile(stream);
|
||||||
|
return res;
|
||||||
}
|
}
|
||||||
|
|
|
@ -28,11 +28,11 @@
|
||||||
void flockfile(FILE *f) {
|
void flockfile(FILE *f) {
|
||||||
int me, owner;
|
int me, owner;
|
||||||
unsigned tries;
|
unsigned tries;
|
||||||
if (!__threaded) return;
|
if (__threaded) {
|
||||||
for (tries = 0, me = gettid();;) {
|
for (tries = 0, me = gettid();;) {
|
||||||
owner = 0;
|
owner = 0;
|
||||||
if (_lockcmpxchgp(&f->lock, &owner, me) || owner == me) {
|
if (_lockcmpxchgp(&f->lock, &owner, me) || owner == me) {
|
||||||
return;
|
break;
|
||||||
}
|
}
|
||||||
if (++tries & 7) {
|
if (++tries & 7) {
|
||||||
__builtin_ia32_pause();
|
__builtin_ia32_pause();
|
||||||
|
@ -40,4 +40,6 @@ void flockfile(FILE *f) {
|
||||||
sched_yield();
|
sched_yield();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
++f->reent;
|
||||||
}
|
}
|
||||||
|
|
|
@ -29,7 +29,7 @@ int fputc_unlocked(int c, FILE *f) {
|
||||||
unsigned char b;
|
unsigned char b;
|
||||||
if (c != '\n' && f->beg < f->size && f->bufmode != _IONBF) {
|
if (c != '\n' && f->beg < f->size && f->bufmode != _IONBF) {
|
||||||
f->buf[f->beg++] = c;
|
f->buf[f->beg++] = c;
|
||||||
return c & 0xff;
|
return c & 255;
|
||||||
} else {
|
} else {
|
||||||
b = c;
|
b = c;
|
||||||
if (!fwrite_unlocked(&b, 1, 1, f)) return -1;
|
if (!fwrite_unlocked(&b, 1, 1, f)) return -1;
|
||||||
|
|
|
@ -34,5 +34,8 @@ int ftrylockfile(FILE *f) {
|
||||||
owner = 0;
|
owner = 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (!owner) {
|
||||||
|
++f->reent;
|
||||||
|
}
|
||||||
return owner;
|
return owner;
|
||||||
}
|
}
|
||||||
|
|
|
@ -16,12 +16,24 @@
|
||||||
│ 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/intrin/spinlock.h"
|
#include "libc/assert.h"
|
||||||
|
#include "libc/calls/calls.h"
|
||||||
|
#include "libc/nexgen32e/threaded.h"
|
||||||
#include "libc/stdio/stdio.h"
|
#include "libc/stdio/stdio.h"
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Releases lock on stdio object.
|
* Releases lock on stdio object.
|
||||||
*/
|
*/
|
||||||
void funlockfile(FILE *f) {
|
void funlockfile(FILE *f) {
|
||||||
_spunlock(&f->lock);
|
int owner;
|
||||||
|
bool shouldunlock;
|
||||||
|
assert(f->reent > 0);
|
||||||
|
shouldunlock = --f->reent <= 0;
|
||||||
|
if (__threaded) {
|
||||||
|
assert(f->lock == gettid());
|
||||||
|
if (shouldunlock) {
|
||||||
|
owner = 0;
|
||||||
|
__atomic_store(&f->lock, &owner, __ATOMIC_RELAXED);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -16,64 +16,18 @@
|
||||||
│ 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/assert.h"
|
|
||||||
#include "libc/calls/calls.h"
|
|
||||||
#include "libc/errno.h"
|
|
||||||
#include "libc/macros.internal.h"
|
|
||||||
#include "libc/mem/mem.h"
|
|
||||||
#include "libc/runtime/runtime.h"
|
|
||||||
#include "libc/stdio/stdio.h"
|
#include "libc/stdio/stdio.h"
|
||||||
#include "libc/str/str.h"
|
|
||||||
#include "libc/sysv/consts/o.h"
|
|
||||||
|
|
||||||
static ssize_t getdelim_unlocked(char **s, size_t *n, int delim, FILE *f) {
|
|
||||||
char *p;
|
|
||||||
ssize_t rc;
|
|
||||||
size_t i, m;
|
|
||||||
if ((f->iomode & O_ACCMODE) == O_WRONLY) {
|
|
||||||
f->state = errno = EBADF;
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
if (f->beg > f->end) {
|
|
||||||
f->state = errno = EINVAL;
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
if (!*s) *n = 0;
|
|
||||||
for (i = 0;; i += m) {
|
|
||||||
m = f->end - f->beg;
|
|
||||||
if ((p = memchr(f->buf + f->beg, delim, m))) m = p + 1 - (f->buf + f->beg);
|
|
||||||
if (i + m + 1 > *n) {
|
|
||||||
*n = i + m + 1;
|
|
||||||
*s = realloc(*s, *n);
|
|
||||||
if (!*s) {
|
|
||||||
abort();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
memcpy(*s + i, f->buf + f->beg, m);
|
|
||||||
(*s)[i + m] = '\0';
|
|
||||||
if ((f->beg += m) == f->end) f->beg = f->end = 0;
|
|
||||||
if (p) {
|
|
||||||
return i + m;
|
|
||||||
} else if (f->fd == -1) {
|
|
||||||
break;
|
|
||||||
} else if ((rc = read(f->fd, f->buf, f->size)) != -1) {
|
|
||||||
if (!rc) break;
|
|
||||||
f->end = rc;
|
|
||||||
} else if (errno != EINTR) {
|
|
||||||
f->state = errno;
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
f->state = -1;
|
|
||||||
if (i + m) {
|
|
||||||
return i + m;
|
|
||||||
} else {
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Reads string from stream.
|
* Reads string from stream, e.g.
|
||||||
|
*
|
||||||
|
* char *line = NULL;
|
||||||
|
* size_t linesize = 0;
|
||||||
|
* while (getdelim(&line, &linesize, '\n', stdin) > 0) {
|
||||||
|
* _chomp(line);
|
||||||
|
* printf("%s\n", line);
|
||||||
|
* }
|
||||||
|
* free(line);
|
||||||
*
|
*
|
||||||
* @param s is the caller's buffer (in/out) which is extended or
|
* @param s is the caller's buffer (in/out) which is extended or
|
||||||
* allocated automatically, also NUL-terminated is guaranteed
|
* allocated automatically, also NUL-terminated is guaranteed
|
||||||
|
@ -81,8 +35,9 @@ static ssize_t getdelim_unlocked(char **s, size_t *n, int delim, FILE *f) {
|
||||||
* @param delim is the stop char (and NUL is implicitly too)
|
* @param delim is the stop char (and NUL is implicitly too)
|
||||||
* @return number of bytes read >0, including delim, excluding NUL,
|
* @return number of bytes read >0, including delim, excluding NUL,
|
||||||
* or -1 w/ errno on EOF or error; see ferror() and feof()
|
* or -1 w/ errno on EOF or error; see ferror() and feof()
|
||||||
* @note this function can't punt EINTR to caller
|
* @note this function will ignore EINTR if it occurs mid-line
|
||||||
* @see getline(), _chomp(), gettok_r()
|
* @raises EBADF if stream isn't open for reading
|
||||||
|
* @see fgetln(), getline(), _chomp(), gettok_r()
|
||||||
*/
|
*/
|
||||||
ssize_t getdelim(char **s, size_t *n, int delim, FILE *f) {
|
ssize_t getdelim(char **s, size_t *n, int delim, FILE *f) {
|
||||||
ssize_t rc;
|
ssize_t rc;
|
||||||
|
|
81
libc/stdio/getdelim_unlocked.c
Normal file
81
libc/stdio/getdelim_unlocked.c
Normal file
|
@ -0,0 +1,81 @@
|
||||||
|
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
|
||||||
|
│vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi│
|
||||||
|
╞══════════════════════════════════════════════════════════════════════════════╡
|
||||||
|
│ Copyright 2022 Justine Alexandra Roberts Tunney │
|
||||||
|
│ │
|
||||||
|
│ Permission to use, copy, modify, and/or distribute this software for │
|
||||||
|
│ any purpose with or without fee is hereby granted, provided that the │
|
||||||
|
│ above copyright notice and this permission notice appear in all copies. │
|
||||||
|
│ │
|
||||||
|
│ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL │
|
||||||
|
│ WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED │
|
||||||
|
│ WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE │
|
||||||
|
│ AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL │
|
||||||
|
│ DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR │
|
||||||
|
│ PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER │
|
||||||
|
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
||||||
|
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||||
|
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||||
|
#include "libc/calls/calls.h"
|
||||||
|
#include "libc/errno.h"
|
||||||
|
#include "libc/stdio/stdio.h"
|
||||||
|
#include "libc/str/str.h"
|
||||||
|
#include "libc/sysv/consts/o.h"
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reads string from unlocked stream.
|
||||||
|
* @see getdelim() for documentation
|
||||||
|
*/
|
||||||
|
ssize_t getdelim_unlocked(char **s, size_t *n, int delim, FILE *f) {
|
||||||
|
ssize_t rc;
|
||||||
|
char *p, *s2;
|
||||||
|
size_t i, m, n2;
|
||||||
|
if ((f->iomode & O_ACCMODE) == O_WRONLY) {
|
||||||
|
f->state = errno = EBADF;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
if (f->beg > f->end) {
|
||||||
|
f->state = errno = EINVAL;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
if (!*s) *n = 0;
|
||||||
|
for (i = 0;; i += m) {
|
||||||
|
m = f->end - f->beg;
|
||||||
|
if ((p = memchr(f->buf + f->beg, delim, m))) {
|
||||||
|
m = p + 1 - (f->buf + f->beg);
|
||||||
|
}
|
||||||
|
if (i + m + 1 > *n) {
|
||||||
|
n2 = i + m + 1;
|
||||||
|
s2 = realloc(*s, n2);
|
||||||
|
if (s2) {
|
||||||
|
*s = s2;
|
||||||
|
*n = n2;
|
||||||
|
} else {
|
||||||
|
f->state = errno;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
memcpy(*s + i, f->buf + f->beg, m);
|
||||||
|
(*s)[i + m] = '\0';
|
||||||
|
if ((f->beg += m) == f->end) {
|
||||||
|
f->beg = f->end = 0;
|
||||||
|
}
|
||||||
|
if (p) {
|
||||||
|
return i + m;
|
||||||
|
} else if (f->fd == -1) {
|
||||||
|
break;
|
||||||
|
} else if ((rc = read(f->fd, f->buf, f->size)) != -1) {
|
||||||
|
if (!rc) break;
|
||||||
|
f->end = rc;
|
||||||
|
} else if (errno != EINTR) {
|
||||||
|
f->state = errno;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
f->state = -1;
|
||||||
|
if (i + m) {
|
||||||
|
return i + m;
|
||||||
|
} else {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
}
|
|
@ -19,7 +19,15 @@
|
||||||
#include "libc/stdio/stdio.h"
|
#include "libc/stdio/stdio.h"
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Reads line from stream.
|
* Reads line from stream, e.g.
|
||||||
|
*
|
||||||
|
* char *line = NULL;
|
||||||
|
* size_t linesize = 0;
|
||||||
|
* while (getline(&line, &linesize, stdin) > 0) {
|
||||||
|
* _chomp(line);
|
||||||
|
* printf("%s\n", line);
|
||||||
|
* }
|
||||||
|
* free(line);
|
||||||
*
|
*
|
||||||
* This function delegates to getdelim(), which provides further
|
* This function delegates to getdelim(), which provides further
|
||||||
* documentation. Concerning lines, please note the \n or \r\n are
|
* documentation. Concerning lines, please note the \n or \r\n are
|
||||||
|
@ -30,7 +38,7 @@
|
||||||
* NUL-termination is guaranteed FTMP
|
* NUL-termination is guaranteed FTMP
|
||||||
* @return number of bytes read, including delim, excluding NUL, or -1
|
* @return number of bytes read, including delim, excluding NUL, or -1
|
||||||
* w/ errno on EOF or error; see ferror() and feof()
|
* w/ errno on EOF or error; see ferror() and feof()
|
||||||
* @see xgetline(), getdelim(), gettok_r()
|
* @see fgetln(), xgetline(), getdelim(), gettok_r()
|
||||||
*/
|
*/
|
||||||
ssize_t getline(char **line, size_t *n, FILE *f) {
|
ssize_t getline(char **line, size_t *n, FILE *f) {
|
||||||
return getdelim(line, n, '\n', f);
|
return getdelim(line, n, '\n', f);
|
||||||
|
|
|
@ -25,7 +25,8 @@ typedef struct FILE {
|
||||||
uint32_t nofree; /* 0x24 */
|
uint32_t nofree; /* 0x24 */
|
||||||
int pid; /* 0x28 */
|
int pid; /* 0x28 */
|
||||||
int lock; /* 0x2c */
|
int lock; /* 0x2c */
|
||||||
char *getln; /* 0x30 */
|
int reent; /* 0x30 */
|
||||||
|
char *getln; /* 0x38 */
|
||||||
} FILE;
|
} FILE;
|
||||||
|
|
||||||
extern FILE *stdin;
|
extern FILE *stdin;
|
||||||
|
@ -39,6 +40,7 @@ int getc(FILE *) paramsnonnull();
|
||||||
int putc(int, FILE *) paramsnonnull();
|
int putc(int, FILE *) paramsnonnull();
|
||||||
int fflush(FILE *);
|
int fflush(FILE *);
|
||||||
int fgetc(FILE *) paramsnonnull();
|
int fgetc(FILE *) paramsnonnull();
|
||||||
|
char *fgetln(FILE *, size_t *) paramsnonnull((1));
|
||||||
int ungetc(int, FILE *) paramsnonnull();
|
int ungetc(int, FILE *) paramsnonnull();
|
||||||
int fileno(FILE *) paramsnonnull() nosideeffect;
|
int fileno(FILE *) paramsnonnull() nosideeffect;
|
||||||
int fputc(int, FILE *) paramsnonnull();
|
int fputc(int, FILE *) paramsnonnull();
|
||||||
|
@ -120,9 +122,9 @@ int fwide(FILE *, int);
|
||||||
│ cosmopolitan § standard i/o » without mutexes ─╬─│┼
|
│ cosmopolitan § standard i/o » without mutexes ─╬─│┼
|
||||||
╚────────────────────────────────────────────────────────────────────────────│*/
|
╚────────────────────────────────────────────────────────────────────────────│*/
|
||||||
|
|
||||||
void flockfile(FILE *);
|
void flockfile(FILE *) paramsnonnull();
|
||||||
void funlockfile(FILE *);
|
void funlockfile(FILE *) paramsnonnull();
|
||||||
int ftrylockfile(FILE *);
|
int ftrylockfile(FILE *) paramsnonnull();
|
||||||
int getc_unlocked(FILE *) paramsnonnull();
|
int getc_unlocked(FILE *) paramsnonnull();
|
||||||
int getchar_unlocked(void);
|
int getchar_unlocked(void);
|
||||||
int putc_unlocked(int, FILE *) paramsnonnull();
|
int putc_unlocked(int, FILE *) paramsnonnull();
|
||||||
|
@ -149,6 +151,7 @@ int fputws_unlocked(const wchar_t *, FILE *);
|
||||||
wint_t ungetwc_unlocked(wint_t, FILE *) paramsnonnull();
|
wint_t ungetwc_unlocked(wint_t, FILE *) paramsnonnull();
|
||||||
int ungetc_unlocked(int, FILE *) paramsnonnull();
|
int ungetc_unlocked(int, FILE *) paramsnonnull();
|
||||||
int fseeko_unlocked(FILE *, int64_t, int) paramsnonnull();
|
int fseeko_unlocked(FILE *, int64_t, int) paramsnonnull();
|
||||||
|
ssize_t getdelim_unlocked(char **, size_t *, int, FILE *) paramsnonnull();
|
||||||
int fprintf_unlocked(FILE *, const char *, ...) printfesque(2)
|
int fprintf_unlocked(FILE *, const char *, ...) printfesque(2)
|
||||||
paramsnonnull((1, 2)) dontthrow nocallback;
|
paramsnonnull((1, 2)) dontthrow nocallback;
|
||||||
int vfprintf_unlocked(FILE *, const char *, va_list)
|
int vfprintf_unlocked(FILE *, const char *, va_list)
|
||||||
|
|
|
@ -1573,18 +1573,6 @@ syscon sock SOCK_NONBLOCK 0x0800 0x0800 0x20000000 0x4000 0x20000000
|
||||||
syscon sock SOCK_DCCP 6 0 0 0 0 0 # what is it?
|
syscon sock SOCK_DCCP 6 0 0 0 0 0 # what is it?
|
||||||
syscon sock SOCK_PACKET 10 0 0 0 0 0 # what is it?
|
syscon sock SOCK_PACKET 10 0 0 0 0 0 # what is it?
|
||||||
|
|
||||||
syscon prsnlty ADDR_COMPAT_LAYOUT 0x0200000 0 0 0 0 0 # linux only
|
|
||||||
syscon prsnlty READ_IMPLIES_EXEC 0x0400000 0 0 0 0 0 # linux only
|
|
||||||
syscon prsnlty ADDR_LIMIT_3GB 0x8000000 0 0 0 0 0 # linux only
|
|
||||||
syscon prsnlty FDPIC_FUNCPTRS 0x0080000 0 0 0 0 0 # linux only
|
|
||||||
syscon prsnlty STICKY_TIMEOUTS 0x4000000 0 0 0 0 0 # linux only
|
|
||||||
syscon prsnlty MMAP_PAGE_ZERO 0x0100000 0 0 0 0 0 # linux only
|
|
||||||
syscon prsnlty ADDR_LIMIT_32BIT 0x0800000 0 0 0 0 0 # linux only
|
|
||||||
syscon prsnlty WHOLE_SECONDS 0x2000000 0 0 0 0 0 # linux only
|
|
||||||
syscon prsnlty ADDR_NO_RANDOMIZE 0x0040000 0 0 0 0 0 # linux only
|
|
||||||
syscon prsnlty SHORT_INODE 0x1000000 0 0 0 0 0 # linux only
|
|
||||||
syscon prsnlty UNAME26 0x0020000 0 0 0 0 0 # linux only
|
|
||||||
|
|
||||||
syscon misc TH_FIN 1 1 1 1 1 1 # consensus
|
syscon misc TH_FIN 1 1 1 1 1 1 # consensus
|
||||||
syscon misc TH_SYN 2 2 2 2 2 2 # consensus
|
syscon misc TH_SYN 2 2 2 2 2 2 # consensus
|
||||||
syscon misc TH_RST 4 4 4 4 4 4 # consensus
|
syscon misc TH_RST 4 4 4 4 4 4 # consensus
|
||||||
|
|
|
@ -1,2 +0,0 @@
|
||||||
#include "libc/sysv/consts/syscon.internal.h"
|
|
||||||
.syscon prsnlty,ADDR_COMPAT_LAYOUT,0x0200000,0,0,0,0,0
|
|
|
@ -1,2 +0,0 @@
|
||||||
#include "libc/sysv/consts/syscon.internal.h"
|
|
||||||
.syscon prsnlty,ADDR_LIMIT_32BIT,0x0800000,0,0,0,0,0
|
|
|
@ -1,2 +0,0 @@
|
||||||
#include "libc/sysv/consts/syscon.internal.h"
|
|
||||||
.syscon prsnlty,ADDR_LIMIT_3GB,0x8000000,0,0,0,0,0
|
|
|
@ -1,2 +0,0 @@
|
||||||
#include "libc/sysv/consts/syscon.internal.h"
|
|
||||||
.syscon prsnlty,ADDR_NO_RANDOMIZE,0x0040000,0,0,0,0,0
|
|
|
@ -1,2 +0,0 @@
|
||||||
#include "libc/sysv/consts/syscon.internal.h"
|
|
||||||
.syscon prsnlty,FDPIC_FUNCPTRS,0x0080000,0,0,0,0,0
|
|
|
@ -1,2 +0,0 @@
|
||||||
#include "libc/sysv/consts/syscon.internal.h"
|
|
||||||
.syscon prsnlty,MMAP_PAGE_ZERO,0x0100000,0,0,0,0,0
|
|
|
@ -1,2 +0,0 @@
|
||||||
#include "libc/sysv/consts/syscon.internal.h"
|
|
||||||
.syscon prsnlty,READ_IMPLIES_EXEC,0x0400000,0,0,0,0,0
|
|
|
@ -1,2 +0,0 @@
|
||||||
#include "libc/sysv/consts/syscon.internal.h"
|
|
||||||
.syscon prsnlty,SHORT_INODE,0x1000000,0,0,0,0,0
|
|
|
@ -1,2 +0,0 @@
|
||||||
#include "libc/sysv/consts/syscon.internal.h"
|
|
||||||
.syscon prsnlty,STICKY_TIMEOUTS,0x4000000,0,0,0,0,0
|
|
|
@ -1,2 +0,0 @@
|
||||||
#include "libc/sysv/consts/syscon.internal.h"
|
|
||||||
.syscon prsnlty,UNAME26,0x0020000,0,0,0,0,0
|
|
|
@ -1,2 +0,0 @@
|
||||||
#include "libc/sysv/consts/syscon.internal.h"
|
|
||||||
.syscon prsnlty,WHOLE_SECONDS,0x2000000,0,0,0,0,0
|
|
|
@ -1,34 +1,17 @@
|
||||||
#ifndef COSMOPOLITAN_LIBC_SYSV_CONSTS_PERSONALITY_H_
|
#ifndef COSMOPOLITAN_LIBC_SYSV_CONSTS_PERSONALITY_H_
|
||||||
#define COSMOPOLITAN_LIBC_SYSV_CONSTS_PERSONALITY_H_
|
#define COSMOPOLITAN_LIBC_SYSV_CONSTS_PERSONALITY_H_
|
||||||
#include "libc/runtime/symbolic.h"
|
#include "libc/runtime/symbolic.h"
|
||||||
#if !(__ASSEMBLER__ + __LINKER__ + 0)
|
|
||||||
COSMOPOLITAN_C_START_
|
|
||||||
|
|
||||||
extern const long ADDR_COMPAT_LAYOUT;
|
#define ADDR_COMPAT_LAYOUT 0x0200000
|
||||||
extern const long READ_IMPLIES_EXEC;
|
#define READ_IMPLIES_EXEC 0x0400000
|
||||||
extern const long ADDR_LIMIT_3GB;
|
#define ADDR_LIMIT_3GB 0x8000000
|
||||||
extern const long FDPIC_FUNCPTRS;
|
#define FDPIC_FUNCPTRS 0x0080000
|
||||||
extern const long STICKY_TIMEOUTS;
|
#define STICKY_TIMEOUTS 0x4000000
|
||||||
extern const long MMAP_PAGE_ZERO;
|
#define MMAP_PAGE_ZERO 0x0100000
|
||||||
extern const long ADDR_LIMIT_32BIT;
|
#define ADDR_LIMIT_32BIT 0x0800000
|
||||||
extern const long WHOLE_SECONDS;
|
#define WHOLE_SECONDS 0x2000000
|
||||||
extern const long ADDR_NO_RANDOMIZE;
|
#define ADDR_NO_RANDOMIZE 0x0040000
|
||||||
extern const long SHORT_INODE;
|
#define SHORT_INODE 0x1000000
|
||||||
extern const long UNAME26;
|
#define UNAME26 0x0020000
|
||||||
|
|
||||||
COSMOPOLITAN_C_END_
|
|
||||||
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
|
|
||||||
|
|
||||||
#define ADDR_COMPAT_LAYOUT SYMBOLIC(ADDR_COMPAT_LAYOUT)
|
|
||||||
#define READ_IMPLIES_EXEC SYMBOLIC(READ_IMPLIES_EXEC)
|
|
||||||
#define ADDR_LIMIT_3GB SYMBOLIC(ADDR_LIMIT_3GB)
|
|
||||||
#define FDPIC_FUNCPTRS SYMBOLIC(FDPIC_FUNCPTRS)
|
|
||||||
#define STICKY_TIMEOUTS SYMBOLIC(STICKY_TIMEOUTS)
|
|
||||||
#define MMAP_PAGE_ZERO SYMBOLIC(MMAP_PAGE_ZERO)
|
|
||||||
#define ADDR_LIMIT_32BIT SYMBOLIC(ADDR_LIMIT_32BIT)
|
|
||||||
#define WHOLE_SECONDS SYMBOLIC(WHOLE_SECONDS)
|
|
||||||
#define ADDR_NO_RANDOMIZE SYMBOLIC(ADDR_NO_RANDOMIZE)
|
|
||||||
#define SHORT_INODE SYMBOLIC(SHORT_INODE)
|
|
||||||
#define UNAME26 SYMBOLIC(UNAME26)
|
|
||||||
|
|
||||||
#endif /* COSMOPOLITAN_LIBC_SYSV_CONSTS_PERSONALITY_H_ */
|
#endif /* COSMOPOLITAN_LIBC_SYSV_CONSTS_PERSONALITY_H_ */
|
||||||
|
|
|
@ -55,6 +55,18 @@ TEST(open, enametoolong) {
|
||||||
ASSERT_SYS(ENAMETOOLONG, -1, creat(s, 0644));
|
ASSERT_SYS(ENAMETOOLONG, -1, creat(s, 0644));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TEST(open, testSpaceInFilename) {
|
||||||
|
char buf[8] = {0};
|
||||||
|
ASSERT_SYS(0, 0, xbarf("hello txt", "hello", -1));
|
||||||
|
ASSERT_SYS(0, 3, open("hello txt", O_WRONLY));
|
||||||
|
EXPECT_SYS(0, 1, write(3, "H", 1));
|
||||||
|
EXPECT_SYS(0, 0, close(3));
|
||||||
|
ASSERT_SYS(0, 3, open("hello txt", O_RDONLY));
|
||||||
|
EXPECT_SYS(0, 5, read(3, buf, 7));
|
||||||
|
EXPECT_STREQ("Hello", buf);
|
||||||
|
EXPECT_SYS(0, 0, close(3));
|
||||||
|
}
|
||||||
|
|
||||||
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));
|
||||||
|
|
|
@ -46,6 +46,27 @@ TEST(asan, test) {
|
||||||
EXPECT_FALSE(__asan_is_valid(p, 64 + 4));
|
EXPECT_FALSE(__asan_is_valid(p, 64 + 4));
|
||||||
EXPECT_TRUE(__asan_is_valid(p + 1, 64 + 2));
|
EXPECT_TRUE(__asan_is_valid(p + 1, 64 + 2));
|
||||||
EXPECT_FALSE(__asan_is_valid(p + 1, 64 + 3));
|
EXPECT_FALSE(__asan_is_valid(p + 1, 64 + 3));
|
||||||
|
EXPECT_FALSE(__asan_is_valid(p - 1, 64));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(asan, test2) {
|
||||||
|
char *p;
|
||||||
|
if (!IsAsan()) return;
|
||||||
|
p = gc(memalign(16, 64));
|
||||||
|
// asan design precludes this kind of poisoning
|
||||||
|
__asan_poison(p + 1, 1, kAsanProtected);
|
||||||
|
EXPECT_TRUE(__asan_is_valid(p, 2));
|
||||||
|
EXPECT_TRUE(__asan_is_valid(p + 1, 2));
|
||||||
|
// but we can do this
|
||||||
|
__asan_poison(p + 7, 1, kAsanProtected);
|
||||||
|
EXPECT_TRUE(__asan_is_valid(p + 6, 1));
|
||||||
|
EXPECT_FALSE(__asan_is_valid(p + 7, 1));
|
||||||
|
EXPECT_TRUE(__asan_is_valid(p + 8, 1));
|
||||||
|
EXPECT_FALSE(__asan_is_valid(p + 6, 2));
|
||||||
|
EXPECT_FALSE(__asan_is_valid(p + 7, 2));
|
||||||
|
EXPECT_FALSE(__asan_is_valid(p + 6, 3));
|
||||||
|
__asan_unpoison(p + 7, 1);
|
||||||
|
EXPECT_TRUE(__asan_is_valid(p + 6, 3));
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(asan, testEmptySize_isAlwaysValid) {
|
TEST(asan, testEmptySize_isAlwaysValid) {
|
||||||
|
|
|
@ -0,0 +1,37 @@
|
||||||
|
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
|
||||||
|
│vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi│
|
||||||
|
╞══════════════════════════════════════════════════════════════════════════════╡
|
||||||
|
│ Copyright 2022 Justine Alexandra Roberts Tunney │
|
||||||
|
│ │
|
||||||
|
│ Permission to use, copy, modify, and/or distribute this software for │
|
||||||
|
│ any purpose with or without fee is hereby granted, provided that the │
|
||||||
|
│ above copyright notice and this permission notice appear in all copies. │
|
||||||
|
│ │
|
||||||
|
│ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL │
|
||||||
|
│ WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED │
|
||||||
|
│ WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE │
|
||||||
|
│ AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL │
|
||||||
|
│ DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR │
|
||||||
|
│ PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER │
|
||||||
|
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
||||||
|
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||||
|
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||||
|
#include "libc/calls/calls.h"
|
||||||
|
#include "libc/dce.h"
|
||||||
|
#include "libc/nexgen32e/threaded.h"
|
||||||
|
#include "libc/testlib/ezbench.h"
|
||||||
|
#include "libc/testlib/testlib.h"
|
||||||
|
|
||||||
|
char tib[64];
|
||||||
|
|
||||||
|
TEST(gettid, test) {
|
||||||
|
if (IsLinux()) EXPECT_EQ(getpid(), gettid());
|
||||||
|
if (IsNetbsd()) EXPECT_EQ(1, gettid());
|
||||||
|
}
|
||||||
|
|
||||||
|
BENCH(gettid, bench) {
|
||||||
|
int gettid_(void) asm("gettid");
|
||||||
|
EZBENCH2("gettid (single threaded)", donothing, gettid());
|
||||||
|
__install_tls(__initialize_tls(tib));
|
||||||
|
EZBENCH2("gettid (tls enabled)", donothing, gettid());
|
||||||
|
}
|
|
@ -28,6 +28,8 @@ TEST(tls, test) {
|
||||||
EXPECT_EQ(31337, errno);
|
EXPECT_EQ(31337, errno);
|
||||||
EXPECT_EQ(&__errno, __errno_location());
|
EXPECT_EQ(&__errno, __errno_location());
|
||||||
__initialize_tls(tib);
|
__initialize_tls(tib);
|
||||||
|
*(int *)((char *)tib + 0x38) = gettid();
|
||||||
|
*(int *)((char *)tib + 0x3c) = __errno;
|
||||||
__install_tls(tib);
|
__install_tls(tib);
|
||||||
EXPECT_EQ(31337, errno);
|
EXPECT_EQ(31337, errno);
|
||||||
EXPECT_EQ(tib, __get_tls());
|
EXPECT_EQ(tib, __get_tls());
|
||||||
|
|
|
@ -80,10 +80,10 @@ TEST(rand64, testLcg_doesntProduceIdenticalValues) {
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(rand64, testThreadSafety_doesntProduceIdenticalValues) {
|
TEST(rand64, testThreadSafety_doesntProduceIdenticalValues) {
|
||||||
char *tls[THREADS];
|
int i, j, rc, ws;
|
||||||
sigset_t ss, oldss;
|
sigset_t ss, oldss;
|
||||||
|
char *tls[THREADS];
|
||||||
void *stacks[THREADS];
|
void *stacks[THREADS];
|
||||||
int i, j, rc, ws, tid[THREADS];
|
|
||||||
struct sigaction oldsa;
|
struct sigaction oldsa;
|
||||||
struct sigaction sa = {.sa_handler = OnChld, .sa_flags = SA_RESTART};
|
struct sigaction sa = {.sa_handler = OnChld, .sa_flags = SA_RESTART};
|
||||||
EXPECT_NE(-1, sigaction(SIGCHLD, &sa, &oldsa));
|
EXPECT_NE(-1, sigaction(SIGCHLD, &sa, &oldsa));
|
||||||
|
@ -92,19 +92,20 @@ TEST(rand64, testThreadSafety_doesntProduceIdenticalValues) {
|
||||||
sigaddset(&ss, SIGCHLD);
|
sigaddset(&ss, SIGCHLD);
|
||||||
EXPECT_EQ(0, sigprocmask(SIG_BLOCK, &ss, &oldss));
|
EXPECT_EQ(0, sigprocmask(SIG_BLOCK, &ss, &oldss));
|
||||||
ready = false;
|
ready = false;
|
||||||
memset(tid, -1, sizeof(tid));
|
|
||||||
for (i = 0; i < THREADS; ++i) {
|
for (i = 0; i < THREADS; ++i) {
|
||||||
tls[i] = __initialize_tls(calloc(1, 64));
|
tls[i] = __initialize_tls(calloc(1, 64));
|
||||||
stacks[i] = mmap(0, GetStackSize(), PROT_READ | PROT_WRITE,
|
stacks[i] = mmap(0, GetStackSize(), PROT_READ | PROT_WRITE,
|
||||||
MAP_STACK | MAP_ANONYMOUS, -1, 0);
|
MAP_STACK | MAP_ANONYMOUS, -1, 0);
|
||||||
ASSERT_NE(-1, clone(Thrasher, stacks[i], GetStackSize(),
|
ASSERT_NE(
|
||||||
CLONE_THREAD | CLONE_VM | CLONE_FS | CLONE_FILES |
|
-1,
|
||||||
CLONE_SIGHAND | CLONE_SETTLS | CLONE_CHILD_CLEARTID,
|
clone(Thrasher, stacks[i], GetStackSize(),
|
||||||
(void *)(intptr_t)i, 0, tls[i], 64, tid + i));
|
CLONE_THREAD | CLONE_VM | CLONE_FS | CLONE_FILES | CLONE_SIGHAND |
|
||||||
|
CLONE_SETTLS | CLONE_CHILD_SETTID | CLONE_CHILD_CLEARTID,
|
||||||
|
(void *)(intptr_t)i, 0, tls[i], 64, (int *)(tls[i] + 0x38)));
|
||||||
}
|
}
|
||||||
ready = true;
|
ready = true;
|
||||||
for (i = 0; i < THREADS; ++i) {
|
for (i = 0; i < THREADS; ++i) {
|
||||||
_spinlock(tid + i);
|
_spinlock((int *)(tls[i] + 0x38));
|
||||||
EXPECT_SYS(0, 0, munmap(stacks[i], GetStackSize()));
|
EXPECT_SYS(0, 0, munmap(stacks[i], GetStackSize()));
|
||||||
free(tls[i]);
|
free(tls[i]);
|
||||||
}
|
}
|
||||||
|
|
|
@ -41,6 +41,12 @@ void Extract(const char *from, const char *to, int mode) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void SetUpOnce(void) {
|
void SetUpOnce(void) {
|
||||||
|
|
||||||
|
// nothing to do if we're using elf
|
||||||
|
if (~SUPPORT_VECTOR & (WINDOWS | XNU)) {
|
||||||
|
exit(0);
|
||||||
|
}
|
||||||
|
|
||||||
ASSERT_SYS(0, 0, mkdir("bin", 0755));
|
ASSERT_SYS(0, 0, mkdir("bin", 0755));
|
||||||
Extract("/zip/apetest.com", "bin/apetest.com", 0755);
|
Extract("/zip/apetest.com", "bin/apetest.com", 0755);
|
||||||
Extract("/zip/apetest2.com", "bin/apetest2.com", 0755);
|
Extract("/zip/apetest2.com", "bin/apetest2.com", 0755);
|
||||||
|
|
|
@ -45,7 +45,7 @@ void SetUp(void) {
|
||||||
tls = calloc(1, 64);
|
tls = calloc(1, 64);
|
||||||
__initialize_tls(tls);
|
__initialize_tls(tls);
|
||||||
*(int *)(tls + 0x3c) = 31337;
|
*(int *)(tls + 0x3c) = 31337;
|
||||||
childetid = (int *)(tls + 0x0038);
|
childetid = (int *)(tls + 0x38);
|
||||||
ASSERT_NE(MAP_FAILED, (stack = mmap(0, GetStackSize(), PROT_READ | PROT_WRITE,
|
ASSERT_NE(MAP_FAILED, (stack = mmap(0, GetStackSize(), PROT_READ | PROT_WRITE,
|
||||||
MAP_STACK | MAP_ANONYMOUS, -1, 0)));
|
MAP_STACK | MAP_ANONYMOUS, -1, 0)));
|
||||||
}
|
}
|
||||||
|
@ -95,6 +95,7 @@ TEST(clone, test1) {
|
||||||
CLONE_SETTLS,
|
CLONE_SETTLS,
|
||||||
(void *)23, &ptid, tls, 64, childetid)));
|
(void *)23, &ptid, tls, 64, childetid)));
|
||||||
_spinlock(childetid); // CLONE_CHILD_CLEARTID
|
_spinlock(childetid); // CLONE_CHILD_CLEARTID
|
||||||
|
ASSERT_NE(gettid(), tid);
|
||||||
ASSERT_EQ(tid, ptid);
|
ASSERT_EQ(tid, ptid);
|
||||||
ASSERT_EQ(42, x);
|
ASSERT_EQ(42, x);
|
||||||
ASSERT_NE(me, tid);
|
ASSERT_NE(me, tid);
|
||||||
|
@ -130,6 +131,6 @@ TEST(clone, tlsSystemCallsErrno_wontClobberMainThreadBecauseTls) {
|
||||||
BENCH(clone, bench) {
|
BENCH(clone, bench) {
|
||||||
errno_t *volatile ep;
|
errno_t *volatile ep;
|
||||||
char *volatile tp;
|
char *volatile tp;
|
||||||
EZBENCH2("__errno_location", donothing, (ep = (__errno_location())));
|
EZBENCH2("__errno_location", donothing, (ep = __errno_location()));
|
||||||
EZBENCH2("__get_tls", donothing, (tp = __get_tls()));
|
EZBENCH2("__get_tls", donothing, (tp = __get_tls()));
|
||||||
}
|
}
|
||||||
|
|
87
test/libc/stdio/fgetln_test.c
Normal file
87
test/libc/stdio/fgetln_test.c
Normal file
|
@ -0,0 +1,87 @@
|
||||||
|
/*-*- 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/mem/mem.h"
|
||||||
|
#include "libc/runtime/gc.internal.h"
|
||||||
|
#include "libc/stdio/stdio.h"
|
||||||
|
#include "libc/str/str.h"
|
||||||
|
#include "libc/testlib/ezbench.h"
|
||||||
|
#include "libc/testlib/hyperion.h"
|
||||||
|
#include "libc/testlib/testlib.h"
|
||||||
|
#include "libc/x/x.h"
|
||||||
|
|
||||||
|
TEST(fgetln, test) {
|
||||||
|
FILE *f;
|
||||||
|
f = fmemopen(gc(strdup(kHyperion)), kHyperionSize, "r+");
|
||||||
|
EXPECT_STREQ("The fall of Hyperion - a Dream\n", fgetln(f, 0));
|
||||||
|
EXPECT_STREQ("John Keats\n", fgetln(f, 0));
|
||||||
|
EXPECT_STREQ("\n", fgetln(f, 0));
|
||||||
|
fclose(f);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(fgetln, testGoodLastLine) {
|
||||||
|
FILE *f;
|
||||||
|
size_t n;
|
||||||
|
f = fmemopen("foo\nbar\n", 8, "r");
|
||||||
|
EXPECT_STREQ("foo\n", fgetln(f, &n));
|
||||||
|
EXPECT_EQ(4, n);
|
||||||
|
EXPECT_STREQ("bar\n", fgetln(f, &n));
|
||||||
|
EXPECT_EQ(4, n);
|
||||||
|
EXPECT_EQ(NULL, fgetln(f, 0));
|
||||||
|
EXPECT_FALSE(ferror(f));
|
||||||
|
EXPECT_TRUE(feof(f));
|
||||||
|
fclose(f);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(fgetln, testEvilLastLine) {
|
||||||
|
FILE *f;
|
||||||
|
f = fmemopen("foo\nbar", 7, "r");
|
||||||
|
EXPECT_STREQ("foo\n", fgetln(f, 0));
|
||||||
|
EXPECT_STREQ("bar", fgetln(f, 0));
|
||||||
|
EXPECT_EQ(NULL, fgetln(f, 0));
|
||||||
|
EXPECT_FALSE(ferror(f));
|
||||||
|
EXPECT_TRUE(feof(f));
|
||||||
|
fclose(f);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(fgetln, testReadingFromStdin_doesntLeakMemory) {
|
||||||
|
FILE *f;
|
||||||
|
int oldstdin, pfds[2];
|
||||||
|
oldstdin = dup(0);
|
||||||
|
EXPECT_SYS(0, 0, pipe(pfds));
|
||||||
|
EXPECT_SYS(0, 8, write(pfds[1], "foo\nbar\n", 8));
|
||||||
|
EXPECT_SYS(0, 0, close(pfds[1]));
|
||||||
|
EXPECT_SYS(0, 0, close(0));
|
||||||
|
EXPECT_SYS(0, 0, dup(pfds[0]));
|
||||||
|
EXPECT_SYS(0, 0, close(pfds[0]));
|
||||||
|
EXPECT_STREQ("foo\n", fgetln(stdin, 0));
|
||||||
|
EXPECT_STREQ("bar\n", fgetln(stdin, 0));
|
||||||
|
EXPECT_EQ(NULL, fgetln(stdin, 0));
|
||||||
|
EXPECT_FALSE(ferror(stdin));
|
||||||
|
EXPECT_TRUE(feof(stdin));
|
||||||
|
EXPECT_SYS(0, 0, close(0));
|
||||||
|
EXPECT_SYS(0, 0, dup(oldstdin));
|
||||||
|
clearerr(stdin);
|
||||||
|
}
|
||||||
|
|
||||||
|
BENCH(fgetln, bench) {
|
||||||
|
FILE *f = fmemopen(gc(strdup(kHyperion)), kHyperionSize, "r+");
|
||||||
|
EZBENCH2("fgetln", donothing, fgetln(f, 0));
|
||||||
|
EZBENCH2("xgetline", donothing, free(xgetline(f)));
|
||||||
|
fclose(f);
|
||||||
|
}
|
314
third_party/libcxx/errno.h
vendored
314
third_party/libcxx/errno.h
vendored
|
@ -78,320 +78,6 @@ static const int __elast2 = 105;
|
||||||
|
|
||||||
// supply errno values likely to be missing, particularly on Windows
|
// supply errno values likely to be missing, particularly on Windows
|
||||||
|
|
||||||
#ifndef EAFNOSUPPORT
|
|
||||||
#define EAFNOSUPPORT 9901
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifndef EADDRINUSE
|
|
||||||
#define EADDRINUSE 9902
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifndef EADDRNOTAVAIL
|
|
||||||
#define EADDRNOTAVAIL 9903
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifndef EISCONN
|
|
||||||
#define EISCONN 9904
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifndef EBADMSG
|
|
||||||
#define EBADMSG 9905
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifndef ECONNABORTED
|
|
||||||
#define ECONNABORTED 9906
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifndef EALREADY
|
|
||||||
#define EALREADY 9907
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifndef ECONNREFUSED
|
|
||||||
#define ECONNREFUSED 9908
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifndef ECONNRESET
|
|
||||||
#define ECONNRESET 9909
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifndef EDESTADDRREQ
|
|
||||||
#define EDESTADDRREQ 9910
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifndef EHOSTUNREACH
|
|
||||||
#define EHOSTUNREACH 9911
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifndef EIDRM
|
|
||||||
#define EIDRM 9912
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifndef EMSGSIZE
|
|
||||||
#define EMSGSIZE 9913
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifndef ENETDOWN
|
|
||||||
#define ENETDOWN 9914
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifndef ENETRESET
|
|
||||||
#define ENETRESET 9915
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifndef ENETUNREACH
|
|
||||||
#define ENETUNREACH 9916
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifndef ENOBUFS
|
|
||||||
#define ENOBUFS 9917
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifndef ENOLINK
|
|
||||||
#define ENOLINK 9918
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifndef ENODATA
|
|
||||||
#define ENODATA 9919
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifndef ENOMSG
|
|
||||||
#define ENOMSG 9920
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifndef ENOPROTOOPT
|
|
||||||
#define ENOPROTOOPT 9921
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifndef ENOSR
|
|
||||||
#define ENOSR 9922
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifndef ENOTSOCK
|
|
||||||
#define ENOTSOCK 9923
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifndef ENOSTR
|
|
||||||
#define ENOSTR 9924
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifndef ENOTCONN
|
|
||||||
#define ENOTCONN 9925
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifndef ENOTSUP
|
|
||||||
#define ENOTSUP 9926
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifndef ECANCELED
|
|
||||||
#define ECANCELED 9927
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifndef EINPROGRESS
|
|
||||||
#define EINPROGRESS 9928
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifndef EOPNOTSUPP
|
|
||||||
#define EOPNOTSUPP 9929
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifndef EWOULDBLOCK
|
|
||||||
#define EWOULDBLOCK 9930
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifndef EOWNERDEAD
|
|
||||||
#define EOWNERDEAD 9931
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifndef EPROTO
|
|
||||||
#define EPROTO 9932
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifndef EPROTONOSUPPORT
|
|
||||||
#define EPROTONOSUPPORT 9933
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifndef ENOTRECOVERABLE
|
|
||||||
#define ENOTRECOVERABLE 9934
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifndef ETIME
|
|
||||||
#define ETIME 9935
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifndef ETXTBSY
|
|
||||||
#define ETXTBSY 9936
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifndef ETIMEDOUT
|
|
||||||
#define ETIMEDOUT 9938
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifndef ELOOP
|
|
||||||
#define ELOOP 9939
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifndef EOVERFLOW
|
|
||||||
#define EOVERFLOW 9940
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifndef EPROTOTYPE
|
|
||||||
#define EPROTOTYPE 9941
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifndef ENOSYS
|
|
||||||
#define ENOSYS 9942
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifndef EINVAL
|
|
||||||
#define EINVAL 9943
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifndef ERANGE
|
|
||||||
#define ERANGE 9944
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifndef EILSEQ
|
|
||||||
#define EILSEQ 9945
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// Windows Mobile doesn't appear to define these:
|
|
||||||
|
|
||||||
#ifndef E2BIG
|
|
||||||
#define E2BIG 9946
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifndef EDOM
|
|
||||||
#define EDOM 9947
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifndef EFAULT
|
|
||||||
#define EFAULT 9948
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifndef EBADF
|
|
||||||
#define EBADF 9949
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifndef EPIPE
|
|
||||||
#define EPIPE 9950
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifndef EXDEV
|
|
||||||
#define EXDEV 9951
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifndef EBUSY
|
|
||||||
#define EBUSY 9952
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifndef ENOTEMPTY
|
|
||||||
#define ENOTEMPTY 9953
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifndef ENOEXEC
|
|
||||||
#define ENOEXEC 9954
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifndef EEXIST
|
|
||||||
#define EEXIST 9955
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifndef EFBIG
|
|
||||||
#define EFBIG 9956
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifndef ENAMETOOLONG
|
|
||||||
#define ENAMETOOLONG 9957
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifndef ENOTTY
|
|
||||||
#define ENOTTY 9958
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifndef EINTR
|
|
||||||
#define EINTR 9959
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifndef ESPIPE
|
|
||||||
#define ESPIPE 9960
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifndef EIO
|
|
||||||
#define EIO 9961
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifndef EISDIR
|
|
||||||
#define EISDIR 9962
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifndef ECHILD
|
|
||||||
#define ECHILD 9963
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifndef ENOLCK
|
|
||||||
#define ENOLCK 9964
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifndef ENOSPC
|
|
||||||
#define ENOSPC 9965
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifndef ENXIO
|
|
||||||
#define ENXIO 9966
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifndef ENODEV
|
|
||||||
#define ENODEV 9967
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifndef ENOENT
|
|
||||||
#define ENOENT 9968
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifndef ESRCH
|
|
||||||
#define ESRCH 9969
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifndef ENOTDIR
|
|
||||||
#define ENOTDIR 9970
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifndef ENOMEM
|
|
||||||
#define ENOMEM 9971
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifndef EPERM
|
|
||||||
#define EPERM 9972
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifndef EACCES
|
|
||||||
#define EACCES 9973
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifndef EROFS
|
|
||||||
#define EROFS 9974
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifndef EDEADLK
|
|
||||||
#define EDEADLK 9975
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifndef EAGAIN
|
|
||||||
#define EAGAIN 9976
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifndef ENFILE
|
|
||||||
#define ENFILE 9977
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifndef EMFILE
|
|
||||||
#define EMFILE 9978
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifndef EMLINK
|
|
||||||
#define EMLINK 9979
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#endif // __cplusplus
|
#endif // __cplusplus
|
||||||
|
|
||||||
#endif // _LIBCPP_ERRNO_H
|
#endif // _LIBCPP_ERRNO_H
|
||||||
|
|
12
third_party/lua/lrepl.c
vendored
12
third_party/lua/lrepl.c
vendored
|
@ -234,9 +234,9 @@ static ssize_t pushline (lua_State *L, int firstline) {
|
||||||
ssize_t rc;
|
ssize_t rc;
|
||||||
char *prmt;
|
char *prmt;
|
||||||
globalL = L;
|
globalL = L;
|
||||||
if (lua_repl_isterminal) {
|
|
||||||
prmt = strdup(get_prompt(L, firstline));
|
prmt = strdup(get_prompt(L, firstline));
|
||||||
lua_pop(L, 1); /* remove prompt */
|
lua_pop(L, 1); /* remove prompt */
|
||||||
|
if (lua_repl_isterminal) {
|
||||||
LUA_REPL_UNLOCK;
|
LUA_REPL_UNLOCK;
|
||||||
rc = linenoiseEdit(lua_repl_linenoise, prmt, &b, !firstline || lua_repl_blocking);
|
rc = linenoiseEdit(lua_repl_linenoise, prmt, &b, !firstline || lua_repl_blocking);
|
||||||
free(prmt);
|
free(prmt);
|
||||||
|
@ -250,9 +250,17 @@ static ssize_t pushline (lua_State *L, int firstline) {
|
||||||
LUA_REPL_LOCK;
|
LUA_REPL_LOCK;
|
||||||
} else {
|
} else {
|
||||||
LUA_REPL_UNLOCK;
|
LUA_REPL_UNLOCK;
|
||||||
|
fputs(prmt, stdout);
|
||||||
|
fflush(stdout);
|
||||||
b = linenoiseGetLine(stdin);
|
b = linenoiseGetLine(stdin);
|
||||||
|
if (b) {
|
||||||
|
rc = 1;
|
||||||
|
} else if (ferror(stdin)) {
|
||||||
|
rc = -1;
|
||||||
|
} else {
|
||||||
|
rc = 0;
|
||||||
|
}
|
||||||
LUA_REPL_LOCK;
|
LUA_REPL_LOCK;
|
||||||
rc = b ? 1 : -1;
|
|
||||||
}
|
}
|
||||||
if (!(rc == -1 && errno == EAGAIN)) {
|
if (!(rc == -1 && errno == EAGAIN)) {
|
||||||
write(1, "\n", 1);
|
write(1, "\n", 1);
|
||||||
|
|
2
third_party/lua/lua.main.c
vendored
2
third_party/lua/lua.main.c
vendored
|
@ -307,6 +307,7 @@ static void doREPL (lua_State *L) {
|
||||||
progname = NULL; /* no 'progname' on errors in interactive mode */
|
progname = NULL; /* no 'progname' on errors in interactive mode */
|
||||||
lua_initrepl(L, LUA_PROGNAME);
|
lua_initrepl(L, LUA_PROGNAME);
|
||||||
for (;;) {
|
for (;;) {
|
||||||
|
if (lua_repl_isterminal)
|
||||||
linenoiseEnableRawMode(0);
|
linenoiseEnableRawMode(0);
|
||||||
TryAgain:
|
TryAgain:
|
||||||
status = lua_loadline(L);
|
status = lua_loadline(L);
|
||||||
|
@ -315,6 +316,7 @@ static void doREPL (lua_State *L) {
|
||||||
poll(&(struct pollfd){0, POLLIN}, 1, -1);
|
poll(&(struct pollfd){0, POLLIN}, 1, -1);
|
||||||
goto TryAgain;
|
goto TryAgain;
|
||||||
}
|
}
|
||||||
|
if (lua_repl_isterminal)
|
||||||
linenoiseDisableRawMode();
|
linenoiseDisableRawMode();
|
||||||
if (status == -1) {
|
if (status == -1) {
|
||||||
break;
|
break;
|
||||||
|
|
45
third_party/make/error.c
vendored
45
third_party/make/error.c
vendored
|
@ -57,48 +57,9 @@ void (*error_print_progname) (void);
|
||||||
/* This variable is incremented each time 'error' is called. */
|
/* This variable is incremented each time 'error' is called. */
|
||||||
unsigned int error_message_count;
|
unsigned int error_message_count;
|
||||||
|
|
||||||
#ifdef _LIBC
|
#undef fcntl
|
||||||
/* In the GNU C library, there is a predefined variable for this. */
|
#define program_name getprogname ()
|
||||||
|
#define __strerror_r strerror_r
|
||||||
# define program_name program_invocation_name
|
|
||||||
|
|
||||||
/* In GNU libc we want do not want to use the common name 'error' directly.
|
|
||||||
Instead make it a weak alias. */
|
|
||||||
extern void __error (int status, int errnum, const char *message, ...)
|
|
||||||
__attribute__ ((__format__ (__printf__, 3, 4)));
|
|
||||||
extern void __error_at_line (int status, int errnum, const char *file_name,
|
|
||||||
unsigned int line_number, const char *message,
|
|
||||||
...)
|
|
||||||
__attribute__ ((__format__ (__printf__, 5, 6)));
|
|
||||||
# define error __error
|
|
||||||
# define error_at_line __error_at_line
|
|
||||||
|
|
||||||
# define fflush(s) _IO_fflush (s)
|
|
||||||
# undef putc
|
|
||||||
# define putc(c, fp) _IO_putc (c, fp)
|
|
||||||
|
|
||||||
|
|
||||||
#else /* not _LIBC */
|
|
||||||
|
|
||||||
# if defined _WIN32 && ! defined __CYGWIN__
|
|
||||||
/* Get declarations of the native Windows API functions. */
|
|
||||||
# define WIN32_LEAN_AND_MEAN
|
|
||||||
/* Get _get_osfhandle. */
|
|
||||||
# if GNULIB_MSVC_NOTHROW
|
|
||||||
# include "msvc-nothrow.h"
|
|
||||||
# else
|
|
||||||
# endif
|
|
||||||
# endif
|
|
||||||
|
|
||||||
/* The gnulib override of fcntl is not needed in this file. */
|
|
||||||
# undef fcntl
|
|
||||||
|
|
||||||
# define program_name getprogname ()
|
|
||||||
|
|
||||||
# if GNULIB_STRERROR_R_POSIX || HAVE_STRERROR_R || defined strerror_r
|
|
||||||
# define __strerror_r strerror_r
|
|
||||||
# endif /* GNULIB_STRERROR_R_POSIX || HAVE_STRERROR_R || defined strerror_r */
|
|
||||||
#endif /* not _LIBC */
|
|
||||||
|
|
||||||
/* Return non-zero if FD is open. */
|
/* Return non-zero if FD is open. */
|
||||||
static int
|
static int
|
||||||
|
|
2
third_party/python/Lib/test/test_doctest.py
vendored
2
third_party/python/Lib/test/test_doctest.py
vendored
|
@ -2921,7 +2921,7 @@ Invalid file name:
|
||||||
>>> print(normalize(err)) # doctest: +ELLIPSIS
|
>>> print(normalize(err)) # doctest: +ELLIPSIS
|
||||||
Traceback (most recent call last):
|
Traceback (most recent call last):
|
||||||
...
|
...
|
||||||
FileNotFoundError: [Errno 2] ENOENT/2/No such file or directory: 'nosuchfile'
|
FileNotFoundError: [Errno 2] ENOENT...
|
||||||
|
|
||||||
Invalid doctest option:
|
Invalid doctest option:
|
||||||
|
|
||||||
|
|
2
third_party/python/Lib/test/test_module.py
vendored
2
third_party/python/Lib/test/test_module.py
vendored
|
@ -29,7 +29,7 @@ class ModuleTests(unittest.TestCase):
|
||||||
self.fail("__name__ = %s" % repr(s))
|
self.fail("__name__ = %s" % repr(s))
|
||||||
except AttributeError:
|
except AttributeError:
|
||||||
pass
|
pass
|
||||||
if cosmo.MODE != 'tiny':
|
if 'tiny' not in cosmo.MODE:
|
||||||
self.assertEqual(foo.__doc__, ModuleType.__doc__)
|
self.assertEqual(foo.__doc__, ModuleType.__doc__)
|
||||||
|
|
||||||
def test_uninitialized_missing_getattr(self):
|
def test_uninitialized_missing_getattr(self):
|
||||||
|
|
5
third_party/python/Modules/socketmodule.c
vendored
5
third_party/python/Modules/socketmodule.c
vendored
|
@ -12,6 +12,7 @@
|
||||||
#include "libc/dns/ent.h"
|
#include "libc/dns/ent.h"
|
||||||
#include "libc/errno.h"
|
#include "libc/errno.h"
|
||||||
#include "libc/nt/enum/version.h"
|
#include "libc/nt/enum/version.h"
|
||||||
|
#include "libc/nt/version.h"
|
||||||
#include "libc/runtime/runtime.h"
|
#include "libc/runtime/runtime.h"
|
||||||
#include "libc/sock/sock.h"
|
#include "libc/sock/sock.h"
|
||||||
#include "libc/sysv/consts/af.h"
|
#include "libc/sysv/consts/af.h"
|
||||||
|
@ -7146,9 +7147,9 @@ PyInit__socket(void)
|
||||||
if (TCP_USER_TIMEOUT) PyModule_AddIntMacro(m, TCP_USER_TIMEOUT);
|
if (TCP_USER_TIMEOUT) PyModule_AddIntMacro(m, TCP_USER_TIMEOUT);
|
||||||
if (TCP_SAVE_SYN) PyModule_AddIntMacro(m, TCP_SAVE_SYN);
|
if (TCP_SAVE_SYN) PyModule_AddIntMacro(m, TCP_SAVE_SYN);
|
||||||
if (TCP_SAVED_SYN) PyModule_AddIntMacro(m, TCP_SAVED_SYN);
|
if (TCP_SAVED_SYN) PyModule_AddIntMacro(m, TCP_SAVED_SYN);
|
||||||
if (TCP_KEEPCNT && (!IsWindows() || NtGetVersion() >= kNtVersionWindows10))
|
if (TCP_KEEPCNT && (!IsWindows() || IsAtLeastWindows10()))
|
||||||
PyModule_AddIntMacro(m, TCP_KEEPCNT);
|
PyModule_AddIntMacro(m, TCP_KEEPCNT);
|
||||||
if (TCP_FASTOPEN && (!IsWindows() || NtGetVersion() >= kNtVersionWindows10))
|
if (TCP_FASTOPEN && (!IsWindows() || IsAtLeastWindows10()))
|
||||||
PyModule_AddIntMacro(m, TCP_FASTOPEN);
|
PyModule_AddIntMacro(m, TCP_FASTOPEN);
|
||||||
if (TCP_FASTOPEN_CONNECT)
|
if (TCP_FASTOPEN_CONNECT)
|
||||||
PyModule_AddIntMacro(m, TCP_FASTOPEN_CONNECT);
|
PyModule_AddIntMacro(m, TCP_FASTOPEN_CONNECT);
|
||||||
|
|
|
@ -2791,6 +2791,9 @@ UNIX MODULE
|
||||||
unix.sigaction(unix.SIGALRM, MyOnSigAlrm, unix.SA_RESETHAND)
|
unix.sigaction(unix.SIGALRM, MyOnSigAlrm, unix.SA_RESETHAND)
|
||||||
unix.setitimer(unix.ITIMER_REAL, 0, 0, 1, 0)
|
unix.setitimer(unix.ITIMER_REAL, 0, 0, 1, 0)
|
||||||
|
|
||||||
|
`intns` needs to be on the interval `[0,1000000000)`
|
||||||
|
`valuens` needs to be on the interval `[0,1000000000)`
|
||||||
|
|
||||||
unix.strsignal(sig:int) → str
|
unix.strsignal(sig:int) → str
|
||||||
|
|
||||||
Turns platform-specific `sig` code into its symbolic name.
|
Turns platform-specific `sig` code into its symbolic name.
|
||||||
|
|
|
@ -16,151 +16,92 @@
|
||||||
│ 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 "dsp/scale/cdecimate2xuint8x8.h"
|
|
||||||
#include "libc/bits/atomic.h"
|
#include "libc/bits/atomic.h"
|
||||||
#include "libc/bits/bits.h"
|
|
||||||
#include "libc/bits/likely.h"
|
|
||||||
#include "libc/bits/popcnt.h"
|
|
||||||
#include "libc/bits/safemacros.internal.h"
|
#include "libc/bits/safemacros.internal.h"
|
||||||
#include "libc/calls/calls.h"
|
#include "libc/calls/calls.h"
|
||||||
#include "libc/calls/ioctl.h"
|
#include "libc/calls/ioctl.h"
|
||||||
#include "libc/calls/math.h"
|
#include "libc/calls/math.h"
|
||||||
#include "libc/calls/sigbits.h"
|
#include "libc/calls/sigbits.h"
|
||||||
#include "libc/calls/strace.internal.h"
|
|
||||||
#include "libc/calls/struct/dirent.h"
|
|
||||||
#include "libc/calls/struct/filter.h"
|
#include "libc/calls/struct/filter.h"
|
||||||
#include "libc/calls/struct/flock.h"
|
#include "libc/calls/struct/flock.h"
|
||||||
|
#include "libc/calls/struct/iovec.h"
|
||||||
#include "libc/calls/struct/rusage.h"
|
#include "libc/calls/struct/rusage.h"
|
||||||
#include "libc/calls/struct/sigaction.h"
|
#include "libc/calls/struct/sigaction.h"
|
||||||
#include "libc/calls/struct/stat.h"
|
#include "libc/calls/struct/stat.h"
|
||||||
#include "libc/calls/struct/termios.h"
|
#include "libc/calls/struct/termios.h"
|
||||||
#include "libc/calls/ttydefaults.h"
|
|
||||||
#include "libc/dce.h"
|
|
||||||
#include "libc/dns/dns.h"
|
#include "libc/dns/dns.h"
|
||||||
#include "libc/dns/hoststxt.h"
|
#include "libc/dns/hoststxt.h"
|
||||||
#include "libc/dos.h"
|
#include "libc/dos.h"
|
||||||
#include "libc/errno.h"
|
|
||||||
#include "libc/fmt/conv.h"
|
#include "libc/fmt/conv.h"
|
||||||
#include "libc/fmt/fmt.h"
|
|
||||||
#include "libc/fmt/itoa.h"
|
#include "libc/fmt/itoa.h"
|
||||||
#include "libc/intrin/kprintf.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/check.h"
|
#include "libc/log/check.h"
|
||||||
#include "libc/log/log.h"
|
#include "libc/log/log.h"
|
||||||
#include "libc/macros.internal.h"
|
|
||||||
#include "libc/math.h"
|
#include "libc/math.h"
|
||||||
#include "libc/mem/alloca.h"
|
#include "libc/mem/alloca.h"
|
||||||
#include "libc/mem/fmt.h"
|
|
||||||
#include "libc/mem/mem.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/nt2sysv.h"
|
||||||
#include "libc/nexgen32e/rdtsc.h"
|
#include "libc/nexgen32e/rdtsc.h"
|
||||||
#include "libc/nexgen32e/rdtscp.h"
|
|
||||||
#include "libc/nexgen32e/threaded.h"
|
#include "libc/nexgen32e/threaded.h"
|
||||||
|
#include "libc/nexgen32e/x86feature.h"
|
||||||
#include "libc/nt/enum/fileflagandattributes.h"
|
#include "libc/nt/enum/fileflagandattributes.h"
|
||||||
#include "libc/nt/runtime.h"
|
|
||||||
#include "libc/nt/thread.h"
|
#include "libc/nt/thread.h"
|
||||||
#include "libc/nt/version.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/gc.h"
|
#include "libc/runtime/gc.h"
|
||||||
#include "libc/runtime/gc.internal.h"
|
#include "libc/runtime/gc.internal.h"
|
||||||
#include "libc/runtime/internal.h"
|
|
||||||
#include "libc/runtime/memtrack.internal.h"
|
|
||||||
#include "libc/runtime/runtime.h"
|
|
||||||
#include "libc/runtime/stack.h"
|
#include "libc/runtime/stack.h"
|
||||||
#include "libc/runtime/symbols.internal.h"
|
|
||||||
#include "libc/sock/goodsocket.internal.h"
|
#include "libc/sock/goodsocket.internal.h"
|
||||||
#include "libc/sock/sock.h"
|
#include "libc/sock/sock.h"
|
||||||
#include "libc/stdio/append.internal.h"
|
#include "libc/stdio/append.internal.h"
|
||||||
#include "libc/stdio/hex.internal.h"
|
#include "libc/stdio/hex.internal.h"
|
||||||
#include "libc/stdio/stdio.h"
|
|
||||||
#include "libc/str/slice.h"
|
#include "libc/str/slice.h"
|
||||||
#include "libc/str/str.h"
|
|
||||||
#include "libc/str/undeflate.h"
|
#include "libc/str/undeflate.h"
|
||||||
#include "libc/sysv/consts/af.h"
|
#include "libc/sysv/consts/af.h"
|
||||||
#include "libc/sysv/consts/audit.h"
|
|
||||||
#include "libc/sysv/consts/auxv.h"
|
|
||||||
#include "libc/sysv/consts/clone.h"
|
#include "libc/sysv/consts/clone.h"
|
||||||
#include "libc/sysv/consts/dt.h"
|
#include "libc/sysv/consts/dt.h"
|
||||||
#include "libc/sysv/consts/ex.h"
|
#include "libc/sysv/consts/ex.h"
|
||||||
#include "libc/sysv/consts/exit.h"
|
#include "libc/sysv/consts/exit.h"
|
||||||
#include "libc/sysv/consts/f.h"
|
#include "libc/sysv/consts/f.h"
|
||||||
#include "libc/sysv/consts/grnd.h"
|
|
||||||
#include "libc/sysv/consts/inaddr.h"
|
#include "libc/sysv/consts/inaddr.h"
|
||||||
#include "libc/sysv/consts/ipproto.h"
|
#include "libc/sysv/consts/ipproto.h"
|
||||||
#include "libc/sysv/consts/lock.h"
|
|
||||||
#include "libc/sysv/consts/madv.h"
|
|
||||||
#include "libc/sysv/consts/map.h"
|
#include "libc/sysv/consts/map.h"
|
||||||
#include "libc/sysv/consts/msync.h"
|
|
||||||
#include "libc/sysv/consts/nr.h"
|
|
||||||
#include "libc/sysv/consts/o.h"
|
#include "libc/sysv/consts/o.h"
|
||||||
#include "libc/sysv/consts/poll.h"
|
#include "libc/sysv/consts/poll.h"
|
||||||
#include "libc/sysv/consts/pr.h"
|
#include "libc/sysv/consts/pr.h"
|
||||||
#include "libc/sysv/consts/prot.h"
|
#include "libc/sysv/consts/prot.h"
|
||||||
#include "libc/sysv/consts/rusage.h"
|
#include "libc/sysv/consts/rusage.h"
|
||||||
#include "libc/sysv/consts/s.h"
|
|
||||||
#include "libc/sysv/consts/sa.h"
|
#include "libc/sysv/consts/sa.h"
|
||||||
#include "libc/sysv/consts/shut.h"
|
|
||||||
#include "libc/sysv/consts/sig.h"
|
#include "libc/sysv/consts/sig.h"
|
||||||
#include "libc/sysv/consts/so.h"
|
|
||||||
#include "libc/sysv/consts/sock.h"
|
#include "libc/sysv/consts/sock.h"
|
||||||
#include "libc/sysv/consts/sol.h"
|
|
||||||
#include "libc/sysv/consts/tcp.h"
|
|
||||||
#include "libc/sysv/consts/termios.h"
|
#include "libc/sysv/consts/termios.h"
|
||||||
#include "libc/sysv/consts/w.h"
|
#include "libc/sysv/consts/w.h"
|
||||||
#include "libc/sysv/errfuns.h"
|
#include "libc/sysv/errfuns.h"
|
||||||
#include "libc/testlib/testlib.h"
|
|
||||||
#include "libc/time/time.h"
|
|
||||||
#include "libc/x/x.h"
|
#include "libc/x/x.h"
|
||||||
#include "libc/zip.h"
|
#include "libc/zip.h"
|
||||||
#include "net/http/escape.h"
|
#include "net/http/escape.h"
|
||||||
#include "net/http/http.h"
|
#include "net/http/http.h"
|
||||||
#include "net/http/ip.h"
|
#include "net/http/ip.h"
|
||||||
#include "net/http/url.h"
|
|
||||||
#include "net/https/https.h"
|
#include "net/https/https.h"
|
||||||
#include "third_party/getopt/getopt.h"
|
#include "third_party/getopt/getopt.h"
|
||||||
#include "third_party/linenoise/linenoise.h"
|
|
||||||
#include "third_party/lua/cosmo.h"
|
#include "third_party/lua/cosmo.h"
|
||||||
#include "third_party/lua/lauxlib.h"
|
#include "third_party/lua/lauxlib.h"
|
||||||
#include "third_party/lua/lrepl.h"
|
#include "third_party/lua/lrepl.h"
|
||||||
#include "third_party/lua/ltests.h"
|
|
||||||
#include "third_party/lua/lua.h"
|
|
||||||
#include "third_party/lua/luaconf.h"
|
|
||||||
#include "third_party/lua/lualib.h"
|
#include "third_party/lua/lualib.h"
|
||||||
#include "third_party/mbedtls/asn1.h"
|
|
||||||
#include "third_party/mbedtls/asn1write.h"
|
|
||||||
#include "third_party/mbedtls/cipher.h"
|
|
||||||
#include "third_party/mbedtls/config.h"
|
|
||||||
#include "third_party/mbedtls/ctr_drbg.h"
|
#include "third_party/mbedtls/ctr_drbg.h"
|
||||||
#include "third_party/mbedtls/debug.h"
|
#include "third_party/mbedtls/debug.h"
|
||||||
#include "third_party/mbedtls/ecp.h"
|
|
||||||
#include "third_party/mbedtls/entropy.h"
|
|
||||||
#include "third_party/mbedtls/entropy_poll.h"
|
|
||||||
#include "third_party/mbedtls/error.h"
|
|
||||||
#include "third_party/mbedtls/iana.h"
|
#include "third_party/mbedtls/iana.h"
|
||||||
#include "third_party/mbedtls/md.h"
|
|
||||||
#include "third_party/mbedtls/md5.h"
|
|
||||||
#include "third_party/mbedtls/net_sockets.h"
|
#include "third_party/mbedtls/net_sockets.h"
|
||||||
#include "third_party/mbedtls/oid.h"
|
#include "third_party/mbedtls/oid.h"
|
||||||
#include "third_party/mbedtls/pk.h"
|
|
||||||
#include "third_party/mbedtls/rsa.h"
|
|
||||||
#include "third_party/mbedtls/san.h"
|
#include "third_party/mbedtls/san.h"
|
||||||
#include "third_party/mbedtls/sha1.h"
|
|
||||||
#include "third_party/mbedtls/ssl.h"
|
#include "third_party/mbedtls/ssl.h"
|
||||||
#include "third_party/mbedtls/ssl_ticket.h"
|
#include "third_party/mbedtls/ssl_ticket.h"
|
||||||
#include "third_party/mbedtls/x509.h"
|
#include "third_party/mbedtls/x509.h"
|
||||||
#include "third_party/mbedtls/x509_crt.h"
|
#include "third_party/mbedtls/x509_crt.h"
|
||||||
#include "third_party/regex/regex.h"
|
|
||||||
#include "third_party/zlib/zlib.h"
|
#include "third_party/zlib/zlib.h"
|
||||||
#include "tool/args/args.h"
|
#include "tool/args/args.h"
|
||||||
#include "tool/build/lib/case.h"
|
#include "tool/build/lib/case.h"
|
||||||
#include "tool/build/lib/psk.h"
|
|
||||||
#include "tool/net/lfuncs.h"
|
#include "tool/net/lfuncs.h"
|
||||||
#include "tool/net/luacheck.h"
|
#include "tool/net/luacheck.h"
|
||||||
#include "tool/net/sandbox.h"
|
#include "tool/net/sandbox.h"
|
||||||
|
@ -441,12 +382,14 @@ static int mainpid;
|
||||||
static int sandboxed;
|
static int sandboxed;
|
||||||
static int changeuid;
|
static int changeuid;
|
||||||
static int changegid;
|
static int changegid;
|
||||||
static int monitortid;
|
|
||||||
static int isyielding;
|
static int isyielding;
|
||||||
static int statuscode;
|
static int statuscode;
|
||||||
static int shutdownsig;
|
static int shutdownsig;
|
||||||
static int sslpskindex;
|
static int sslpskindex;
|
||||||
static int oldloglevel;
|
static int oldloglevel;
|
||||||
|
static int *monitortid;
|
||||||
|
static char *monitortls;
|
||||||
|
static char *monitorstack;
|
||||||
static int maxpayloadsize;
|
static int maxpayloadsize;
|
||||||
static int messageshandled;
|
static int messageshandled;
|
||||||
static int sslticketlifetime;
|
static int sslticketlifetime;
|
||||||
|
@ -6393,7 +6336,7 @@ static int ExitWorker(void) {
|
||||||
}
|
}
|
||||||
if (monitortty) {
|
if (monitortty) {
|
||||||
terminatemonitor = true;
|
terminatemonitor = true;
|
||||||
_spinlock(&monitortid);
|
_spinlock(monitortid);
|
||||||
}
|
}
|
||||||
_Exit(0);
|
_Exit(0);
|
||||||
}
|
}
|
||||||
|
@ -6649,19 +6592,23 @@ static int MemoryMonitor(void *arg) {
|
||||||
}
|
}
|
||||||
|
|
||||||
static void MonitorMemory(void) {
|
static void MonitorMemory(void) {
|
||||||
char *tls;
|
if ((monitortls = __initialize_tls(malloc(64)))) {
|
||||||
monitortid = -1;
|
if ((monitorstack = mmap(0, GetStackSize(), PROT_READ | PROT_WRITE,
|
||||||
tls = __initialize_tls(malloc(64));
|
MAP_STACK | MAP_ANONYMOUS, -1, 0)) != MAP_FAILED) {
|
||||||
__cxa_atexit(free, tls, 0);
|
monitortid = (int *)(monitortls + 0x38);
|
||||||
if (clone(MemoryMonitor,
|
if ((*monitortid =
|
||||||
mmap(0, GetStackSize(), PROT_READ | PROT_WRITE,
|
clone(MemoryMonitor, monitorstack, GetStackSize(),
|
||||||
MAP_STACK | MAP_ANONYMOUS, -1, 0),
|
CLONE_VM | CLONE_THREAD | CLONE_FS | CLONE_FILES |
|
||||||
GetStackSize(),
|
CLONE_SIGHAND | CLONE_SETTLS | CLONE_CHILD_CLEARTID,
|
||||||
CLONE_VM | CLONE_THREAD | CLONE_FS | CLONE_FILES | CLONE_SIGHAND |
|
0, 0, monitortls, 64, monitortid)) != -1) {
|
||||||
CLONE_SETTLS | CLONE_CHILD_SETTID | CLONE_CHILD_CLEARTID,
|
return;
|
||||||
0, 0, tls, 64, &monitortid) == -1) {
|
|
||||||
monitortid = 0;
|
|
||||||
}
|
}
|
||||||
|
munmap(monitorstack, GetStackSize());
|
||||||
|
}
|
||||||
|
free(monitortls);
|
||||||
|
}
|
||||||
|
WARNF("(memv) failed to start memory monitor %m");
|
||||||
|
monitortty = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int HandleConnection(size_t i) {
|
static int HandleConnection(size_t i) {
|
||||||
|
@ -7327,7 +7274,9 @@ void RedBean(int argc, char *argv[]) {
|
||||||
}
|
}
|
||||||
if (monitortty) {
|
if (monitortty) {
|
||||||
terminatemonitor = true;
|
terminatemonitor = true;
|
||||||
_spinlock(&monitortid);
|
_spinlock(monitortid);
|
||||||
|
munmap(monitorstack, GetStackSize());
|
||||||
|
free(monitortls);
|
||||||
}
|
}
|
||||||
INFOF("(srvr) shutdown complete");
|
INFOF("(srvr) shutdown complete");
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue