Fix some issues and do some code cleanup

This commit is contained in:
Justine Tunney 2022-05-23 10:15:53 -07:00
parent 1f229e4efc
commit 312ed5c67c
72 changed files with 880 additions and 982 deletions

View file

@ -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;
// 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();
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(),
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,
(void *)(intptr_t)i, 0, tls, 64, 0));
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);
}
status = "";
} else {
kprintf("error: mmap(%d) failed %m\n", i);
}
if (!(i % 500)) {
PrintStatus();
}
}
} else {
kprintf("error: invalid number of threads\n");
}
// wait for workers to terminate
while (workers) {
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);
}

View file

@ -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;

View file

@ -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;

View file

@ -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);

View file

@ -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;
}
} else if (IsMetal()) {
return true;
} else if (!IsWindows()) {

View file

@ -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;

View file

@ -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

View file

@ -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;

View file

@ -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++ = '-';

View file

@ -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

View file

@ -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,7 +873,7 @@ 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,
void *__asan_allocate(size_t a, size_t n, int underrun, int overrun,
struct AsanTrace *bt) {
char *p;
size_t c;
@ -960,7 +887,7 @@ static void *__asan_allocate(size_t a, size_t n, int underrun, int overrun,
__asan_poison(p + n, c - n, overrun);
__asan_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;

View file

@ -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);
}

View file

@ -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 *);

View 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);
}

View file

@ -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) {

View file

@ -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,10 +59,8 @@ privileged int gettid(void) {
if (__tls_enabled) {
rc = *(int *)(__get_tls() + 0x38);
if (rc && rc != -1) {
return rc;
}
}
if (IsWindows()) {
return __imp_GetCurrentThreadId();

View file

@ -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

View file

@ -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:
*

View file

@ -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;

View file

@ -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

View file

@ -44,23 +44,28 @@
* 0x003c 0x04 errno
*
*/
privileged void *__initialize_tls(char tib[hasatleast 64]) {
privileged void *__initialize_tls(char tib[64]) {
if (tib) {
*(intptr_t *)tib = (intptr_t)tib;
*(intptr_t *)(tib + 0x08) = 0;
*(int *)(tib + 0x10) = -1; // exit code
*(intptr_t *)(tib + 0x30) = (intptr_t)tib;
*(int *)(tib + 0x38) = -1; // tid
*(int *)(tib + 0x3c) = __errno;
*(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();

View file

@ -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__)
/**

View file

@ -4,6 +4,7 @@
/**
* Known versions of the New Technology executive.
* @see IsAtLeastWindows10()
* @see NtGetVersion()
*/
#define kNtVersionWindows10 0x0a00

View file

@ -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_

View 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

View file

@ -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)) !=

View file

@ -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;
}

View file

@ -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;

View file

@ -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);
}

View file

@ -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);
}

View file

@ -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);
}

View 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);
}

View file

@ -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) {

View file

@ -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;
}

View file

@ -28,11 +28,11 @@
void flockfile(FILE *f) {
int me, owner;
unsigned tries;
if (!__threaded) return;
if (__threaded) {
for (tries = 0, me = gettid();;) {
owner = 0;
if (_lockcmpxchgp(&f->lock, &owner, me) || owner == me) {
return;
break;
}
if (++tries & 7) {
__builtin_ia32_pause();
@ -41,3 +41,5 @@ void flockfile(FILE *f) {
}
}
}
++f->reent;
}

View file

@ -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;

View file

@ -34,5 +34,8 @@ int ftrylockfile(FILE *f) {
owner = 0;
}
}
if (!owner) {
++f->reent;
}
return owner;
}

View file

@ -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);
}
}
}

View file

@ -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;

View 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;
}
}

View file

@ -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);

View file

@ -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)

View file

@ -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

View file

@ -1,2 +0,0 @@
#include "libc/sysv/consts/syscon.internal.h"
.syscon prsnlty,ADDR_COMPAT_LAYOUT,0x0200000,0,0,0,0,0

View file

@ -1,2 +0,0 @@
#include "libc/sysv/consts/syscon.internal.h"
.syscon prsnlty,ADDR_LIMIT_32BIT,0x0800000,0,0,0,0,0

View file

@ -1,2 +0,0 @@
#include "libc/sysv/consts/syscon.internal.h"
.syscon prsnlty,ADDR_LIMIT_3GB,0x8000000,0,0,0,0,0

View file

@ -1,2 +0,0 @@
#include "libc/sysv/consts/syscon.internal.h"
.syscon prsnlty,ADDR_NO_RANDOMIZE,0x0040000,0,0,0,0,0

View file

@ -1,2 +0,0 @@
#include "libc/sysv/consts/syscon.internal.h"
.syscon prsnlty,FDPIC_FUNCPTRS,0x0080000,0,0,0,0,0

View file

@ -1,2 +0,0 @@
#include "libc/sysv/consts/syscon.internal.h"
.syscon prsnlty,MMAP_PAGE_ZERO,0x0100000,0,0,0,0,0

View file

@ -1,2 +0,0 @@
#include "libc/sysv/consts/syscon.internal.h"
.syscon prsnlty,READ_IMPLIES_EXEC,0x0400000,0,0,0,0,0

View file

@ -1,2 +0,0 @@
#include "libc/sysv/consts/syscon.internal.h"
.syscon prsnlty,SHORT_INODE,0x1000000,0,0,0,0,0

View file

@ -1,2 +0,0 @@
#include "libc/sysv/consts/syscon.internal.h"
.syscon prsnlty,STICKY_TIMEOUTS,0x4000000,0,0,0,0,0

View file

@ -1,2 +0,0 @@
#include "libc/sysv/consts/syscon.internal.h"
.syscon prsnlty,UNAME26,0x0020000,0,0,0,0,0

View file

@ -1,2 +0,0 @@
#include "libc/sysv/consts/syscon.internal.h"
.syscon prsnlty,WHOLE_SECONDS,0x2000000,0,0,0,0,0

View file

@ -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_ */

View file

@ -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));

View file

@ -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) {

View file

@ -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());
}

View file

@ -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());

View file

@ -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]);
}

View file

@ -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);

View file

@ -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()));
}

View 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);
}

View file

@ -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

View file

@ -234,9 +234,9 @@ static ssize_t pushline (lua_State *L, int firstline) {
ssize_t rc;
char *prmt;
globalL = L;
if (lua_repl_isterminal) {
prmt = strdup(get_prompt(L, firstline));
lua_pop(L, 1); /* remove prompt */
if (lua_repl_isterminal) {
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);

View file

@ -307,6 +307,7 @@ static void doREPL (lua_State *L) {
progname = NULL; /* no 'progname' on errors in interactive mode */
lua_initrepl(L, LUA_PROGNAME);
for (;;) {
if (lua_repl_isterminal)
linenoiseEnableRawMode(0);
TryAgain:
status = lua_loadline(L);
@ -315,6 +316,7 @@ static void doREPL (lua_State *L) {
poll(&(struct pollfd){0, POLLIN}, 1, -1);
goto TryAgain;
}
if (lua_repl_isterminal)
linenoiseDisableRawMode();
if (status == -1) {
break;

View file

@ -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 */
/* Return non-zero if FD is open. */
static int

View file

@ -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:

View file

@ -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):

View file

@ -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);

View file

@ -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.

View file

@ -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");
}