mirror of
https://github.com/jart/cosmopolitan.git
synced 2025-03-02 23:18:44 +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/itoa.h"
|
||||
#include "libc/intrin/kprintf.h"
|
||||
#include "libc/limits.h"
|
||||
#include "libc/log/check.h"
|
||||
#include "libc/log/log.h"
|
||||
#include "libc/macros.internal.h"
|
||||
|
@ -96,11 +97,12 @@
|
|||
"Referrer-Policy: origin\r\n" \
|
||||
"Cache-Control: private; max-age=0\r\n"
|
||||
|
||||
int workers;
|
||||
int messages;
|
||||
int connections;
|
||||
const char *status;
|
||||
_Atomic(int) workers;
|
||||
_Atomic(int) messages;
|
||||
_Atomic(int) listening;
|
||||
_Atomic(int) connections;
|
||||
_Atomic(int) closingtime;
|
||||
const char *volatile status;
|
||||
|
||||
int Worker(void *id) {
|
||||
int server, yes = 1;
|
||||
|
@ -132,6 +134,7 @@ int Worker(void *id) {
|
|||
listen(server, 1);
|
||||
|
||||
// connection loop
|
||||
++listening;
|
||||
while (!closingtime) {
|
||||
struct tm tm;
|
||||
int64_t unixts;
|
||||
|
@ -167,7 +170,7 @@ int Worker(void *id) {
|
|||
continue;
|
||||
}
|
||||
|
||||
asm volatile("lock incl\t%0" : "+m"(connections));
|
||||
++connections;
|
||||
|
||||
// message loop
|
||||
do {
|
||||
|
@ -177,12 +180,12 @@ int Worker(void *id) {
|
|||
if ((got = read(client, inbuf, sizeof(inbuf))) <= 0) break;
|
||||
// check that client message wasn't fragmented into more reads
|
||||
if (!(inmsglen = ParseHttpMessage(&msg, inbuf, got))) break;
|
||||
asm volatile("lock incl\t%0" : "+m"(messages));
|
||||
++messages;
|
||||
|
||||
#if LOGGING
|
||||
// log the incoming http message
|
||||
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 & 0x0000ff00) >> 010, (clientip & 0x000000ff) >> 000,
|
||||
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
|
||||
"Content-Type: text/html; charset=utf-8\r\n"
|
||||
"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 = stpcpy(p, "\r\nContent-Length: ");
|
||||
p = FormatInt32(p, strlen(q));
|
||||
|
@ -218,7 +221,7 @@ int Worker(void *id) {
|
|||
"HTTP/1.1 404 Not Found\r\n" STANDARD_RESPONSE_HEADERS
|
||||
"Content-Type: text/html; charset=utf-8\r\n"
|
||||
"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 = stpcpy(p, "\r\nContent-Length: ");
|
||||
p = FormatInt32(p, strlen(q));
|
||||
|
@ -238,13 +241,14 @@ int Worker(void *id) {
|
|||
(msg.method == kHttpGet || msg.method == kHttpHead));
|
||||
DestroyHttpMessage(&msg);
|
||||
close(client);
|
||||
asm volatile("lock decl\t%0" : "+m"(connections));
|
||||
--connections;
|
||||
}
|
||||
--listening;
|
||||
|
||||
// inform the parent that this clone has finished
|
||||
WorkerFinished:
|
||||
close(server);
|
||||
asm volatile("lock decl\t%0" : "+m"(workers));
|
||||
--workers;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -253,35 +257,85 @@ void OnCtrlC(int sig) {
|
|||
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[]) {
|
||||
char **tls;
|
||||
char **stack;
|
||||
int i, threads;
|
||||
uint32_t *hostips;
|
||||
// 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) {
|
||||
kprintf("listening on http://%d.%d.%d.%d:%d\n",
|
||||
(hostips[i] & 0xff000000) >> 030, (hostips[i] & 0x00ff0000) >> 020,
|
||||
(hostips[i] & 0x0000ff00) >> 010, (hostips[i] & 0x000000ff) >> 000,
|
||||
PORT);
|
||||
}
|
||||
threads = argc > 1 ? atoi(argv[1]) : 0;
|
||||
if (!threads) threads = GetCpuCount();
|
||||
workers = threads;
|
||||
for (i = 0; i < threads; ++i) {
|
||||
char *tls = __initialize_tls(malloc(64));
|
||||
void *stack = mmap(0, GetStackSize(), PROT_READ | PROT_WRITE,
|
||||
MAP_STACK | MAP_ANONYMOUS, -1, 0);
|
||||
CHECK_NE(-1, clone(Worker, stack, GetStackSize(),
|
||||
CLONE_THREAD | CLONE_VM | CLONE_FS | CLONE_FILES |
|
||||
CLONE_SIGHAND | CLONE_SETTLS,
|
||||
(void *)(intptr_t)i, 0, tls, 64, 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();
|
||||
for (i = 0; i < threads; ++i) {
|
||||
if ((tls[i] = __initialize_tls(malloc(64))) &&
|
||||
(stack[i] = mmap(0, GetStackSize(), PROT_READ | PROT_WRITE,
|
||||
MAP_STACK | MAP_ANONYMOUS, -1, 0)) != MAP_FAILED) {
|
||||
++workers;
|
||||
if (clone(Worker, stack[i], GetStackSize(),
|
||||
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)) == -1) {
|
||||
--workers;
|
||||
kprintf("error: clone(%d) failed %m\n", i);
|
||||
}
|
||||
} else {
|
||||
kprintf("error: mmap(%d) failed %m\n", i);
|
||||
}
|
||||
if (!(i % 500)) {
|
||||
PrintStatus();
|
||||
}
|
||||
}
|
||||
} else {
|
||||
kprintf("error: invalid number of threads\n");
|
||||
}
|
||||
status = "";
|
||||
|
||||
// wait for workers to terminate
|
||||
while (workers) {
|
||||
kprintf(
|
||||
"\r\e[K\e[32mgreenbean\e[0m workers=%d connections=%d messages=%d%s ",
|
||||
workers, connections, messages, status);
|
||||
PrintStatus();
|
||||
usleep(HEARTBEAT * 1000);
|
||||
}
|
||||
|
||||
// clean up terminal line
|
||||
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 gethostname(char *, size_t);
|
||||
int getloadavg(double *, int);
|
||||
int getpgid(int);
|
||||
int getpgid(int) nosideeffect libcesque;
|
||||
int getpgrp(void) nosideeffect;
|
||||
int getpid(void);
|
||||
int getpid(void) nosideeffect libcesque;
|
||||
int getppid(void);
|
||||
int getpriority(int, unsigned);
|
||||
int getresgid(uint32_t *, uint32_t *, uint32_t *);
|
||||
int getresuid(uint32_t *, uint32_t *, uint32_t *);
|
||||
int getrlimit(int, struct rlimit *);
|
||||
int getrusage(int, struct rusage *);
|
||||
int getsid(int) nosideeffect;
|
||||
int gettid(void);
|
||||
int getuid(void) nosideeffect;
|
||||
int getsid(int) nosideeffect libcesque;
|
||||
int gettid(void) libcesque;
|
||||
int getuid(void) nosideeffect libcesque;
|
||||
int kill(int, int);
|
||||
int killpg(int, int);
|
||||
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.
|
||||
*/
|
||||
void *__get_clock_gettime(void) {
|
||||
// TODO(jart): Re-enable this.
|
||||
return 0;
|
||||
void *vdso;
|
||||
static bool once;
|
||||
static void *result;
|
||||
|
|
|
@ -24,6 +24,7 @@
|
|||
#include "libc/nt/console.h"
|
||||
#include "libc/nt/enum/consolemodeflags.h"
|
||||
#include "libc/nt/enum/version.h"
|
||||
#include "libc/nt/version.h"
|
||||
#include "libc/sysv/consts/o.h"
|
||||
#include "libc/sysv/consts/termios.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)) {
|
||||
inmode |= kNtEnableProcessedInput;
|
||||
}
|
||||
if (NtGetVersion() >= kNtVersionWindows10) {
|
||||
if (IsAtLeastWindows10()) {
|
||||
inmode |= kNtEnableVirtualTerminalInput;
|
||||
}
|
||||
ok = SetConsoleMode(in, inmode);
|
||||
|
@ -71,7 +72,7 @@ textwindows int ioctl_tcsets_nt(int ignored, uint64_t request,
|
|||
if (!(tio->c_oflag & ONLCR)) {
|
||||
outmode |= kNtDisableNewlineAutoReturn;
|
||||
}
|
||||
if (NtGetVersion() >= kNtVersionWindows10) {
|
||||
if (IsAtLeastWindows10()) {
|
||||
outmode |= kNtEnableVirtualTerminalProcessing;
|
||||
}
|
||||
ok = SetConsoleMode(out, outmode);
|
||||
|
|
|
@ -16,17 +16,13 @@
|
|||
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/bits/weaken.h"
|
||||
#include "libc/calls/calls.h"
|
||||
#include "libc/calls/internal.h"
|
||||
#include "libc/calls/struct/metastat.internal.h"
|
||||
#include "libc/calls/struct/stat.h"
|
||||
#include "libc/dce.h"
|
||||
#include "libc/errno.h"
|
||||
#include "libc/nt/enum/filetype.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.
|
||||
|
@ -44,15 +40,7 @@ bool32 ischardev(int fd) {
|
|||
int e;
|
||||
union metastat st;
|
||||
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()) {
|
||||
return true;
|
||||
} else if (!IsWindows()) {
|
||||
|
|
|
@ -97,7 +97,8 @@ static long double nowl_vdso(void) {
|
|||
|
||||
long double nowl_setup(void) {
|
||||
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;
|
||||
} else if (X86_HAVE(INVTSC)) {
|
||||
RefreshTime();
|
||||
|
@ -107,5 +108,3 @@ long double nowl_setup(void) {
|
|||
}
|
||||
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 -*-│
|
||||
│vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi│
|
||||
/*-*- 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 │
|
||||
│ │
|
||||
|
@ -16,13 +16,14 @@
|
|||
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/calls/calls.h"
|
||||
#include "libc/macros.internal.h"
|
||||
|
||||
/**
|
||||
* Maximum amount of virtual memory in bytes.
|
||||
*
|
||||
* mmap() will return ENOMEM once this is reached.
|
||||
*
|
||||
* By default no limit is imposed.
|
||||
*/
|
||||
size_t __virtualmax = -1;
|
||||
.initbss 201,_init_nowl
|
||||
nowl: .quad 0
|
||||
.endobj nowl,globl
|
||||
.previous
|
||||
|
||||
.init.start 201,_init_nowl
|
||||
ezlea nowl_setup,ax
|
||||
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,
|
||||
struct itimerval *out_opt_oldvalue) {
|
||||
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 (__hastimer) {
|
||||
elapsed = nowl() - __lastalrm;
|
||||
|
|
|
@ -48,7 +48,7 @@ static inline textwindows noasan int NtGetBuildNumber(void) {
|
|||
* @return 0 on success, or -1 w/ errno
|
||||
*/
|
||||
int uname(struct utsname *lool) {
|
||||
int rc, v;
|
||||
int rc;
|
||||
char *out, *p;
|
||||
size_t i, j, len;
|
||||
char tmp[sizeof(struct utsname)];
|
||||
|
@ -87,7 +87,6 @@ int uname(struct utsname *lool) {
|
|||
rc = enosys();
|
||||
}
|
||||
} else {
|
||||
v = NtGetVersion();
|
||||
p = lool->release;
|
||||
p = FormatUint32(p, NtGetMajorVersion()), *p++ = '.';
|
||||
p = FormatUint32(p, NtGetMinorVersion()), *p++ = '-';
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
/*-*- 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 2020 Justine Alexandra Roberts Tunney │
|
||||
│ 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 │
|
||||
|
@ -18,16 +18,20 @@
|
|||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#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
|
||||
// @return 0 on success or -1 w/ errno
|
||||
// @see fflush_unlocked()
|
||||
// @threadsafe
|
||||
fflush: ezlea fflush_unlocked,ax
|
||||
test %rdi,%rdi
|
||||
jz 1f
|
||||
mov %rdi,%r11
|
||||
jmp stdio_unlock
|
||||
1: jmp *%rax
|
||||
.endfn fflush,globl
|
||||
// mmap() will return ENOMEM once this is reached.
|
||||
//
|
||||
// By default no limit is imposed.
|
||||
__virtualmax:
|
||||
.quad 0
|
||||
.endobj __virtualmax,globl
|
||||
.previous
|
||||
|
||||
.init.start 201,_init___virtualmax
|
||||
push $-1
|
||||
pop %rax
|
||||
stosq
|
||||
.init.end 201,_init___virtualmax
|
|
@ -199,7 +199,7 @@ static char *__asan_utf8cpy(char *p, unsigned c) {
|
|||
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;
|
||||
size_t i;
|
||||
uint64_t x;
|
||||
|
@ -207,29 +207,29 @@ static void *__asan_memset(void *p, char c, size_t n) {
|
|||
x = 0x0101010101010101ul * (c & 255);
|
||||
switch (n) {
|
||||
case 0:
|
||||
return p;
|
||||
break;
|
||||
case 1:
|
||||
__builtin_memcpy(b, &x, 1);
|
||||
return p;
|
||||
break;
|
||||
case 2:
|
||||
__builtin_memcpy(b, &x, 2);
|
||||
return p;
|
||||
break;
|
||||
case 3:
|
||||
__builtin_memcpy(b, &x, 2);
|
||||
__builtin_memcpy(b + 1, &x, 2);
|
||||
return p;
|
||||
break;
|
||||
case 4:
|
||||
__builtin_memcpy(b, &x, 4);
|
||||
return p;
|
||||
break;
|
||||
case 5:
|
||||
case 6:
|
||||
case 7:
|
||||
__builtin_memcpy(b, &x, 4);
|
||||
__builtin_memcpy(b + n - 4, &x, 4);
|
||||
return p;
|
||||
break;
|
||||
case 8:
|
||||
__builtin_memcpy(b, &x, 8);
|
||||
return p;
|
||||
break;
|
||||
case 9:
|
||||
case 10:
|
||||
case 11:
|
||||
|
@ -240,7 +240,7 @@ static void *__asan_memset(void *p, char c, size_t n) {
|
|||
case 16:
|
||||
__builtin_memcpy(b, &x, 8);
|
||||
__builtin_memcpy(b + n - 8, &x, 8);
|
||||
return p;
|
||||
break;
|
||||
default:
|
||||
if (n <= 64) {
|
||||
i = 0;
|
||||
|
@ -253,83 +253,10 @@ static void *__asan_memset(void *p, char c, size_t n) {
|
|||
} else {
|
||||
__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) {
|
||||
while (k) *p++ = "0123456789abcdef"[(x >> (k -= 4)) & 15];
|
||||
return p;
|
||||
|
@ -736,7 +663,7 @@ static void __asan_report_memory_origin(const unsigned char *addr, int size,
|
|||
if (_base <= addr && addr < _end) {
|
||||
__asan_report_memory_origin_image((intptr_t)addr, size);
|
||||
} else if (IsAutoFrame((intptr_t)addr >> 16)) {
|
||||
/* __asan_report_memory_origin_heap(addr, size); */
|
||||
__asan_report_memory_origin_heap(addr, size);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -946,8 +873,8 @@ static void __asan_trace(struct AsanTrace *bt, const struct StackFrame *bp) {
|
|||
|
||||
#define __asan_trace __asan_rawtrace
|
||||
|
||||
static void *__asan_allocate(size_t a, size_t n, int underrun, int overrun,
|
||||
struct AsanTrace *bt) {
|
||||
void *__asan_allocate(size_t a, size_t n, int underrun, int overrun,
|
||||
struct AsanTrace *bt) {
|
||||
char *p;
|
||||
size_t c;
|
||||
struct AsanExtra *e;
|
||||
|
@ -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_memset(p, 0xF9, n);
|
||||
__asan_write48(&e->size, n);
|
||||
__asan_memcpy(&e->bt, bt, sizeof(*bt));
|
||||
__builtin_memcpy(&e->bt, bt, sizeof(*bt));
|
||||
}
|
||||
return p;
|
||||
}
|
||||
|
@ -1082,7 +1009,7 @@ static void *__asan_realloc_grow(void *p, size_t n, size_t m,
|
|||
struct AsanTrace *bt) {
|
||||
char *q;
|
||||
if ((q = __asan_allocate(16, n, kAsanHeapUnderrun, kAsanHeapOverrun, bt))) {
|
||||
__asan_memcpy(q, p, m);
|
||||
__builtin_memcpy(q, p, m);
|
||||
__asan_deallocate(p, kAsanHeapRelocated);
|
||||
}
|
||||
return q;
|
||||
|
|
|
@ -46,7 +46,6 @@ relegated wontreturn void __assert_fail(const char *expr, const char *file,
|
|||
} else {
|
||||
rc = 24;
|
||||
}
|
||||
if (weaken(__die)) weaken(__die)();
|
||||
__restorewintty();
|
||||
_Exit(rc);
|
||||
}
|
||||
|
|
|
@ -23,6 +23,7 @@ const char *DescribeMapFlags(int);
|
|||
const char *DescribeProtFlags(int);
|
||||
const char *DescribeRemapFlags(int);
|
||||
const char *DescribeRlimitName(int);
|
||||
const char *DescribePersonalityFlags(int);
|
||||
const char *DescribeSeccompOperationFlags(int);
|
||||
const char *DescribePollFlags(char *, size_t, int);
|
||||
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.
|
||||
*
|
||||
* 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
|
||||
* @threadsafe
|
||||
* @vforksafe
|
||||
*/
|
||||
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
|
||||
* 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
|
||||
* @asyncsignalsafe
|
||||
* @threadsafe
|
||||
*/
|
||||
privileged int gettid(void) {
|
||||
int rc;
|
||||
|
@ -42,9 +59,7 @@ privileged int gettid(void) {
|
|||
|
||||
if (__tls_enabled) {
|
||||
rc = *(int *)(__get_tls() + 0x38);
|
||||
if (rc && rc != -1) {
|
||||
return rc;
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
|
||||
if (IsWindows()) {
|
||||
|
|
|
@ -46,9 +46,14 @@ $(LIBC_INTRIN_A_OBJS): \
|
|||
OVERRIDE_CFLAGS += \
|
||||
-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/ubsan.o: \
|
||||
OVERRIDE_CFLAGS += \
|
||||
-ffreestanding \
|
||||
-fno-sanitize=all \
|
||||
-fno-stack-protector
|
||||
|
||||
|
@ -145,12 +150,6 @@ o/$(MODE)/libc/intrin/describeopenflags.greg.o: \
|
|||
OVERRIDE_CPPFLAGS += \
|
||||
-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: \
|
||||
OVERRIDE_CFLAGS += \
|
||||
-fno-toplevel-reorder
|
||||
|
|
|
@ -857,7 +857,6 @@ privileged void kvprintf(const char *fmt, va_list v) {
|
|||
*
|
||||
* Specifiers:
|
||||
*
|
||||
* - `P` pid
|
||||
* - `c` char
|
||||
* - `o` octal
|
||||
* - `b` binary
|
||||
|
@ -873,6 +872,7 @@ privileged void kvprintf(const char *fmt, va_list v) {
|
|||
* - `X` uppercase
|
||||
* - `T` timestamp
|
||||
* - `x` hexadecimal
|
||||
* - `P` pid (or tid if threaded)
|
||||
*
|
||||
* Types:
|
||||
*
|
||||
|
|
|
@ -22,9 +22,9 @@
|
|||
/**
|
||||
* Returns New Technology version, e.g.
|
||||
*
|
||||
* if (IsWindows() && NtGetVersion() >=k NtVersionWindows10) {...}
|
||||
*
|
||||
* This can only be called on Windows.
|
||||
*
|
||||
* @see IsAtLeastWindows10()
|
||||
*/
|
||||
textwindows noasan int NtGetVersion(void) {
|
||||
return (NtGetPeb()->OSMajorVersion & 0xff) << 8 | NtGetPeb()->OSMinorVersion;
|
||||
|
|
|
@ -25,16 +25,8 @@
|
|||
//
|
||||
// @return 0 on success, or -1 w/ errno
|
||||
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
|
||||
//
|
||||
// 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
|
||||
// returns immediately, and the thread continues execution.
|
||||
// ──Quoth MSDN
|
||||
1: xor %ecx,%ecx
|
||||
testb IsWindows()
|
||||
jz 1f
|
||||
push %rbp
|
||||
mov %rsp,%rbp
|
||||
xor %ecx,%ecx
|
||||
xor %edx,%edx
|
||||
ntcall __imp_SleepEx
|
||||
xor %eax,%eax
|
||||
|
||||
2: pop %rbp
|
||||
pop %rbp
|
||||
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
|
||||
.previous
|
||||
|
|
|
@ -44,23 +44,28 @@
|
|||
* 0x003c 0x04 errno
|
||||
*
|
||||
*/
|
||||
privileged void *__initialize_tls(char tib[hasatleast 64]) {
|
||||
*(intptr_t *)tib = (intptr_t)tib;
|
||||
*(intptr_t *)(tib + 0x08) = 0;
|
||||
*(int *)(tib + 0x10) = -1; // exit code
|
||||
*(intptr_t *)(tib + 0x30) = (intptr_t)tib;
|
||||
*(int *)(tib + 0x38) = -1; // tid
|
||||
*(int *)(tib + 0x3c) = __errno;
|
||||
privileged void *__initialize_tls(char tib[64]) {
|
||||
if (tib) {
|
||||
*(intptr_t *)tib = (intptr_t)tib;
|
||||
*(intptr_t *)(tib + 0x08) = 0;
|
||||
*(int *)(tib + 0x10) = -1; // exit code
|
||||
*(intptr_t *)(tib + 0x30) = (intptr_t)tib;
|
||||
*(int *)(tib + 0x38) = -1; // tid
|
||||
*(int *)(tib + 0x3c) = 0;
|
||||
}
|
||||
return tib;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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;
|
||||
uint64_t magic;
|
||||
unsigned char *p;
|
||||
assert(tib);
|
||||
assert(!__tls_enabled);
|
||||
assert(*(int *)(tib + 0x38) != -1);
|
||||
if (IsWindows()) {
|
||||
if (!__tls_index) {
|
||||
__tls_index = TlsAlloc();
|
||||
|
|
|
@ -8,8 +8,8 @@ extern bool __threaded;
|
|||
extern bool __tls_enabled;
|
||||
extern unsigned __tls_index;
|
||||
|
||||
void *__initialize_tls(char[hasatleast 64]);
|
||||
void __install_tls(char[hasatleast 64]);
|
||||
void *__initialize_tls(char[64]);
|
||||
void __install_tls(char[64]);
|
||||
|
||||
#if defined(__GNUC__) && defined(__x86_64__) && !defined(__STRICT_ANSI__)
|
||||
/**
|
||||
|
|
|
@ -4,17 +4,18 @@
|
|||
|
||||
/**
|
||||
* Known versions of the New Technology executive.
|
||||
* @see IsAtLeastWindows10()
|
||||
* @see NtGetVersion()
|
||||
*/
|
||||
#define kNtVersionWindows10 0x0a00
|
||||
#define kNtVersionWindows81 0x0603
|
||||
#define kNtVersionWindows8 0x0602
|
||||
#define kNtVersionWindows7 0x0601
|
||||
#define kNtVersionWindows10 0x0a00
|
||||
#define kNtVersionWindows81 0x0603
|
||||
#define kNtVersionWindows8 0x0602
|
||||
#define kNtVersionWindows7 0x0601
|
||||
#define kNtVersionWindowsVista 0x0600 /* intended baseline */
|
||||
#define kNtVersionWindowsXp64 0x0502 /* end of the road */
|
||||
#define kNtVersionWindowsXp 0x0501 /* snowball's chance */
|
||||
#define kNtVersionWindows2000 0x0500 /* the golden age */
|
||||
#define kNtVersionFuture 0x0b00
|
||||
#define kNtVersionWindowsXp64 0x0502 /* end of the road */
|
||||
#define kNtVersionWindowsXp 0x0501 /* snowball's chance */
|
||||
#define kNtVersionWindows2000 0x0500 /* the golden age */
|
||||
#define kNtVersionFuture 0x0b00
|
||||
|
||||
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
|
||||
#endif /* COSMOPOLITAN_LIBC_NT_ENUM_VERSION_H_ */
|
||||
|
|
|
@ -8,16 +8,14 @@ bool IsAtLeastWindows10(void) pureconst;
|
|||
bool32 GetVersionEx(struct NtOsVersionInfo *lpVersionInformation);
|
||||
|
||||
#if defined(__GCC_ASM_FLAG_OUTPUTS__) && !defined(__STRICT_ANSI__)
|
||||
#define IsAtLeastWindows10() \
|
||||
({ \
|
||||
long ReG; \
|
||||
bool NoTbelow; \
|
||||
asm("mov\t%%gs:96,%1\r\n" \
|
||||
"cmpb\t%2,280(%1)" \
|
||||
: "=@ccnb"(NoTbelow), "=l"(ReG) \
|
||||
: "i"(10)); \
|
||||
NoTbelow; \
|
||||
})
|
||||
#define IsAtLeastWindows10() (GetNtMajorVersion() >= 10)
|
||||
static pureconst inline unsigned char GetNtMajorVersion(void) {
|
||||
uintptr_t _x;
|
||||
asm("mov\t%%gs:96,%q0\r\n"
|
||||
"mov\t280(%q0),%b0"
|
||||
: "=q"(_x));
|
||||
return _x;
|
||||
}
|
||||
#endif
|
||||
|
||||
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
|
||||
|
||||
int CloneLinux(int (*func)(void *), char *stk, size_t stksz, int flags,
|
||||
void *arg, int *ptid, void *tls, size_t tlssz, int *ctid) {
|
||||
#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
|
||||
}
|
||||
int sys_clone_linux(int flags, char *stk, int *ptid, int *ctid, void *tls,
|
||||
int (*func)(void *), void *arg);
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// COSMOPOLITAN
|
||||
|
@ -542,13 +510,23 @@ int clone(int (*func)(void *), void *stk, size_t stksz, int flags, void *arg,
|
|||
int rc;
|
||||
struct CloneArgs *wt;
|
||||
|
||||
if (flags & CLONE_THREAD) {
|
||||
__threaded = true;
|
||||
}
|
||||
|
||||
// transition program to threaded state
|
||||
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);
|
||||
*(int *)((char *)tibdefault + 0x38) = gettid();
|
||||
*(int *)((char *)tibdefault + 0x3c) = __errno;
|
||||
__install_tls(tibdefault);
|
||||
__threaded = true;
|
||||
} else if (flags & CLONE_THREAD) {
|
||||
__threaded = true;
|
||||
}
|
||||
|
||||
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))))) {
|
||||
rc = einval();
|
||||
} 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() &&
|
||||
(flags & ~(CLONE_SETTLS | CLONE_PARENT_SETTID |
|
||||
CLONE_CHILD_SETTID | CLONE_CHILD_CLEARTID)) !=
|
||||
|
|
|
@ -26,7 +26,9 @@
|
|||
* @assume stack addresses are always greater than heap addresses
|
||||
* @assume stack memory isn't stored beneath %rsp (-mno-red-zone)
|
||||
*/
|
||||
noasan bool _isheap(void *p) {
|
||||
return kAutomapStart <= (intptr_t)p &&
|
||||
(intptr_t)p < kAutomapStart + kAutomapSize;
|
||||
optimizesize noasan bool _isheap(void *p) {
|
||||
intptr_t x, y;
|
||||
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/dce.h"
|
||||
#include "libc/macros.internal.h"
|
||||
#include "libc/nt/enum/version.h"
|
||||
#include "libc/runtime/runtime.h"
|
||||
#include "libc/nt/version.h"
|
||||
#include "libc/runtime/stack.h"
|
||||
#include "libc/sysv/consts/ss.h"
|
||||
#if !(__ASSEMBLER__ + __LINKER__ + 0)
|
||||
|
@ -29,7 +28,7 @@ COSMOPOLITAN_C_START_
|
|||
ROUNDUP(VSPACE / FRAMESIZE * (intptr_t)sizeof(struct MemoryInterval), \
|
||||
FRAMESIZE)
|
||||
#define _kMem(NORMAL, WIN7) \
|
||||
(!(IsWindows() && NtGetVersion() < kNtVersionWindows10) ? NORMAL : WIN7)
|
||||
(!IsWindows() || IsAtLeastWindows10() ? NORMAL : WIN7)
|
||||
|
||||
struct MemoryInterval {
|
||||
int x;
|
||||
|
|
|
@ -16,59 +16,11 @@
|
|||
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/bits/pushpop.h"
|
||||
#include "libc/nt/enum/version.h"
|
||||
#include "libc/nt/runtime.h"
|
||||
#include "libc/intrin/kprintf.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"
|
||||
|
||||
/**
|
||||
* Aborts program under enemy fire to avoid being taken alive.
|
||||
*/
|
||||
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);
|
||||
}
|
||||
privileged noasan noinstrument void __stack_chk_fail(void) {
|
||||
kprintf("stack smashed\n");
|
||||
__restorewintty();
|
||||
_Exit(207);
|
||||
}
|
||||
|
|
|
@ -39,6 +39,7 @@ int fclose(FILE *f) {
|
|||
if (!f) return 0;
|
||||
__fflush_unregister(f);
|
||||
fflush(f);
|
||||
free_s(&f->getln);
|
||||
if (!f->nofree) {
|
||||
free_s(&f->buf);
|
||||
}
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
/*-*- 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 │
|
||||
│ 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 │
|
||||
│ 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
|
||||
* @threadsafe
|
||||
*/
|
||||
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 fflush(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);
|
||||
if (f) flockfile(f);
|
||||
rc = fflush_unlocked(f);
|
||||
if (f) funlockfile(f);
|
||||
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/errno.h"
|
||||
#include "libc/runtime/runtime.h"
|
||||
#include "libc/stdio/internal.h"
|
||||
#include "libc/sysv/consts/o.h"
|
||||
|
||||
int __fflush_impl(FILE *f) {
|
||||
size_t i;
|
||||
ssize_t rc;
|
||||
free_s(&f->getln);
|
||||
if (f->beg && !f->end && (f->iomode & O_ACCMODE) != O_RDONLY) {
|
||||
for (i = 0; i < f->beg; i += rc) {
|
||||
if ((rc = write(f->fd, f->buf + i, f->beg - i)) == -1) {
|
||||
|
|
|
@ -18,13 +18,35 @@
|
|||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#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 *res;
|
||||
ssize_t rc;
|
||||
size_t n = 0;
|
||||
if ((rc = getdelim(&stream->getln, &n, '\n', stream)) > 0) {
|
||||
*len = rc;
|
||||
return stream->getln;
|
||||
flockfile(stream);
|
||||
if ((rc = getdelim_unlocked(&stream->getln, &n, '\n', stream)) > 0) {
|
||||
if (len) *len = rc;
|
||||
res = stream->getln;
|
||||
} else {
|
||||
return 0;
|
||||
res = 0;
|
||||
}
|
||||
funlockfile(stream);
|
||||
return res;
|
||||
}
|
||||
|
|
|
@ -28,16 +28,18 @@
|
|||
void flockfile(FILE *f) {
|
||||
int me, owner;
|
||||
unsigned tries;
|
||||
if (!__threaded) return;
|
||||
for (tries = 0, me = gettid();;) {
|
||||
owner = 0;
|
||||
if (_lockcmpxchgp(&f->lock, &owner, me) || owner == me) {
|
||||
return;
|
||||
}
|
||||
if (++tries & 7) {
|
||||
__builtin_ia32_pause();
|
||||
} else {
|
||||
sched_yield();
|
||||
if (__threaded) {
|
||||
for (tries = 0, me = gettid();;) {
|
||||
owner = 0;
|
||||
if (_lockcmpxchgp(&f->lock, &owner, me) || owner == me) {
|
||||
break;
|
||||
}
|
||||
if (++tries & 7) {
|
||||
__builtin_ia32_pause();
|
||||
} else {
|
||||
sched_yield();
|
||||
}
|
||||
}
|
||||
}
|
||||
++f->reent;
|
||||
}
|
||||
|
|
|
@ -29,7 +29,7 @@ int fputc_unlocked(int c, FILE *f) {
|
|||
unsigned char b;
|
||||
if (c != '\n' && f->beg < f->size && f->bufmode != _IONBF) {
|
||||
f->buf[f->beg++] = c;
|
||||
return c & 0xff;
|
||||
return c & 255;
|
||||
} else {
|
||||
b = c;
|
||||
if (!fwrite_unlocked(&b, 1, 1, f)) return -1;
|
||||
|
|
|
@ -34,5 +34,8 @@ int ftrylockfile(FILE *f) {
|
|||
owner = 0;
|
||||
}
|
||||
}
|
||||
if (!owner) {
|
||||
++f->reent;
|
||||
}
|
||||
return owner;
|
||||
}
|
||||
|
|
|
@ -16,12 +16,24 @@
|
|||
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
||||
│ 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"
|
||||
|
||||
/**
|
||||
* Releases lock on stdio object.
|
||||
*/
|
||||
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 │
|
||||
│ 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/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
|
||||
* 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)
|
||||
* @return number of bytes read >0, including delim, excluding NUL,
|
||||
* or -1 w/ errno on EOF or error; see ferror() and feof()
|
||||
* @note this function can't punt EINTR to caller
|
||||
* @see getline(), _chomp(), gettok_r()
|
||||
* @note this function will ignore EINTR if it occurs mid-line
|
||||
* @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 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"
|
||||
|
||||
/**
|
||||
* 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
|
||||
* documentation. Concerning lines, please note the \n or \r\n are
|
||||
|
@ -30,7 +38,7 @@
|
|||
* NUL-termination is guaranteed FTMP
|
||||
* @return number of bytes read, including delim, excluding NUL, or -1
|
||||
* 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) {
|
||||
return getdelim(line, n, '\n', f);
|
||||
|
|
|
@ -25,7 +25,8 @@ typedef struct FILE {
|
|||
uint32_t nofree; /* 0x24 */
|
||||
int pid; /* 0x28 */
|
||||
int lock; /* 0x2c */
|
||||
char *getln; /* 0x30 */
|
||||
int reent; /* 0x30 */
|
||||
char *getln; /* 0x38 */
|
||||
} FILE;
|
||||
|
||||
extern FILE *stdin;
|
||||
|
@ -39,6 +40,7 @@ int getc(FILE *) paramsnonnull();
|
|||
int putc(int, FILE *) paramsnonnull();
|
||||
int fflush(FILE *);
|
||||
int fgetc(FILE *) paramsnonnull();
|
||||
char *fgetln(FILE *, size_t *) paramsnonnull((1));
|
||||
int ungetc(int, FILE *) paramsnonnull();
|
||||
int fileno(FILE *) paramsnonnull() nosideeffect;
|
||||
int fputc(int, FILE *) paramsnonnull();
|
||||
|
@ -120,9 +122,9 @@ int fwide(FILE *, int);
|
|||
│ cosmopolitan § standard i/o » without mutexes ─╬─│┼
|
||||
╚────────────────────────────────────────────────────────────────────────────│*/
|
||||
|
||||
void flockfile(FILE *);
|
||||
void funlockfile(FILE *);
|
||||
int ftrylockfile(FILE *);
|
||||
void flockfile(FILE *) paramsnonnull();
|
||||
void funlockfile(FILE *) paramsnonnull();
|
||||
int ftrylockfile(FILE *) paramsnonnull();
|
||||
int getc_unlocked(FILE *) paramsnonnull();
|
||||
int getchar_unlocked(void);
|
||||
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();
|
||||
int ungetc_unlocked(int, FILE *) 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)
|
||||
paramsnonnull((1, 2)) dontthrow nocallback;
|
||||
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_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_SYN 2 2 2 2 2 2 # 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_
|
||||
#define COSMOPOLITAN_LIBC_SYSV_CONSTS_PERSONALITY_H_
|
||||
#include "libc/runtime/symbolic.h"
|
||||
#if !(__ASSEMBLER__ + __LINKER__ + 0)
|
||||
COSMOPOLITAN_C_START_
|
||||
|
||||
extern const long ADDR_COMPAT_LAYOUT;
|
||||
extern const long READ_IMPLIES_EXEC;
|
||||
extern const long ADDR_LIMIT_3GB;
|
||||
extern const long FDPIC_FUNCPTRS;
|
||||
extern const long STICKY_TIMEOUTS;
|
||||
extern const long MMAP_PAGE_ZERO;
|
||||
extern const long ADDR_LIMIT_32BIT;
|
||||
extern const long WHOLE_SECONDS;
|
||||
extern const long ADDR_NO_RANDOMIZE;
|
||||
extern const long SHORT_INODE;
|
||||
extern const long UNAME26;
|
||||
|
||||
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)
|
||||
#define ADDR_COMPAT_LAYOUT 0x0200000
|
||||
#define READ_IMPLIES_EXEC 0x0400000
|
||||
#define ADDR_LIMIT_3GB 0x8000000
|
||||
#define FDPIC_FUNCPTRS 0x0080000
|
||||
#define STICKY_TIMEOUTS 0x4000000
|
||||
#define MMAP_PAGE_ZERO 0x0100000
|
||||
#define ADDR_LIMIT_32BIT 0x0800000
|
||||
#define WHOLE_SECONDS 0x2000000
|
||||
#define ADDR_NO_RANDOMIZE 0x0040000
|
||||
#define SHORT_INODE 0x1000000
|
||||
#define UNAME26 0x0020000
|
||||
|
||||
#endif /* COSMOPOLITAN_LIBC_SYSV_CONSTS_PERSONALITY_H_ */
|
||||
|
|
|
@ -55,6 +55,18 @@ TEST(open, enametoolong) {
|
|||
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) {
|
||||
char buf[8] = {0};
|
||||
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_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));
|
||||
}
|
||||
|
||||
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) {
|
||||
|
|
|
@ -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(&__errno, __errno_location());
|
||||
__initialize_tls(tib);
|
||||
*(int *)((char *)tib + 0x38) = gettid();
|
||||
*(int *)((char *)tib + 0x3c) = __errno;
|
||||
__install_tls(tib);
|
||||
EXPECT_EQ(31337, errno);
|
||||
EXPECT_EQ(tib, __get_tls());
|
||||
|
|
|
@ -80,10 +80,10 @@ TEST(rand64, testLcg_doesntProduceIdenticalValues) {
|
|||
}
|
||||
|
||||
TEST(rand64, testThreadSafety_doesntProduceIdenticalValues) {
|
||||
char *tls[THREADS];
|
||||
int i, j, rc, ws;
|
||||
sigset_t ss, oldss;
|
||||
char *tls[THREADS];
|
||||
void *stacks[THREADS];
|
||||
int i, j, rc, ws, tid[THREADS];
|
||||
struct sigaction oldsa;
|
||||
struct sigaction sa = {.sa_handler = OnChld, .sa_flags = SA_RESTART};
|
||||
EXPECT_NE(-1, sigaction(SIGCHLD, &sa, &oldsa));
|
||||
|
@ -92,19 +92,20 @@ TEST(rand64, testThreadSafety_doesntProduceIdenticalValues) {
|
|||
sigaddset(&ss, SIGCHLD);
|
||||
EXPECT_EQ(0, sigprocmask(SIG_BLOCK, &ss, &oldss));
|
||||
ready = false;
|
||||
memset(tid, -1, sizeof(tid));
|
||||
for (i = 0; i < THREADS; ++i) {
|
||||
tls[i] = __initialize_tls(calloc(1, 64));
|
||||
stacks[i] = mmap(0, GetStackSize(), PROT_READ | PROT_WRITE,
|
||||
MAP_STACK | MAP_ANONYMOUS, -1, 0);
|
||||
ASSERT_NE(-1, clone(Thrasher, stacks[i], GetStackSize(),
|
||||
CLONE_THREAD | CLONE_VM | CLONE_FS | CLONE_FILES |
|
||||
CLONE_SIGHAND | CLONE_SETTLS | CLONE_CHILD_CLEARTID,
|
||||
(void *)(intptr_t)i, 0, tls[i], 64, tid + i));
|
||||
ASSERT_NE(
|
||||
-1,
|
||||
clone(Thrasher, stacks[i], GetStackSize(),
|
||||
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;
|
||||
for (i = 0; i < THREADS; ++i) {
|
||||
_spinlock(tid + i);
|
||||
_spinlock((int *)(tls[i] + 0x38));
|
||||
EXPECT_SYS(0, 0, munmap(stacks[i], GetStackSize()));
|
||||
free(tls[i]);
|
||||
}
|
||||
|
|
|
@ -41,6 +41,12 @@ void Extract(const char *from, const char *to, int mode) {
|
|||
}
|
||||
|
||||
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));
|
||||
Extract("/zip/apetest.com", "bin/apetest.com", 0755);
|
||||
Extract("/zip/apetest2.com", "bin/apetest2.com", 0755);
|
||||
|
|
|
@ -45,7 +45,7 @@ void SetUp(void) {
|
|||
tls = calloc(1, 64);
|
||||
__initialize_tls(tls);
|
||||
*(int *)(tls + 0x3c) = 31337;
|
||||
childetid = (int *)(tls + 0x0038);
|
||||
childetid = (int *)(tls + 0x38);
|
||||
ASSERT_NE(MAP_FAILED, (stack = mmap(0, GetStackSize(), PROT_READ | PROT_WRITE,
|
||||
MAP_STACK | MAP_ANONYMOUS, -1, 0)));
|
||||
}
|
||||
|
@ -95,6 +95,7 @@ TEST(clone, test1) {
|
|||
CLONE_SETTLS,
|
||||
(void *)23, &ptid, tls, 64, childetid)));
|
||||
_spinlock(childetid); // CLONE_CHILD_CLEARTID
|
||||
ASSERT_NE(gettid(), tid);
|
||||
ASSERT_EQ(tid, ptid);
|
||||
ASSERT_EQ(42, x);
|
||||
ASSERT_NE(me, tid);
|
||||
|
@ -130,6 +131,6 @@ TEST(clone, tlsSystemCallsErrno_wontClobberMainThreadBecauseTls) {
|
|||
BENCH(clone, bench) {
|
||||
errno_t *volatile ep;
|
||||
char *volatile tp;
|
||||
EZBENCH2("__errno_location", donothing, (ep = (__errno_location())));
|
||||
EZBENCH2("__errno_location", donothing, (ep = __errno_location()));
|
||||
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
|
||||
|
||||
#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 // _LIBCPP_ERRNO_H
|
||||
|
|
14
third_party/lua/lrepl.c
vendored
14
third_party/lua/lrepl.c
vendored
|
@ -234,9 +234,9 @@ static ssize_t pushline (lua_State *L, int firstline) {
|
|||
ssize_t rc;
|
||||
char *prmt;
|
||||
globalL = L;
|
||||
prmt = strdup(get_prompt(L, firstline));
|
||||
lua_pop(L, 1); /* remove prompt */
|
||||
if (lua_repl_isterminal) {
|
||||
prmt = strdup(get_prompt(L, firstline));
|
||||
lua_pop(L, 1); /* remove prompt */
|
||||
LUA_REPL_UNLOCK;
|
||||
rc = linenoiseEdit(lua_repl_linenoise, prmt, &b, !firstline || lua_repl_blocking);
|
||||
free(prmt);
|
||||
|
@ -250,9 +250,17 @@ static ssize_t pushline (lua_State *L, int firstline) {
|
|||
LUA_REPL_LOCK;
|
||||
} else {
|
||||
LUA_REPL_UNLOCK;
|
||||
fputs(prmt, stdout);
|
||||
fflush(stdout);
|
||||
b = linenoiseGetLine(stdin);
|
||||
if (b) {
|
||||
rc = 1;
|
||||
} else if (ferror(stdin)) {
|
||||
rc = -1;
|
||||
} else {
|
||||
rc = 0;
|
||||
}
|
||||
LUA_REPL_LOCK;
|
||||
rc = b ? 1 : -1;
|
||||
}
|
||||
if (!(rc == -1 && errno == EAGAIN)) {
|
||||
write(1, "\n", 1);
|
||||
|
|
6
third_party/lua/lua.main.c
vendored
6
third_party/lua/lua.main.c
vendored
|
@ -307,7 +307,8 @@ static void doREPL (lua_State *L) {
|
|||
progname = NULL; /* no 'progname' on errors in interactive mode */
|
||||
lua_initrepl(L, LUA_PROGNAME);
|
||||
for (;;) {
|
||||
linenoiseEnableRawMode(0);
|
||||
if (lua_repl_isterminal)
|
||||
linenoiseEnableRawMode(0);
|
||||
TryAgain:
|
||||
status = lua_loadline(L);
|
||||
if (status == -2 && errno == EAGAIN) {
|
||||
|
@ -315,7 +316,8 @@ static void doREPL (lua_State *L) {
|
|||
poll(&(struct pollfd){0, POLLIN}, 1, -1);
|
||||
goto TryAgain;
|
||||
}
|
||||
linenoiseDisableRawMode();
|
||||
if (lua_repl_isterminal)
|
||||
linenoiseDisableRawMode();
|
||||
if (status == -1) {
|
||||
break;
|
||||
} else if (status == -2) {
|
||||
|
|
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. */
|
||||
unsigned int error_message_count;
|
||||
|
||||
#ifdef _LIBC
|
||||
/* In the GNU C library, there is a predefined variable for this. */
|
||||
|
||||
# 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 */
|
||||
#undef fcntl
|
||||
#define program_name getprogname ()
|
||||
#define __strerror_r strerror_r
|
||||
|
||||
/* Return non-zero if FD is open. */
|
||||
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
|
||||
Traceback (most recent call last):
|
||||
...
|
||||
FileNotFoundError: [Errno 2] ENOENT/2/No such file or directory: 'nosuchfile'
|
||||
FileNotFoundError: [Errno 2] ENOENT...
|
||||
|
||||
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))
|
||||
except AttributeError:
|
||||
pass
|
||||
if cosmo.MODE != 'tiny':
|
||||
if 'tiny' not in cosmo.MODE:
|
||||
self.assertEqual(foo.__doc__, ModuleType.__doc__)
|
||||
|
||||
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/errno.h"
|
||||
#include "libc/nt/enum/version.h"
|
||||
#include "libc/nt/version.h"
|
||||
#include "libc/runtime/runtime.h"
|
||||
#include "libc/sock/sock.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_SAVE_SYN) PyModule_AddIntMacro(m, TCP_SAVE_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);
|
||||
if (TCP_FASTOPEN && (!IsWindows() || NtGetVersion() >= kNtVersionWindows10))
|
||||
if (TCP_FASTOPEN && (!IsWindows() || IsAtLeastWindows10()))
|
||||
PyModule_AddIntMacro(m, TCP_FASTOPEN);
|
||||
if (TCP_FASTOPEN_CONNECT)
|
||||
PyModule_AddIntMacro(m, TCP_FASTOPEN_CONNECT);
|
||||
|
|
|
@ -2791,6 +2791,9 @@ UNIX MODULE
|
|||
unix.sigaction(unix.SIGALRM, MyOnSigAlrm, unix.SA_RESETHAND)
|
||||
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
|
||||
|
||||
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 │
|
||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "dsp/scale/cdecimate2xuint8x8.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/calls/calls.h"
|
||||
#include "libc/calls/ioctl.h"
|
||||
#include "libc/calls/math.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/flock.h"
|
||||
#include "libc/calls/struct/iovec.h"
|
||||
#include "libc/calls/struct/rusage.h"
|
||||
#include "libc/calls/struct/sigaction.h"
|
||||
#include "libc/calls/struct/stat.h"
|
||||
#include "libc/calls/struct/termios.h"
|
||||
#include "libc/calls/ttydefaults.h"
|
||||
#include "libc/dce.h"
|
||||
#include "libc/dns/dns.h"
|
||||
#include "libc/dns/hoststxt.h"
|
||||
#include "libc/dos.h"
|
||||
#include "libc/errno.h"
|
||||
#include "libc/fmt/conv.h"
|
||||
#include "libc/fmt/fmt.h"
|
||||
#include "libc/fmt/itoa.h"
|
||||
#include "libc/intrin/kprintf.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/log.h"
|
||||
#include "libc/macros.internal.h"
|
||||
#include "libc/math.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/crc32.h"
|
||||
#include "libc/nexgen32e/nt2sysv.h"
|
||||
#include "libc/nexgen32e/rdtsc.h"
|
||||
#include "libc/nexgen32e/rdtscp.h"
|
||||
#include "libc/nexgen32e/threaded.h"
|
||||
#include "libc/nexgen32e/x86feature.h"
|
||||
#include "libc/nt/enum/fileflagandattributes.h"
|
||||
#include "libc/nt/runtime.h"
|
||||
#include "libc/nt/thread.h"
|
||||
#include "libc/nt/version.h"
|
||||
#include "libc/rand/rand.h"
|
||||
#include "libc/runtime/clktck.h"
|
||||
#include "libc/runtime/directmap.internal.h"
|
||||
#include "libc/runtime/gc.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/symbols.internal.h"
|
||||
#include "libc/sock/goodsocket.internal.h"
|
||||
#include "libc/sock/sock.h"
|
||||
#include "libc/stdio/append.internal.h"
|
||||
#include "libc/stdio/hex.internal.h"
|
||||
#include "libc/stdio/stdio.h"
|
||||
#include "libc/str/slice.h"
|
||||
#include "libc/str/str.h"
|
||||
#include "libc/str/undeflate.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/dt.h"
|
||||
#include "libc/sysv/consts/ex.h"
|
||||
#include "libc/sysv/consts/exit.h"
|
||||
#include "libc/sysv/consts/f.h"
|
||||
#include "libc/sysv/consts/grnd.h"
|
||||
#include "libc/sysv/consts/inaddr.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/msync.h"
|
||||
#include "libc/sysv/consts/nr.h"
|
||||
#include "libc/sysv/consts/o.h"
|
||||
#include "libc/sysv/consts/poll.h"
|
||||
#include "libc/sysv/consts/pr.h"
|
||||
#include "libc/sysv/consts/prot.h"
|
||||
#include "libc/sysv/consts/rusage.h"
|
||||
#include "libc/sysv/consts/s.h"
|
||||
#include "libc/sysv/consts/sa.h"
|
||||
#include "libc/sysv/consts/shut.h"
|
||||
#include "libc/sysv/consts/sig.h"
|
||||
#include "libc/sysv/consts/so.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/w.h"
|
||||
#include "libc/sysv/errfuns.h"
|
||||
#include "libc/testlib/testlib.h"
|
||||
#include "libc/time/time.h"
|
||||
#include "libc/x/x.h"
|
||||
#include "libc/zip.h"
|
||||
#include "net/http/escape.h"
|
||||
#include "net/http/http.h"
|
||||
#include "net/http/ip.h"
|
||||
#include "net/http/url.h"
|
||||
#include "net/https/https.h"
|
||||
#include "third_party/getopt/getopt.h"
|
||||
#include "third_party/linenoise/linenoise.h"
|
||||
#include "third_party/lua/cosmo.h"
|
||||
#include "third_party/lua/lauxlib.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/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/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/md.h"
|
||||
#include "third_party/mbedtls/md5.h"
|
||||
#include "third_party/mbedtls/net_sockets.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/sha1.h"
|
||||
#include "third_party/mbedtls/ssl.h"
|
||||
#include "third_party/mbedtls/ssl_ticket.h"
|
||||
#include "third_party/mbedtls/x509.h"
|
||||
#include "third_party/mbedtls/x509_crt.h"
|
||||
#include "third_party/regex/regex.h"
|
||||
#include "third_party/zlib/zlib.h"
|
||||
#include "tool/args/args.h"
|
||||
#include "tool/build/lib/case.h"
|
||||
#include "tool/build/lib/psk.h"
|
||||
#include "tool/net/lfuncs.h"
|
||||
#include "tool/net/luacheck.h"
|
||||
#include "tool/net/sandbox.h"
|
||||
|
@ -441,12 +382,14 @@ static int mainpid;
|
|||
static int sandboxed;
|
||||
static int changeuid;
|
||||
static int changegid;
|
||||
static int monitortid;
|
||||
static int isyielding;
|
||||
static int statuscode;
|
||||
static int shutdownsig;
|
||||
static int sslpskindex;
|
||||
static int oldloglevel;
|
||||
static int *monitortid;
|
||||
static char *monitortls;
|
||||
static char *monitorstack;
|
||||
static int maxpayloadsize;
|
||||
static int messageshandled;
|
||||
static int sslticketlifetime;
|
||||
|
@ -6393,7 +6336,7 @@ static int ExitWorker(void) {
|
|||
}
|
||||
if (monitortty) {
|
||||
terminatemonitor = true;
|
||||
_spinlock(&monitortid);
|
||||
_spinlock(monitortid);
|
||||
}
|
||||
_Exit(0);
|
||||
}
|
||||
|
@ -6649,19 +6592,23 @@ static int MemoryMonitor(void *arg) {
|
|||
}
|
||||
|
||||
static void MonitorMemory(void) {
|
||||
char *tls;
|
||||
monitortid = -1;
|
||||
tls = __initialize_tls(malloc(64));
|
||||
__cxa_atexit(free, tls, 0);
|
||||
if (clone(MemoryMonitor,
|
||||
mmap(0, GetStackSize(), PROT_READ | PROT_WRITE,
|
||||
MAP_STACK | MAP_ANONYMOUS, -1, 0),
|
||||
GetStackSize(),
|
||||
CLONE_VM | CLONE_THREAD | CLONE_FS | CLONE_FILES | CLONE_SIGHAND |
|
||||
CLONE_SETTLS | CLONE_CHILD_SETTID | CLONE_CHILD_CLEARTID,
|
||||
0, 0, tls, 64, &monitortid) == -1) {
|
||||
monitortid = 0;
|
||||
if ((monitortls = __initialize_tls(malloc(64)))) {
|
||||
if ((monitorstack = mmap(0, GetStackSize(), PROT_READ | PROT_WRITE,
|
||||
MAP_STACK | MAP_ANONYMOUS, -1, 0)) != MAP_FAILED) {
|
||||
monitortid = (int *)(monitortls + 0x38);
|
||||
if ((*monitortid =
|
||||
clone(MemoryMonitor, monitorstack, GetStackSize(),
|
||||
CLONE_VM | CLONE_THREAD | CLONE_FS | CLONE_FILES |
|
||||
CLONE_SIGHAND | CLONE_SETTLS | CLONE_CHILD_CLEARTID,
|
||||
0, 0, monitortls, 64, monitortid)) != -1) {
|
||||
return;
|
||||
}
|
||||
munmap(monitorstack, GetStackSize());
|
||||
}
|
||||
free(monitortls);
|
||||
}
|
||||
WARNF("(memv) failed to start memory monitor %m");
|
||||
monitortty = 0;
|
||||
}
|
||||
|
||||
static int HandleConnection(size_t i) {
|
||||
|
@ -7327,7 +7274,9 @@ void RedBean(int argc, char *argv[]) {
|
|||
}
|
||||
if (monitortty) {
|
||||
terminatemonitor = true;
|
||||
_spinlock(&monitortid);
|
||||
_spinlock(monitortid);
|
||||
munmap(monitorstack, GetStackSize());
|
||||
free(monitortls);
|
||||
}
|
||||
INFOF("(srvr) shutdown complete");
|
||||
}
|
||||
|
|
Loading…
Add table
Reference in a new issue