Fix bugs with recent change

This change makes further effort towards improving our poll()
implementation on the New Technology. The stdin worker didn't work out
so well for Python so it's not being used for now. System call tracing
with the --strace flag should now be less noisy now on Windows unless
you modify the strace.internal.h defines to turn on some optional ones
that are most useful for debugging the system call wrappers.
This commit is contained in:
Justine Tunney 2022-04-16 10:40:23 -07:00
parent 933411ba99
commit dc0ea6640e
127 changed files with 1354 additions and 866 deletions

View file

@ -7,19 +7,30 @@
http://creativecommons.org/publicdomain/zero/1.0/ │
*/
#endif
#include "libc/intrin/kprintf.h"
#include "libc/log/backtrace.internal.h"
#include "libc/log/log.h"
#include "libc/runtime/runtime.h"
#include "libc/runtime/symbols.internal.h"
#include "libc/stdio/stdio.h"
int main(int argc, char *argv[]) {
ShowCrashReports();
// ShowCrashReports();
if (IsDebuggerPresent(false)) {
printf("debugger found!\r\n");
DebugBreak();
return 0;
kprintf("debugger found!%n");
} else {
kprintf("try running: gdb %s%n", argv[0]);
kprintf("try running: o//tool/build/strace.com %s%n", argv[0]);
}
printf("try running: gdb %s\r\n", argv[0]);
return 1;
asm volatile("mov\t%4,%%r10\n\t"
"mov\t%5,%%r8\n\t"
"mov\t%6,%%r9\n\t"
"int3"
: /* no outputs */
: "a"(0), "D"(1), "S"(2), "d"(3), "g"(4), "g"(5), "g"(6)
: "r8", "r9", "r10");
printf("recovered from SIGTRAP without handler\r\n");
return 0;
}

23
examples/linenoise.c Normal file
View file

@ -0,0 +1,23 @@
#if 0
/*─────────────────────────────────────────────────────────────────╗
To the extent possible under law, Justine Tunney has waived
all copyright and related or neighboring rights to this file,
as it is written in the following disclaimers:
http://unlicense.org/ │
http://creativecommons.org/publicdomain/zero/1.0/ │
*/
#endif
#include "libc/mem/mem.h"
#include "libc/stdio/stdio.h"
#include "third_party/linenoise/linenoise.h"
int main(int argc, char *argv[]) {
char *line;
while ((line = linenoiseWithHistory("IN> ", "foo"))) {
fputs("OUT> ", stdout);
fputs(line, stdout);
fputs("\n", stdout);
free(line);
}
return 0;
}

View file

@ -7,115 +7,8 @@
http://creativecommons.org/publicdomain/zero/1.0/ │
*/
#endif
#include "libc/calls/calls.h"
#include "libc/intrin/kprintf.h"
#include "libc/log/log.h"
#include "libc/macros.internal.h"
#include "libc/mem/mem.h"
#include "libc/nt/process.h"
#include "libc/runtime/gc.h"
#include "libc/runtime/runtime.h"
#include "libc/runtime/stack.h"
#include "libc/stdio/stdio.h"
#include "libc/str/str.h"
#include "libc/sysv/consts/auxv.h"
const struct AuxiliaryValue {
const char *fmt;
long *id;
const char *name;
const char *description;
} kAuxiliaryValues[] = {
{"%-14p", &AT_EXECFD, "AT_EXECFD", "file descriptor of program"},
{"%-14p", &AT_PHDR, "AT_PHDR", "address of elf program headers"},
{"%-14p", &AT_PHENT, "AT_PHENT", "size of program header entry"},
{"%-14p", &AT_PHNUM, "AT_PHNUM", "number of program headers"},
{"%-14p", &AT_PAGESZ, "AT_PAGESZ", "system page size"},
{"%-14p", &AT_BASE, "AT_BASE", "base address of the program interpreter"},
{"%-14p", &AT_ENTRY, "AT_ENTRY", "entry address of executable"},
{"%-14p", &AT_NOTELF, "AT_NOTELF", "set if not an elf"},
{"%-14d", &AT_UID, "AT_UID", "real user id of thread"},
{"%-14d", &AT_EUID, "AT_EUID", "effective user id of thread"},
{"%-14d", &AT_GID, "AT_GID", "real group id of thread"},
{"%-14d", &AT_EGID, "AT_EGID", "effective group id of thread"},
{"%-14d", &AT_CLKTCK, "AT_CLKTCK", "frequency of times() counts"},
{"%-14d", &AT_OSRELDATE, "AT_OSRELDATE",
"freebsd release number, e.g. 1200086"},
{"%-14p", &AT_PLATFORM, "AT_PLATFORM",
"string identifying hardware platform"},
{"%-14p", &AT_DCACHEBSIZE, "AT_DCACHEBSIZE", "data cache block size"},
{"%-14p", &AT_ICACHEBSIZE, "AT_ICACHEBSIZE",
"instruction cache block size"},
{"%-14p", &AT_UCACHEBSIZE, "AT_UCACHEBSIZE", "unified cache block size"},
{"%-14p", &AT_SECURE, "AT_SECURE",
"for set{u,g}id binz & security blankets"},
{"%-14s", &AT_BASE_PLATFORM, "AT_BASE_PLATFORM",
"string identifying real platform"},
{"%-14p", &AT_RANDOM, "AT_RANDOM", "address of sixteen random bytes"},
{"%-14s (%p)", &AT_EXECFN, "AT_EXECFN", "pathname used to execute program"},
{"%-14p", &AT_SYSINFO_EHDR, "AT_SYSINFO_EHDR",
"linux virtual dso page address"},
{"%-14p", &AT_FLAGS, "AT_FLAGS", "unused?"},
{"%-14p", &AT_HWCAP, "AT_HWCAP", "cpu stuff"},
{"%-14p", &AT_HWCAP2, "AT_HWCAP2", "more cpu stuff"},
{"%-14p", &AT_STACKBASE, "AT_STACKBASE", "NetBSD stack base"},
{"%-14p", &AT_CANARY, "AT_CANARY", "FreeBSD AT_CANARY"},
{"%-14p", &AT_CANARYLEN, "AT_CANARYLEN", "FreeBSD AT_CANARYLEN"},
{"%-14ld", &AT_NCPUS, "AT_NCPUS", "FreeBSD AT_NCPUS"},
{"%-14p", &AT_PAGESIZES, "AT_PAGESIZES", "FreeBSD AT_PAGESIZES"},
{"%-14d", &AT_PAGESIZESLEN, "AT_PAGESIZESLEN", "FreeBSD AT_PAGESIZESLEN"},
{"%-14p", &AT_TIMEKEEP, "AT_TIMEKEEP", "FreeBSD AT_TIMEKEEP"},
{"%-14p", &AT_STACKPROT, "AT_STACKPROT", "FreeBSD AT_STACKPROT"},
{"%-14p", &AT_EHDRFLAGS, "AT_EHDRFLAGS", "FreeBSD AT_EHDRFLAGS"},
};
const struct AuxiliaryValue *DescribeAuxv(unsigned long x) {
int i;
for (i = 0; i < ARRAYLEN(kAuxiliaryValues); ++i) {
if (*kAuxiliaryValues[i].id && x == *kAuxiliaryValues[i].id) {
return kAuxiliaryValues + i;
}
}
return NULL;
}
int main(int argc, char *argv[], char **envp) {
long key;
char **env;
unsigned i;
unsigned long *auxp;
struct AuxiliaryValue *auxinfo;
uint32_t varlen;
char16_t var[PATH_MAX];
kprintf("%nArguments:%n");
for (i = 0; i < __argc; ++i) {
kprintf(" ☼ %s%n", argv[i]);
}
kprintf("%nEnvironment:%n");
for (env = envp; *env; ++env) {
kprintf(" ☼ %s%n", *env);
}
kprintf("%nAuxiliary Values:%n");
for (auxp = __auxv; *auxp; auxp += 2) {
if ((auxinfo = DescribeAuxv(auxp[0]))) {
kprintf(" ☼ %16s[%4ld] = ", auxinfo->name, auxp[0]);
kprintf(auxinfo->fmt, auxp[1], auxp[1]);
kprintf(" # %s%n", auxinfo->description);
} else {
kprintf(" ☼ %16s[%4ld] = %014p%n", "unknown", auxp[0], auxp[1]);
}
}
kprintf("%nSpecial Parameters:%n");
kprintf(" ☼ kTmpPath = %#s%n", kTmpPath);
kprintf(" ☼ kNtSystemDirectory = %#s%n", kNtSystemDirectory);
kprintf(" ☼ kNtWindowsDirectory = %#s%n", kNtWindowsDirectory);
kprintf(" ☼ program_executable_name = %#s (%p)%n", GetProgramExecutableName(),
GetProgramExecutableName());
kprintf(" ☼ GetInterpreterExecutableName() → %#s%n",
GetInterpreterExecutableName(_gc(malloc(1024)), 1024));
kprintf(" ☼ RSP → %p%n", __builtin_frame_address(0));
kprintf(" ☼ GetStackAddr() → %p%n", GetStackAddr(0));
kprintf(" ☼ GetStaticStackAddr() → %p%n", GetStaticStackAddr(0));
kprintf(" ☼ GetStackSize() → %p%n", GetStackSize());
return 0;
int main() {
__printargs("");
}

View file

@ -29,14 +29,6 @@ textwindows int sys_close_nt(struct Fd *fd) {
int e;
bool ok = true;
// if this file descriptor is wrapped in a named pipe worker thread
// then we need to close our copy of the worker thread handle. it's
// also required that whatever install a worker use malloc, so free
if (fd->worker) {
if (!weaken(UnrefNtStdinWorker)(fd->worker)) ok = false;
fd->worker = 0;
}
if (fd->kind == kFdFile && ((fd->flags & O_ACCMODE) != O_RDONLY &&
GetFileType(fd->handle) == kNtFileTypeDisk)) {
// Like Linux, closing a file on Windows doesn't guarantee it's
@ -47,8 +39,15 @@ textwindows int sys_close_nt(struct Fd *fd) {
errno = e;
}
// now we can close the handle
if (!CloseHandle(fd->handle)) ok = false;
// if this file descriptor is wrapped in a named pipe worker thread
// then we need to close our copy of the worker thread handle. it's
// also required that whatever install a worker use malloc, so free
if (fd->worker) {
if (!weaken(UnrefNtStdinWorker)(fd->worker)) ok = false;
fd->worker = 0;
} else {
if (!CloseHandle(fd->handle)) ok = false;
}
if (fd->kind == kFdConsole && fd->extra && fd->extra != -1) {
if (!CloseHandle(fd->extra)) ok = false;
}

View file

@ -40,14 +40,13 @@ textwindows struct DirectMap sys_mmap_nt(void *addr, size_t size, int prot,
struct DirectMap dm;
struct ProtectNt fl;
const struct NtSecurityAttributes *sec;
struct NtProcessMemoryCountersEx memcount;
#ifndef NDEBUG
struct NtProcessMemoryCountersEx memcount = {
.cb = sizeof(struct NtProcessMemoryCountersEx),
};
#if _NT_RLIMIT_PWSS_MB
if (GetProcessMemoryInfo(GetCurrentProcess(), &memcount, sizeof(memcount))) {
if (memcount.PeakWorkingSetSize > 5ull * 1024 * 1024 * 1024) {
kprintf("error: exceeded 5gb memory limit%n");
if (memcount.PeakWorkingSetSize > _NT_RLIMIT_PWSS_MB * 1048576ull) {
kprintf("error: PeakWorkingSetSize %'ldmb exceeded %'ldmb limit%n",
memcount.PeakWorkingSetSize / 1048576, (long)_NT_RLIMIT_PWSS_MB);
_Exit(201);
}
}

View file

@ -45,8 +45,8 @@ struct DirectMap sys_mmap(void *addr, size_t size, int prot, int flags, int fd,
} else {
d = sys_mmap_nt(addr, size, prot, flags, fd, off);
}
STRACE("sys_mmap(%.12p%s, %'zu, %s, %s, %d, %'ld) → {%.12p, %p}% m", addr,
DescribeFrame((intptr_t)addr >> 16), size, DescribeProtFlags(prot),
DescribeMapFlags(flags), fd, off, d.addr, d.maphandle);
KERNTRACE("sys_mmap(%.12p%s, %'zu, %s, %s, %d, %'ld) → {%.12p, %p}% m", addr,
DescribeFrame((intptr_t)addr >> 16), size, DescribeProtFlags(prot),
DescribeMapFlags(flags), fd, off, d.addr, d.maphandle);
return d;
}

View file

@ -68,6 +68,6 @@ int fcntl(int fd, int cmd, ...) {
} else {
rc = einval();
}
STRACE("fcntl(%d, %d, %p) → %d% m", fd, cmd, arg);
STRACE("fcntl(%d, %d, %p) → %#x% m", fd, cmd, arg, rc);
return rc;
}

View file

@ -41,7 +41,7 @@ int fstat(int fd, struct stat *st) {
} else if (!__isfdkind(fd, kFdFile)) {
rc = ebadf();
} else {
rc = sys_fstat_nt(g_fds.p[fd].handle, st);
rc = sys_fstat_nt(__getfdhandleactual(fd), st);
}
STRACE("fstat(%d, [%s]) → %d% m", fd, __strace_stat(rc, st), rc);
return rc;

View file

@ -20,6 +20,7 @@
#include "libc/calls/internal.h"
#include "libc/calls/strace.internal.h"
#include "libc/nt/runtime.h"
#include "libc/sysv/consts/o.h"
STATIC_YOINK("_init_g_fds");
@ -48,4 +49,7 @@ textstartup void InitializeFileDescriptors(void) {
fds->__init_p[1].handle = GetStdHandle(pushpop(kNtStdOutputHandle));
fds->__init_p[2].handle = GetStdHandle(pushpop(kNtStdErrorHandle));
}
fds->__init_p[0].flags = O_RDONLY;
fds->__init_p[1].flags = O_WRONLY | O_APPEND;
fds->__init_p[2].flags = O_WRONLY | O_APPEND;
}

View file

@ -39,8 +39,5 @@ unsigned long getauxval(unsigned long at) {
return ap[1];
}
}
if (at == AT_EXECFN) {
return (intptr_t)__argv[0];
}
return 0;
}

31
libc/calls/getegid.c Normal file
View file

@ -0,0 +1,31 @@
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi
Copyright 2022 Justine Alexandra Roberts Tunney
Permission to use, copy, modify, and/or distribute this software for
any purpose with or without fee is hereby granted, provided that the
above copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE.
*/
#include "libc/calls/calls.h"
#include "libc/calls/internal.h"
#include "libc/calls/strace.internal.h"
/**
* Returns effective group ID of calling process.
*/
uint32_t getegid(void) {
int rc;
rc = sys_getegid();
STRACE("%s() → %d% m", "getegid", rc);
return rc;
}

View file

@ -27,6 +27,8 @@
*
* pheidippides.domain.example
* ^^^^^^^^^^^^
*
* @return 0 on success or -1 w/ errno
*/
int gethostname(char *name, size_t len) {
if (len < 1) return einval();

View file

@ -16,27 +16,21 @@
TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE.
*/
#include "libc/runtime/symbols.internal.h"
#include "libc/calls/calls.h"
#include "libc/calls/internal.h"
#include "libc/calls/strace.internal.h"
#include "libc/dce.h"
privileged noinstrument noasan noubsan int __get_symbol(struct SymbolTable *t,
intptr_t a) {
/* asan runtime depends on this function */
unsigned l, m, r, n, k;
if (t) {
l = 0;
r = n = t->count;
k = a - t->addr_base;
while (l < r) {
m = (l + r) >> 1;
if (t->symbols[m].y < k) {
l = m + 1;
} else {
r = m;
}
}
if (l < n && t->symbols[l].x <= k && k <= t->symbols[l].y) {
return l;
}
/**
* Returns process group id of calling process.
*/
uint32_t getpgrp(void) {
int rc;
if (!IsWindows()) {
rc = sys_getpgrp();
} else {
rc = getpid();
}
return -1;
STRACE("%s() → %d% m", "getpgrp", rc);
return rc;
}

View file

@ -30,30 +30,22 @@
#include "libc/sysv/errfuns.h"
textwindows int sys_getrusage_nt(int who, struct rusage *usage) {
struct NtFileTime CreationFileTime;
struct NtFileTime ExitFileTime;
struct NtFileTime KernelFileTime;
struct NtFileTime UserFileTime;
struct NtProcessMemoryCountersEx memcount;
struct NtFileTime ftExit, ftUser, ftKernel, ftCreation;
if (!usage) return efault();
if (who == 99) return enosys(); /* @see libc/sysv/consts.sh */
bzero(usage, sizeof(*usage));
if ((who == RUSAGE_SELF ? GetProcessTimes : GetThreadTimes)(
if (who == 99) return enosys(); // @see libc/sysv/consts.sh
if (!usage) return 0;
if (!(who == RUSAGE_SELF ? GetProcessTimes : GetThreadTimes)(
(who == RUSAGE_SELF ? GetCurrentProcess : GetCurrentThread)(),
&CreationFileTime, &ExitFileTime, &KernelFileTime, &UserFileTime)) {
/* xxx: shouldn't clobber memory on failure below */
usage->ru_utime = WindowsDurationToTimeVal(ReadFileTime(UserFileTime));
usage->ru_stime = WindowsDurationToTimeVal(ReadFileTime(KernelFileTime));
} else {
return __winerr();
}
bzero(&memcount, sizeof(memcount));
memcount.cb = sizeof(struct NtProcessMemoryCountersEx);
if (GetProcessMemoryInfo(GetCurrentProcess(), &memcount, sizeof(memcount))) {
usage->ru_maxrss = memcount.PeakWorkingSetSize / 1024;
usage->ru_majflt = memcount.PageFaultCount;
} else {
&ftCreation, &ftExit, &ftKernel, &ftUser) ||
!GetProcessMemoryInfo(GetCurrentProcess(), &memcount, sizeof(memcount))) {
return __winerr();
}
*usage = (struct rusage){
.ru_utime = WindowsDurationToTimeVal(ReadFileTime(ftUser)),
.ru_stime = WindowsDurationToTimeVal(ReadFileTime(ftKernel)),
.ru_maxrss = memcount.PeakWorkingSetSize / 1024,
.ru_majflt = memcount.PageFaultCount,
};
return 0;
}

View file

@ -157,6 +157,7 @@ i32 sys_futimes(i32, const struct timeval *) hidden;
i32 sys_futimesat(i32, const char *, const struct timeval *) hidden;
i32 sys_getitimer(i32, struct itimerval *) hidden;
i32 sys_getpgid(i32) hidden;
i32 sys_getpgrp(void) hidden;
i32 sys_getppid(void) hidden;
i32 sys_getpriority(i32, u32) hidden;
i32 sys_getrlimit(i32, struct rlimit *) hidden;
@ -223,6 +224,7 @@ i64 sys_sendfile(i32, i32, i64 *, u64) hidden;
i64 sys_splice(i32, i64 *, i32, i64 *, u64, u32) hidden;
i64 sys_vmsplice(i32, const struct iovec *, i64, u32) hidden;
i64 sys_write(i32, const void *, u64) hidden;
u32 sys_getegid(void) hidden;
u32 sys_geteuid(void) hidden;
u32 sys_getgid(void) hidden;
u32 sys_getsid(int) hidden;

View file

@ -35,7 +35,7 @@ int ioctl_default(int fd, uint64_t request, ...) {
return sys_ioctl(fd, request, arg);
} else if (__isfdopen(fd)) {
if (g_fds.p[fd].kind == kFdSocket) {
handle = g_fds.p[fd].handle;
handle = __getfdhandleactual(fd);
if ((rc = weaken(__sys_ioctlsocket_nt)(handle, request, arg)) != -1) {
return rc;
} else {

View file

@ -31,8 +31,8 @@ textwindows int ioctl_tcgets_nt(int ignored, struct termios *tio) {
int64_t in, out;
bool32 inok, outok;
uint32_t inmode, outmode;
inok = GetConsoleMode((in = g_fds.p[0].handle), &inmode);
outok = GetConsoleMode((out = g_fds.p[1].handle), &outmode);
inok = GetConsoleMode((in = __getfdhandleactual(0)), &inmode);
outok = GetConsoleMode((out = __getfdhandleactual(1)), &outmode);
if (inok | outok) {
bzero(tio, sizeof(*tio));
if (inok) {

View file

@ -31,8 +31,8 @@ textwindows int ioctl_tcsets_nt(int ignored, uint64_t request,
int64_t in, out;
bool32 inok, outok;
uint32_t inmode, outmode;
inok = GetConsoleMode((in = g_fds.p[0].handle), &inmode);
outok = GetConsoleMode((out = g_fds.p[1].handle), &outmode);
inok = GetConsoleMode((in = __getfdhandleactual(0)), &inmode);
outok = GetConsoleMode((out = __getfdhandleactual(1)), &outmode);
if (inok | outok) {
if (inok) {
if (request == TCSETSF) {

View file

@ -42,10 +42,10 @@ textwindows int ioctl_tiocgwinsz_nt(struct Fd *fd, struct winsize *ws) {
GetStartupInfo(&startinfo);
for (i = 0; i < ARRAYLEN(fds); ++i) {
if (fds[i]->kind == kFdFile || fds[i]->kind == kFdConsole) {
if (GetConsoleMode(fds[i]->handle, &mode)) {
if (GetConsoleMode(__getfdhandleactual(i), &mode)) {
bzero(&sbinfo, sizeof(sbinfo));
sbinfo.cbSize = sizeof(sbinfo);
if (GetConsoleScreenBufferInfoEx(fds[i]->handle, &sbinfo)) {
if (GetConsoleScreenBufferInfoEx(__getfdhandleactual(i), &sbinfo)) {
ws->ws_col = sbinfo.srWindow.Right - sbinfo.srWindow.Left + 1;
ws->ws_row = sbinfo.srWindow.Bottom - sbinfo.srWindow.Top + 1;
ws->ws_xpixel = 0;

View file

@ -29,9 +29,10 @@ textwindows int ioctl_tiocswinsz_nt(int fd, const struct winsize *ws) {
struct NtCoord coord;
if (!ws) return efault();
if (!__isfdkind(fd, kFdFile)) return ebadf();
if (!GetConsoleMode(g_fds.p[fd].handle, &mode)) return enotty();
if (!GetConsoleMode(__getfdhandleactual(fd), &mode)) return enotty();
coord.X = ws->ws_col;
coord.Y = ws->ws_row;
if (!SetConsoleScreenBufferSize(g_fds.p[fd].handle, coord)) return __winerr();
if (!SetConsoleScreenBufferSize(__getfdhandleactual(fd), coord))
return __winerr();
return 0;
}

View file

@ -24,5 +24,5 @@
textwindows bool32 sys_isatty_nt(int fd) {
return __isfdkind(fd, kFdConsole) ||
(__isfdkind(fd, kFdFile) &&
GetFileType(g_fds.p[fd].handle) == kNtFileTypeChar);
GetFileType(__getfdhandleactual(fd)) == kNtFileTypeChar);
}

View file

@ -66,6 +66,6 @@ bool32 ischardev(int fd) {
} else {
return __isfdkind(fd, kFdConsole) ||
(__isfdkind(fd, kFdFile) &&
GetFileType(g_fds.p[fd].handle) == kNtFileTypeChar);
GetFileType(__getfdhandleactual(fd)) == kNtFileTypeChar);
}
}

View file

@ -60,6 +60,6 @@ privileged void *sys_mremap(void *p, size_t n, size_t m, int f, void *q) {
} else {
rax = enosys();
}
STRACE("sys_mremap(%p, %'zu, %'zu, %#b, %p) → %p% m", p, n, m, f, q, rax);
KERNTRACE("sys_mremap(%p, %'zu, %'zu, %#b, %p) → %p% m", p, n, m, f, q, rax);
return (void *)rax;
}

View file

@ -28,7 +28,7 @@ int sys_munmap(void *p, size_t n) {
} else {
rc = sys_munmap_metal(p, n);
}
STRACE("sys_munmap(%p%s, %'zu) → %d", p, DescribeFrame((intptr_t)p >> 16), n,
rc);
KERNTRACE("sys_munmap(%p%s, %'zu) → %d", p, DescribeFrame((intptr_t)p >> 16),
n, rc);
return rc;
}

View file

@ -29,8 +29,9 @@
textwindows noinstrument int sys_nanosleep_nt(const struct timespec *req,
struct timespec *rem) {
int rc;
int64_t sec, nsec;
uint64_t ms, slice;
bool alertable;
uint32_t slice;
int64_t ms, sec, nsec;
if (__builtin_mul_overflow(req->tv_sec, 1000, &ms) ||
__builtin_add_overflow(ms, req->tv_nsec / 1000000, &ms)) {
ms = -1;
@ -44,18 +45,20 @@ textwindows noinstrument int sys_nanosleep_nt(const struct timespec *req,
rc = eintr();
break;
}
if (ms > __SIG_POLLING_INTERVAL_MS) {
slice = __SIG_POLLING_INTERVAL_MS;
slice = MIN(__SIG_POLLING_INTERVAL_MS, ms);
if (__time_critical) {
alertable = false;
} else {
slice = ms;
alertable = true;
POLLTRACE("sys_nanosleep_nt polling for %'ldms of %'ld");
}
if (SleepEx(slice, true) == kNtWaitIoCompletion) {
STRACE("IOCP TRIGGERED EINTR");
rc = eintr();
break;
if (SleepEx(slice, alertable) == kNtWaitIoCompletion) {
POLLTRACE("IOCP EINTR");
continue;
}
ms -= slice;
} while (ms);
} while (ms > 0);
ms = MAX(ms, 0);
if (rem) {
sec = ms / 1000;
nsec = ms % 1000 * 1000000000;

View file

@ -61,6 +61,10 @@ ssize_t preadv(int fd, struct iovec *iov, int iovlen, int64_t off) {
return enosys();
}
if (iovlen == 1) {
return sys_pread(fd, iov[0].iov_base, iov[0].iov_len, off, off);
}
/*
* NT, 2018-era XNU, and 2007-era Linux don't support this system call
*/

View file

@ -65,6 +65,10 @@ ssize_t pwritev(int fd, const struct iovec *iov, int iovlen, int64_t off) {
return enosys();
}
if (iovlen == 1) {
return sys_pwrite(fd, iov[0].iov_base, iov[0].iov_len, off, off);
}
/*
* NT, 2018-era XNU, and 2007-era Linux don't support this system call
*/

View file

@ -65,10 +65,7 @@ int raise(int sig) {
// groups potentially. We just shouldn't use this because it
// doesn't make any sense and it's so evil.
if (GenerateConsoleCtrlEvent(event, 0)) {
// XXX: we shouldn't need to sleep here ctrl-c is evil on nt
if (SleepEx(100, true) == kNtWaitIoCompletion) {
STRACE("IOCP TRIGGERED EINTR");
}
SleepEx(100, true);
__sig_check(false);
rc = 0;
} else {

View file

@ -26,6 +26,7 @@
#include "libc/errno.h"
#include "libc/intrin/kprintf.h"
#include "libc/limits.h"
#include "libc/nt/enum/filetype.h"
#include "libc/nt/enum/wait.h"
#include "libc/nt/errors.h"
#include "libc/nt/files.h"
@ -40,15 +41,20 @@ static textwindows ssize_t sys_read_nt_impl(struct Fd *fd, void *data,
size_t size, ssize_t offset) {
uint32_t err, got, avail;
struct NtOverlapped overlap;
if (fd->worker) {
if (GetFileType(fd->handle) == kNtFileTypePipe) {
for (;;) {
if (!PeekNamedPipe(fd->handle, 0, 0, 0, &avail, 0)) break;
if (avail) break;
if (SleepEx(__SIG_POLLING_INTERVAL_MS, true) == kNtWaitIoCompletion ||
_check_interrupts(true, g_fds.p)) {
POLLTRACE("sys_read_nt polling");
if (SleepEx(__SIG_POLLING_INTERVAL_MS, true) == kNtWaitIoCompletion) {
POLLTRACE("IOCP EINTR");
}
if (_check_interrupts(true, g_fds.p)) {
POLLTRACE("sys_read_nt interrupted");
return eintr();
}
}
POLLTRACE("sys_read_nt ready to read");
}
if (ReadFile(fd->handle, data, _clampio(size), &got,
_offset2overlap(fd->handle, offset, &overlap))) {

View file

@ -61,7 +61,7 @@ textwindows ssize_t sys_readlinkat_nt(int dirfd, const char *path, char *buf,
rdb = (struct NtReparseDataBuffer *)buf;
freeme = 0;
} else {
STRACE("sys_readlinkat_nt() needs bigger buffer malloc() to be yoinked");
NTTRACE("sys_readlinkat_nt() needs bigger buffer malloc() to be yoinked");
return enomem();
}
if ((h = CreateFile(path16, 0, 0, 0, kNtOpenExisting,
@ -102,11 +102,11 @@ textwindows ssize_t sys_readlinkat_nt(int dirfd, const char *path, char *buf,
if (freeme || (intptr_t)(buf + j) <= (intptr_t)(p + i)) {
rc = j;
} else {
STRACE("sys_readlinkat_nt() too many astral codepoints");
NTTRACE("sys_readlinkat_nt() too many astral codepoints");
rc = enametoolong();
}
} else {
STRACE("sys_readlinkat_nt() should have kNtIoReparseTagSymlink");
NTTRACE("sys_readlinkat_nt() should have kNtIoReparseTagSymlink");
rc = einval();
}
} else {

View file

@ -29,6 +29,13 @@
/**
* Reads data to multiple buffers.
*
* This is the same thing as read() except it has multiple buffers.
* This yields a performance boost in situations where it'd be expensive
* to stitch data together using memcpy() or issuing multiple syscalls.
* This wrapper is implemented so that readv() calls where iovlen<2 may
* be passed to the kernel as read() instead. This yields a 100 cycle
* performance boost in the case of a single small iovec.
*
* @return number of bytes actually read, or -1 w/ errno
* @restartable
*/
@ -41,7 +48,11 @@ ssize_t readv(int fd, const struct iovec *iov, int iovlen) {
rc = weaken(__zipos_read)(
(struct ZiposHandle *)(intptr_t)g_fds.p[fd].handle, iov, iovlen, -1);
} else if (!IsWindows() && !IsMetal()) {
rc = sys_readv(fd, iov, iovlen);
if (iovlen == 1) {
rc = sys_read(fd, iov[0].iov_base, iov[0].iov_len);
} else {
rc = sys_readv(fd, iov, iovlen);
}
} else if (fd >= g_fds.n) {
rc = ebadf();
} else if (IsMetal()) {

View file

@ -90,7 +90,7 @@ int __reservefd(int start) {
*/
static void __freefds(void) {
int i;
STRACE("__freefds()");
NTTRACE("__freefds()");
for (i = 3; i < g_fds.n; ++i) {
if (g_fds.p[i].kind) {
close(i);

View file

@ -42,6 +42,10 @@
#include "libc/sysv/consts/sig.h"
#include "libc/sysv/errfuns.h"
#ifdef SYSDEBUG
STATIC_YOINK("strsignal"); // for kprintf()
#endif
#define SA_RESTORER 0x04000000
#ifndef SWITCHEROO

View file

@ -78,15 +78,14 @@ int sigsuspend(const sigset_t *ignore) {
break;
}
if (SleepEx(__SIG_POLLING_INTERVAL_MS, true) == kNtWaitIoCompletion) {
STRACE("IOCP TRIGGERED EINTR");
rc = eintr();
break;
POLLTRACE("IOCP EINTR");
continue;
}
#ifdef SYSDEBUG
#if defined(SYSDEBUG) && defined(_POLLTRACE)
ms += __SIG_POLLING_INTERVAL_MS;
if (ms >= __SIG_LOGGING_INTERVAL_MS) {
totoms += ms, ms = 0;
STRACE("... sigsuspending for %'lums...", totoms);
POLLTRACE("... sigsuspending for %'lums...", totoms);
}
#endif
} while (1);

View file

@ -4,6 +4,11 @@
#include "libc/calls/struct/sigaction.h"
#include "libc/calls/struct/stat.h"
#define _NT_RLIMIT_PWSS_MB 1000 /* nocommit */
#define _KERNTRACE 0 /* not configurable w/ flag yet */
#define _POLLTRACE 0 /* not configurable w/ flag yet */
#define _NTTRACE 0 /* not configurable w/ flag yet */
#define STRACE_PROLOGUE "%rSYS %5P %'18T "
#if !(__ASSEMBLER__ + __LINKER__ + 0)
@ -20,6 +25,24 @@ COSMOPOLITAN_C_START_
#define STRACE(FMT, ...) (void)0
#endif
#if defined(SYSDEBUG) && _POLLTRACE
#define POLLTRACE(FMT, ...) STRACE(FMT, ##__VA_ARGS__)
#else
#define POLLTRACE(FMT, ...) (void)0
#endif
#if defined(SYSDEBUG) && _KERNTRACE
#define KERNTRACE(FMT, ...) STRACE(FMT, ##__VA_ARGS__)
#else
#define KERNTRACE(FMT, ...) (void)0
#endif
#if defined(SYSDEBUG) && _NTTRACE
#define NTTRACE(FMT, ...) STRACE(FMT, ##__VA_ARGS__)
#else
#define NTTRACE(FMT, ...) (void)0
#endif
extern int __strace;
void __stracef(const char *, ...);

View file

@ -86,7 +86,7 @@ int uname(struct utsname *lool) {
}
} else {
v = NtGetVersion();
p = lool->version;
p = lool->release;
p = FormatUint32(p, NtGetMajorVersion()), *p++ = '.';
p = FormatUint32(p, NtGetMinorVersion()), *p++ = '-';
p = FormatUint32(p, NtGetBuildNumber());

View file

@ -28,6 +28,13 @@
/**
* Writes data from multiple buffers.
*
* This is the same thing as write() except it has multiple buffers.
* This yields a performance boost in situations where it'd be expensive
* to stitch data together using memcpy() or issuing multiple syscalls.
* This wrapper is implemented so that writev() calls where iovlen<2 may
* be passed to the kernel as write() instead. This yields a 100 cycle
* performance boost in the case of a single small iovec.
*
* Please note that it's not an error for a short write to happen. This
* can happen in the kernel if EINTR happens after some of the write has
* been committed. It can also happen if we need to polyfill this system
@ -45,7 +52,11 @@ ssize_t writev(int fd, const struct iovec *iov, int iovlen) {
rc = weaken(__zipos_write)(
(struct ZiposHandle *)(intptr_t)g_fds.p[fd].handle, iov, iovlen, -1);
} else if (!IsWindows() && !IsMetal()) {
rc = sys_writev(fd, iov, iovlen);
if (iovlen == 1) {
rc = sys_write(fd, iov[0].iov_base, iov[0].iov_len);
} else {
rc = sys_writev(fd, iov, iovlen);
}
} else if (fd >= g_fds.n) {
rc = ebadf();
} else if (IsMetal()) {

View file

@ -72,15 +72,11 @@ _start:
mov %rdi,%rcx # auxv
#if SupportsXnu()
// should probably be removed in favor of newer apis
// xnu doesn't have auxiliary values
testb IsXnu()
jz 1f # polyfill xnu auxv
push $0 # auxv[1][1]=0
push $0 # auxv[1][0]=0
mov (%rcx),%rax # executable_path=BIN
lea 16(%rax),%rax # BIN
push %rax # auxv[0][0]=BIN
push $31 # auxv[0][0]=AT_EXECFN
mov %rsp,%rcx # auxv
#endif

View file

@ -36,6 +36,6 @@ textwindows bool32 CloseHandle(int64_t hObject) {
__winerr();
if (weaken(__die)) weaken(__die)();
}
STRACE("CloseHandle(%ld) → %hhhd% m", hObject, ok);
NTTRACE("CloseHandle(%ld) → %hhhd% m", hObject, ok);
return ok;
}

View file

@ -36,7 +36,7 @@ CreateDirectory(const char16_t *lpPathName,
bool32 ok;
ok = __imp_CreateDirectoryW(lpPathName, lpSecurityAttributes);
if (!ok) __winerr();
STRACE("CreateDirectory(%#hs, %s) → %hhhd% m", lpPathName,
DescribeNtSecurityAttributes(lpSecurityAttributes), ok);
NTTRACE("CreateDirectory(%#hs, %s) → %hhhd% m", lpPathName,
DescribeNtSecurityAttributes(lpSecurityAttributes), ok);
return ok;
}

View file

@ -40,12 +40,12 @@ textwindows int64_t CreateFile(
opt_lpSecurityAttributes, dwCreationDisposition,
dwFlagsAndAttributes, opt_hTemplateFile);
if (hHandle == -1) __winerr();
STRACE("CreateFile(%#hs, %s, %s, %s, %s, %s, %ld) → %ld% m", lpFileName,
DescribeNtFileAccessFlags(dwDesiredAccess),
DescribeNtFileShareFlags(dwShareMode),
DescribeNtSecurityAttributes(opt_lpSecurityAttributes),
DescribeNtCreationDisposition(dwCreationDisposition),
DescribeNtFileFlagsAndAttributes(dwFlagsAndAttributes),
opt_hTemplateFile, hHandle);
NTTRACE("CreateFile(%#hs, %s, %s, %s, %s, %s, %ld) → %ld% m", lpFileName,
DescribeNtFileAccessFlags(dwDesiredAccess),
DescribeNtFileShareFlags(dwShareMode),
DescribeNtSecurityAttributes(opt_lpSecurityAttributes),
DescribeNtCreationDisposition(dwCreationDisposition),
DescribeNtFileFlagsAndAttributes(dwFlagsAndAttributes),
opt_hTemplateFile, hHandle);
return hHandle;
}

View file

@ -43,10 +43,10 @@ textwindows int64_t CreateFileMapping(
flProtect, dwMaximumSizeHigh,
dwMaximumSizeLow, opt_lpName);
if (!hHandle) __winerr();
STRACE("CreateFileMapping(%ld, %s, %s, %'zu, %#hs) → %ld% m", opt_hFile,
DescribeNtSecurityAttributes(opt_lpFileMappingAttributes),
DescribeNtPageFlags(flProtect),
(uint64_t)dwMaximumSizeHigh << 32 | dwMaximumSizeLow, opt_lpName,
hHandle);
NTTRACE("CreateFileMapping(%ld, %s, %s, %'zu, %#hs) → %ld% m", opt_hFile,
DescribeNtSecurityAttributes(opt_lpFileMappingAttributes),
DescribeNtPageFlags(flProtect),
(uint64_t)dwMaximumSizeHigh << 32 | dwMaximumSizeLow, opt_lpName,
hHandle);
return hHandle;
}

View file

@ -44,10 +44,10 @@ textwindows int64_t CreateFileMappingNuma(
opt_hFile, opt_lpFileMappingAttributes, flProtect, dwMaximumSizeHigh,
dwMaximumSizeLow, opt_lpName, nndDesiredNumaNode);
if (!hHandle) __winerr();
STRACE("CreateFileMappingNuma(%ld, %s, %s, %'zu, %#hs) → %ld% m", opt_hFile,
DescribeNtSecurityAttributes(opt_lpFileMappingAttributes),
DescribeNtPageFlags(flProtect),
(uint64_t)dwMaximumSizeHigh << 32 | dwMaximumSizeLow, opt_lpName,
hHandle);
NTTRACE("CreateFileMappingNuma(%ld, %s, %s, %'zu, %#hs) → %ld% m", opt_hFile,
DescribeNtSecurityAttributes(opt_lpFileMappingAttributes),
DescribeNtPageFlags(flProtect),
(uint64_t)dwMaximumSizeHigh << 32 | dwMaximumSizeLow, opt_lpName,
hHandle);
return hHandle;
}

View file

@ -41,10 +41,10 @@ textwindows int64_t CreateNamedPipe(
nMaxInstances, nOutBufferSize, nInBufferSize,
nDefaultTimeOutMs, opt_lpSecurityAttributes);
if (hServer == -1) __winerr();
STRACE("CreateNamedPipe(%#hs, %s, %s, %u, %'u, %'u, %'u, %s) → %ld% m",
lpName, DescribeNtPipeOpenFlags(dwOpenMode),
DescribeNtPipeModeFlags(dwPipeMode), nMaxInstances, nOutBufferSize,
nInBufferSize, nDefaultTimeOutMs,
DescribeNtSecurityAttributes(opt_lpSecurityAttributes), hServer);
NTTRACE("CreateNamedPipe(%#hs, %s, %s, %u, %'u, %'u, %'u, %s) → %ld% m",
lpName, DescribeNtPipeOpenFlags(dwOpenMode),
DescribeNtPipeModeFlags(dwPipeMode), nMaxInstances, nOutBufferSize,
nInBufferSize, nDefaultTimeOutMs,
DescribeNtSecurityAttributes(opt_lpSecurityAttributes), hServer);
return hServer;
}

View file

@ -36,8 +36,8 @@ textwindows bool32 CreatePipe(
ok = __imp_CreatePipe(out_hReadPipe, out_hWritePipe, opt_lpPipeAttributes,
nSize);
if (!ok) __winerr();
STRACE("CreatePipe([%ld], [%ld], %s, %'zu) → %hhhd% m", *out_hReadPipe,
*out_hWritePipe, DescribeNtSecurityAttributes(opt_lpPipeAttributes),
nSize, ok);
NTTRACE("CreatePipe([%ld], [%ld], %s, %'zu) → %hhhd% m", *out_hReadPipe,
*out_hWritePipe, DescribeNtSecurityAttributes(opt_lpPipeAttributes),
nSize, ok);
return ok;
}

View file

@ -44,7 +44,7 @@ CreateProcess(const char16_t *opt_lpApplicationName, char16_t *lpCommandLine,
opt_lpCurrentDirectory, lpStartupInfo,
opt_out_lpProcessInformation);
if (!ok) __winerr();
STRACE(
NTTRACE(
"CreateFile(%#hs, %#hs, %s, %s, %hhhd, %u, %p, %#hs, %p, %p) → %hhhd% m",
opt_lpApplicationName, lpCommandLine,
DescribeNtSecurityAttributes(opt_lpProcessAttributes),

View file

@ -39,8 +39,9 @@ textwindows int64_t CreateThread(
hHandle = __imp_CreateThread(lpThreadAttributes, dwStackSize, lpStartAddress,
lpParameter, dwCreationFlags, opt_lpThreadId);
if (hHandle == -1) __winerr();
STRACE("CreateThread(%s, %'zu, %p, %p, %s, %p) → %ld% m",
DescribeNtSecurityAttributes(lpThreadAttributes), dwStackSize,
lpStartAddress, lpParameter, dwCreationFlags, opt_lpThreadId, hHandle);
NTTRACE("CreateThread(%s, %'zu, %p, %p, %s, %p) → %ld% m",
DescribeNtSecurityAttributes(lpThreadAttributes), dwStackSize,
lpStartAddress, lpParameter, dwCreationFlags, opt_lpThreadId,
hHandle);
return hHandle;
}

View file

@ -36,7 +36,6 @@
void __cxa_finalize(void *pred) {
unsigned i, mask;
struct CxaAtexitBlock *b, *b2;
STRACE("__cxa_finalize()");
StartOver:
if ((b = __cxa_blocks.p)) {
for (;;) {
@ -47,6 +46,7 @@ StartOver:
if (!pred || pred == b->p[i].pred) {
b->mask &= ~(1u << i);
if (b->p[i].fp) {
STRACE("__cxa_finalize(%t, %p)", b->p[i].fp, b->p[i].arg);
((void (*)(void *))b->p[i].fp)(b->p[i].arg);
goto StartOver;
}

View file

@ -32,6 +32,6 @@ textwindows bool32 DeleteFile(const char16_t *lpPathName) {
bool32 ok;
ok = __imp_DeleteFileW(lpPathName);
if (!ok) __winerr();
STRACE("DeleteFile(%#hs) → %hhhd% m", lpPathName, ok);
NTTRACE("DeleteFile(%#hs) → %hhhd% m", lpPathName, ok);
return ok;
}

View file

@ -40,8 +40,8 @@ textwindows bool32 DeviceIoControl(int64_t hDevice, uint32_t dwIoControlCode,
nInBufferSize, lpOutBuffer, nOutBufferSize,
lpBytesReturned, lpOverlapped);
if (!ok) __winerr();
STRACE("DeviceIoControl(%ld, %#x, %p, %'zu, %p, %'zu, %p, %p) → %hhhd% m",
hDevice, dwIoControlCode, lpInBuffer, nInBufferSize, lpOutBuffer,
nOutBufferSize, lpBytesReturned, lpOverlapped, ok);
NTTRACE("DeviceIoControl(%ld, %#x, %p, %'zu, %p, %'zu, %p, %p) → %hhhd% m",
hDevice, dwIoControlCode, lpInBuffer, nInBufferSize, lpOutBuffer,
nOutBufferSize, lpBytesReturned, lpOverlapped, ok);
return ok;
}

View file

@ -31,6 +31,6 @@ textwindows bool32 FindClose(int64_t hFindFile) {
bool32 ok;
ok = __imp_FindClose(hFindFile);
if (!ok) __winerr();
STRACE("FindClose(%ld) → %hhhd% m", hFindFile, ok);
NTTRACE("FindClose(%ld) → %hhhd% m", hFindFile, ok);
return ok;
}

View file

@ -35,7 +35,7 @@ textwindows int64_t FindFirstFile(const char16_t *lpFileName,
int64_t hFindFile;
hFindFile = __imp_FindFirstFileW(lpFileName, out_lpFindFileData);
if (hFindFile != -1) {
STRACE(
NTTRACE(
"FindFirstFile(%#hs, [{"
".cFileName=%#hs, "
".dwFileAttributes=%s, "
@ -46,7 +46,7 @@ textwindows int64_t FindFirstFile(const char16_t *lpFileName,
DescribeNtFiletypeFlags(out_lpFindFileData->dwFileType), hFindFile);
} else {
__winerr();
STRACE("FindFirstFile(%#hs, [n/a]) → %ld% m", lpFileName, hFindFile);
NTTRACE("FindFirstFile(%#hs, [n/a]) → %ld% m", lpFileName, hFindFile);
}
return hFindFile;
}

View file

@ -37,7 +37,7 @@ textwindows bool32 FindNextFile(int64_t hFindFile,
bool32 ok;
ok = __imp_FindNextFileW(hFindFile, out_lpFindFileData);
if (ok) {
STRACE(
NTTRACE(
"FindNextFile(%ld, [{"
".cFileName=%#hs, "
".dwFileAttributes=%s, "
@ -48,7 +48,7 @@ textwindows bool32 FindNextFile(int64_t hFindFile,
DescribeNtFiletypeFlags(out_lpFindFileData->dwFileType), ok);
} else {
if (GetLastError() != kNtErrorNoMoreFiles) __winerr();
STRACE("FindNextFile(%ld) → %hhhd% m", hFindFile, ok);
NTTRACE("FindNextFile(%ld) → %hhhd% m", hFindFile, ok);
}
return ok;
}

View file

@ -38,6 +38,6 @@ textwindows bool32 FlushFileBuffers(int64_t hFile) {
bool32 ok;
ok = __imp_FlushFileBuffers(hFile);
if (!ok) __winerr();
STRACE("FlushFileBuffers(%ld) → %hhhd% m", hFile, ok);
NTTRACE("FlushFileBuffers(%ld) → %hhhd% m", hFile, ok);
return ok;
}

View file

@ -37,7 +37,7 @@ textwindows bool32 FlushViewOfFile(const void *lpBaseAddress,
bool32 ok;
ok = __imp_FlushViewOfFile(lpBaseAddress, dwNumberOfBytesToFlush);
if (!ok) __winerr();
STRACE("FlushViewOfFile(%p, %'zu) → %hhhd% m", lpBaseAddress,
dwNumberOfBytesToFlush, ok);
NTTRACE("FlushViewOfFile(%p, %'zu) → %hhhd% m", lpBaseAddress,
dwNumberOfBytesToFlush, ok);
return ok;
}

View file

@ -35,7 +35,7 @@ textwindows bool32 GenerateConsoleCtrlEvent(uint32_t dwCtrlEvent,
bool32 ok;
ok = __imp_GenerateConsoleCtrlEvent(dwCtrlEvent, dwProcessGroupId);
if (!ok) __winerr();
STRACE("GenerateConsoleCtrlEvent(%x, %d) → %hhhd% m", dwCtrlEvent,
dwProcessGroupId, ok);
NTTRACE("GenerateConsoleCtrlEvent(%x, %d) → %hhhd% m", dwCtrlEvent,
dwProcessGroupId, ok);
return ok;
}

View file

@ -21,6 +21,7 @@
#include "libc/dce.h"
#include "libc/errno.h"
#include "libc/intrin/kprintf.h"
#include "libc/log/libfatal.internal.h"
#include "libc/runtime/runtime.h"
forceinline int Identity(int c) {
@ -66,6 +67,11 @@ char *getenv(const char *s) {
} else {
r = GetEnv(s, ToUpper);
}
STRACE("getenv(%#s) → %#s", s, r);
#if SYSDEBUG
if (!(s[0] == 'T' && s[1] == 'Z' && !s[2])) {
// TODO(jart): memoize TZ or something
STRACE("getenv(%#s) → %#s", s, r);
}
#endif
return r;
}

View file

@ -35,7 +35,7 @@ textwindows uint32_t GetFileAttributes(const char16_t *lpPathName) {
uint32_t flags;
flags = __imp_GetFileAttributesW(lpPathName);
if (flags == -1u) __winerr();
STRACE("GetFileAttributes(%#hs) → %s% m", lpPathName,
DescribeNtFileFlagsAndAttributes(flags));
NTTRACE("GetFileAttributes(%#hs) → %s% m", lpPathName,
DescribeNtFileFlagsAndAttributes(flags));
return flags;
}

View file

@ -40,6 +40,7 @@
#include "libc/nt/winsock.h"
#include "libc/runtime/memtrack.internal.h"
#include "libc/runtime/runtime.h"
#include "libc/runtime/symbols.internal.h"
#include "libc/str/str.h"
#include "libc/str/tpenc.h"
#include "libc/str/utf16.h"
@ -515,19 +516,27 @@ privileged static size_t kformat(char *b, size_t n, const char *fmt, va_list va,
case 'G':
x = va_arg(va, int);
if (weaken(strsignal)) {
s = weaken(strsignal)(x);
if (weaken(strsignal) && (s = weaken(strsignal)(x))) {
goto FormatString;
} else {
if (p + 3 <= e) {
p[0] = 'S';
p[1] = 'I';
p[2] = 'G';
}
p += 3;
goto FormatDecimal;
}
case 't': {
int idx;
x = va_arg(va, intptr_t);
if (weaken(__get_symbol) &&
(idx = weaken(__get_symbol)(0, x)) != -1) {
if (p + 1 <= e) *p++ = '&';
s = weaken(GetSymbolTable)()->name_base +
weaken(GetSymbolTable)()->names[idx];
goto FormatString;
}
base = 4;
hash = '&';
goto FormatNumber;
}
case 'n':
// nonstandard %n specifier
// used to print newlines that work in raw terminal modes
@ -558,8 +567,8 @@ privileged static size_t kformat(char *b, size_t n, const char *fmt, va_list va,
if (!(s = va_arg(va, const void *))) {
s = sign != ' ' ? "NULL" : "";
FormatString:
type = 0;
hash = 0;
type = 0;
} else if (!dang && (kisdangerous(s) || kischarmisaligned(s, type))) {
if (sign == ' ') {
if (p < e) *p = ' ';
@ -847,6 +856,7 @@ privileged void kvprintf(const char *fmt, va_list v) {
* - `o` octal
* - `b` binary
* - `s` string
* - `t` symbol
* - `p` pointer
* - `d` decimal
* - `n` newline
@ -885,6 +895,10 @@ privileged void kvprintf(const char *fmt, va_list v) {
* - `% m` formats error with leading space if errno isn't zero
* - `%lm` means favor WSAGetLastError() over GetLastError() if linked
*
* You need to link and load the symbol table before `%t` will work. You
* can do that by calling `GetSymbolTable()`. If that hasn't happened it
* will print `&hexnumber` instead.
*
* @asyncsignalsafe
* @vforksafe
*/

View file

@ -45,9 +45,9 @@ textwindows void *MapViewOfFileEx(int64_t hFileMappingObject,
hFileMappingObject, dwDesiredAccess, dwFileOffsetHigh, dwFileOffsetLow,
dwNumberOfBytesToMap, opt_lpDesiredBaseAddress);
if (!pStartingAddress) __winerr();
STRACE("MapViewOfFileEx(%ld, %s, %'ld, %'zu, %p) → %p% m", hFileMappingObject,
DescribeNtFileMapFlags(dwDesiredAccess),
(uint64_t)dwFileOffsetHigh << 32 | dwFileOffsetLow,
dwNumberOfBytesToMap, opt_lpDesiredBaseAddress, pStartingAddress);
NTTRACE("MapViewOfFileEx(%ld, %s, %'ld, %'zu, %p) → %p% m",
hFileMappingObject, DescribeNtFileMapFlags(dwDesiredAccess),
(uint64_t)dwFileOffsetHigh << 32 | dwFileOffsetLow,
dwNumberOfBytesToMap, opt_lpDesiredBaseAddress, pStartingAddress);
return pStartingAddress;
}

View file

@ -47,9 +47,9 @@ textwindows void *MapViewOfFileExNuma(int64_t hFileMappingObject,
hFileMappingObject, dwDesiredAccess, dwFileOffsetHigh, dwFileOffsetLow,
dwNumberOfBytesToMap, opt_lpDesiredBaseAddress, nndDesiredNumaNode);
if (!pStartingAddress) __winerr();
STRACE("MapViewOfFileExNuma(%ld, %s, %'ld, %'zu, %p) → %p% m",
hFileMappingObject, DescribeNtFileMapFlags(dwDesiredAccess),
(uint64_t)dwFileOffsetHigh << 32 | dwFileOffsetLow,
dwNumberOfBytesToMap, opt_lpDesiredBaseAddress, pStartingAddress);
NTTRACE("MapViewOfFileExNuma(%ld, %s, %'ld, %'zu, %p) → %p% m",
hFileMappingObject, DescribeNtFileMapFlags(dwDesiredAccess),
(uint64_t)dwFileOffsetHigh << 32 | dwFileOffsetLow,
dwNumberOfBytesToMap, opt_lpDesiredBaseAddress, pStartingAddress);
return pStartingAddress;
}

View file

@ -39,8 +39,8 @@ textwindows int64_t OpenProcess(uint32_t dwDesiredAccess, bool32 bInheritHandle,
int64_t hHandle;
hHandle = __imp_OpenProcess(dwDesiredAccess, bInheritHandle, dwProcessId);
if (!hHandle) __winerr();
STRACE("OpenProcess(%s, %hhhd, %u) → %ld% m",
DescribeNtProcessAccessFlags(dwDesiredAccess), bInheritHandle,
dwProcessId, hHandle);
NTTRACE("OpenProcess(%s, %hhhd, %u) → %ld% m",
DescribeNtProcessAccessFlags(dwDesiredAccess), bInheritHandle,
dwProcessId, hHandle);
return hHandle;
}

View file

@ -32,6 +32,6 @@ textwindows bool32 RemoveDirectory(const char16_t *lpPathName) {
bool32 ok;
ok = __imp_RemoveDirectoryW(lpPathName);
if (!ok) __winerr();
STRACE("RemoveDirectory(%#hs) → %hhhd% m", lpPathName, ok);
NTTRACE("RemoveDirectory(%#hs) → %hhhd% m", lpPathName, ok);
return ok;
}

View file

@ -36,9 +36,9 @@ int64_t ReOpenFile(int64_t hOriginalFile, uint32_t dwDesiredAccess,
hHandle = __imp_ReOpenFile(hOriginalFile, dwDesiredAccess, dwShareMode,
dwFlagsAndAttributes);
if (hHandle == -1) __winerr();
STRACE("ReOpenFile(%ld, %s, %s, %s) → %ld% m", hOriginalFile,
DescribeNtFileAccessFlags(dwDesiredAccess),
DescribeNtFileShareFlags(dwShareMode),
DescribeNtFileFlagsAndAttributes(dwFlagsAndAttributes), hHandle);
NTTRACE("ReOpenFile(%ld, %s, %s, %s) → %ld% m", hOriginalFile,
DescribeNtFileAccessFlags(dwDesiredAccess),
DescribeNtFileShareFlags(dwShareMode),
DescribeNtFileFlagsAndAttributes(dwFlagsAndAttributes), hHandle);
return hHandle;
}

View file

@ -37,7 +37,7 @@ const char kConsoleHandles[3] = {
noasan void __restorewintty(void) {
int i;
if (!IsWindows()) return;
STRACE("__restorewintty()");
NTTRACE("__restorewintty()");
if (GetCurrentProcessId() == __winmainpid) {
for (i = 0; i < 3; ++i) {
SetConsoleMode(GetStdHandle(kConsoleHandles[i]), __ntconsolemode[i]);

View file

@ -32,6 +32,6 @@ textwindows bool32 SetCurrentDirectory(const char16_t *lpPathName) {
bool32 ok;
ok = __imp_SetCurrentDirectoryW(lpPathName);
if (!ok) __winerr();
STRACE("SetCurrentDirectory(%#hs) → %hhhd% m", lpPathName, ok);
NTTRACE("SetCurrentDirectory(%#hs) → %hhhd% m", lpPathName, ok);
return ok;
}

View file

@ -32,6 +32,6 @@ textwindows bool32 TerminateProcess(int64_t hProcess, uint32_t uExitCode) {
bool32 ok;
ok = __imp_TerminateProcess(hProcess, uExitCode);
if (!ok) __winerr();
STRACE("TerminateProcess(%ld, %u) → %hhhd% m", hProcess, uExitCode, ok);
NTTRACE("TerminateProcess(%ld, %u) → %hhhd% m", hProcess, uExitCode, ok);
return ok;
}

View file

@ -30,6 +30,6 @@ textwindows bool32 UnmapViewOfFile(const void *lpBaseAddress) {
bool32 ok;
ok = __imp_UnmapViewOfFile(lpBaseAddress);
if (!ok) __winerr();
STRACE("UnmapViewOfFile(%p) → %hhhd% m", lpBaseAddress, ok);
NTTRACE("UnmapViewOfFile(%p) → %hhhd% m", lpBaseAddress, ok);
return ok;
}

View file

@ -40,7 +40,7 @@ textwindows bool32 VirtualProtect(void *lpAddress, uint64_t dwSize,
__winerr();
__stpcpy(oldbuf, "n/a");
}
STRACE("VirtualProtect(%p, %'zu, %s, [%s]) → %hhhd% m", lpAddress, dwSize,
DescribeNtPageFlags(flNewProtect), oldbuf, bOk);
NTTRACE("VirtualProtect(%p, %'zu, %s, [%s]) → %hhhd% m", lpAddress, dwSize,
DescribeNtPageFlags(flNewProtect), oldbuf, bOk);
return bOk;
}

View file

@ -22,6 +22,7 @@
#include "libc/log/internal.h"
#include "libc/log/log.h"
#include "libc/macros.internal.h"
#include "libc/runtime/symbols.internal.h"
#include "libc/sysv/consts/sa.h"
#include "libc/sysv/consts/sig.h"
#include "libc/sysv/consts/ss.h"
@ -79,4 +80,5 @@ void ShowCrashReports(void) {
sigaction(kCrashSigs[i], &sa, &g_oldcrashacts[i]);
}
}
GetSymbolTable();
}

View file

@ -149,29 +149,6 @@
pop \dest
.endm
// Loads address of linktime mergeable string literal into register.
.macro getstr text:req reg64:req reg32 regsz64 regsz32 bias=0
.section .rodata.str1.1,"aSM",@progbits,1
.type .Lstr\@,@object
.Lstr\@: .asciz "\text"
.Lstr\@.size = .-.Lstr\@ - 1
.size .Lstr\@,.-.Lstr\@
.previous
plea .Lstr\@,\reg64,\reg32
.ifnb \regsz64
#ifdef __OPTIMIZE_SIZE__
.if .Lstr\@.size + \bias < 128
pushpop .Lstr\@.size,\regsz64
.else
mov $.Lstr\@.size,\regsz32
.endif
#else
mov $.Lstr\@.size,\regsz32
#endif
.endif
.endm
// TODO(jart): delete
// Loads address of linktime mergeable string literal into register.
.macro loadstr text:req reg:req regsz bias=0
.section .rodata.str1.1,"aSM",@progbits,1

View file

@ -125,7 +125,7 @@ static textstartup void getrandom_init(void) {
if (!(rc = sys_getrandom(0, 0, 0))) {
have_getrandom = true;
}
STRACE("sys_getrandom(0,0,0) → %d% m");
KERNTRACE("sys_getrandom(0,0,0) → %d% m");
errno = e;
}

View file

@ -90,11 +90,14 @@ cosmo: push %rbp
#if IsModeDbg()
#ifdef SYSDEBUG
.init.start 307,_init_printargs
cmpl $0,__strace(%rip)
jz 1f
push %rdi
push %rsi
loadstr STRACE_PROLOGUE,di
call __printargs
pop %rsi
pop %rdi
.init.end 307,_init_printargs
1: .init.end 307,_init_printargs
#endif
#endif

View file

@ -52,6 +52,7 @@
STATIC_YOINK("_check_sigchld");
extern int __pid;
extern int64_t __wincrashearly;
extern unsigned long long __kbirth;
extern unsigned char __data_start[]; /* αpε */
extern unsigned char __data_end[]; /* αpε */
@ -59,6 +60,11 @@ extern unsigned char __bss_start[]; /* αpε */
extern unsigned char __bss_end[]; /* αpε */
bool32 __onntconsoleevent_nt(uint32_t);
static textwindows wontreturn void KillForkChild(const char *func) {
STRACE("fork() %s() failed %d", func, GetLastError());
ExitProcess(177);
}
static textwindows char16_t *ParseInt(char16_t *p, int64_t *x) {
*x = 0;
while (*p == ' ') p++;
@ -84,7 +90,7 @@ static inline textwindows ssize_t ForkIo(int64_t h, char *p, size_t n,
static dontinline textwindows bool ForkIo2(int64_t h, void *buf, size_t n,
bool32 (*fn)(), const char *sf) {
ssize_t rc = ForkIo(h, buf, n, fn);
// STRACE("%s(%ld, %'zu) → %'zd% m", sf, h, n, rc);
NTTRACE("%s(%ld, %'zu) → %'zd% m", sf, h, n, rc);
return rc != -1;
}
@ -92,8 +98,10 @@ static dontinline textwindows bool WriteAll(int64_t h, void *buf, size_t n) {
return ForkIo2(h, buf, n, WriteFile, "WriteFile");
}
static textwindows dontinline bool ReadAll(int64_t h, void *buf, size_t n) {
return ForkIo2(h, buf, n, ReadFile, "ReadFile");
static textwindows dontinline void ReadOrDie(int64_t h, void *buf, size_t n) {
if (!ForkIo2(h, buf, n, ReadFile, "ReadFile")) {
KillForkChild("ReadFile");
}
}
textwindows void WinMainForked(void) {
@ -114,7 +122,7 @@ textwindows void WinMainForked(void) {
// this variable should have the pipe handle numba
varlen = GetEnvironmentVariable(u"_FORK", fvar, ARRAYLEN(fvar));
if (!varlen || varlen >= ARRAYLEN(fvar)) return;
STRACE("WinMainForked()");
NTTRACE("WinMainForked()");
SetEnvironmentVariable(u"_FORK", NULL);
ParseInt(fvar, &reader);
@ -123,21 +131,21 @@ textwindows void WinMainForked(void) {
// this is stored in a special secretive memory map!
// read ExtendMemoryIntervals for further details :|
maps = (void *)kMemtrackStart;
ReadAll(reader, jb, sizeof(jb));
ReadAll(reader, &mapcount, sizeof(_mmi.i));
ReadAll(reader, &mapcapacity, sizeof(_mmi.n));
ReadOrDie(reader, jb, sizeof(jb));
ReadOrDie(reader, &mapcount, sizeof(_mmi.i));
ReadOrDie(reader, &mapcapacity, sizeof(_mmi.n));
specialz = ROUNDUP(mapcapacity * sizeof(_mmi.p[0]), kMemtrackGran);
MapViewOfFileEx(
CreateFileMapping(-1, 0, kNtPageReadwrite, specialz >> 32, specialz, 0),
kNtFileMapWrite, 0, 0, specialz, maps);
ReadAll(reader, maps, mapcount * sizeof(_mmi.p[0]));
ReadOrDie(reader, maps, mapcount * sizeof(_mmi.p[0]));
if (IsAsan()) {
shad = (char *)(((intptr_t)maps >> 3) + 0x7fff8000);
size = ROUNDUP(specialz >> 3, FRAMESIZE);
MapViewOfFileEx(
CreateFileMapping(-1, 0, kNtPageReadwrite, size >> 32, size, 0),
kNtFileMapWrite, 0, 0, size, maps);
ReadAll(reader, shad, (mapcount * sizeof(_mmi.p[0])) >> 3);
ReadOrDie(reader, shad, (mapcount * sizeof(_mmi.p[0])) >> 3);
}
// read the heap mappings from the parent process
@ -152,7 +160,7 @@ textwindows void WinMainForked(void) {
upsize >> 32, upsize, 0);
MapViewOfFileEx(maps[i].h, kNtFileMapWrite | kNtFileMapExecute, 0, 0,
upsize, addr);
ReadAll(reader, addr, size);
ReadOrDie(reader, addr, size);
} else {
// we can however safely inherit MAP_SHARED with zero copy
MapViewOfFileEx(maps[i].h,
@ -167,8 +175,8 @@ textwindows void WinMainForked(void) {
savepid = __pid;
savebir = __kbirth;
savetsc = ts;
ReadAll(reader, __data_start, __data_end - __data_start);
ReadAll(reader, __bss_start, __bss_end - __bss_start);
ReadOrDie(reader, __data_start, __data_end - __data_start);
ReadOrDie(reader, __bss_start, __bss_end - __bss_start);
__pid = savepid;
__kbirth = savebir;
ts = savetsc;
@ -177,23 +185,28 @@ textwindows void WinMainForked(void) {
_mmi.p = maps;
_mmi.n = specialz / sizeof(_mmi.p[0]);
for (i = 0; i < mapcount; ++i) {
VirtualProtect((void *)((uint64_t)maps[i].x << 16), maps[i].size,
__prot2nt(maps[i].prot, maps[i].iscow), &oldprot);
if (!VirtualProtect((void *)((uint64_t)maps[i].x << 16), maps[i].size,
__prot2nt(maps[i].prot, maps[i].iscow), &oldprot)) {
KillForkChild("VirtualProtect");
}
}
// mitosis complete
CloseHandle(reader);
if (!CloseHandle(reader)) {
KillForkChild("CloseHandle");
}
// rewrap the stdin named pipe hack
// since the handles closed on fork
if (weaken(ForkNtStdinWorker)) weaken(ForkNtStdinWorker)();
struct Fds *fds = VEIL("r", &g_fds);
fds->__init_p[0].handle = GetStdHandle(kNtStdInputHandle); // just in case
fds->__init_p[1].handle = GetStdHandle(kNtStdOutputHandle); // just in case
fds->__init_p[2].handle = GetStdHandle(kNtStdErrorHandle); // just in case
fds->__init_p[0].handle = GetStdHandle(kNtStdInputHandle);
fds->__init_p[1].handle = GetStdHandle(kNtStdOutputHandle);
fds->__init_p[2].handle = GetStdHandle(kNtStdErrorHandle);
// restore the crash reporting stuff
if (weaken(__wincrash_nt)) {
RemoveVectoredExceptionHandler(__wincrashearly);
AddVectoredExceptionHandler(1, (void *)weaken(__wincrash_nt));
}
if (weaken(__onntconsoleevent_nt)) {

View file

@ -48,9 +48,8 @@ void ftrace_hook(void);
bool ftrace_enabled;
static int g_skew;
static int g_lastsymbol;
static uint64_t laststamp;
static struct SymbolTable *g_symbols;
static int64_t g_lastaddr;
static uint64_t g_laststamp;
static privileged noinstrument noasan noubsan int GetNestingLevelImpl(
struct StackFrame *frame) {
@ -80,34 +79,31 @@ static privileged noinstrument noasan noubsan int GetNestingLevel(
*/
privileged noinstrument noasan noubsan void ftracer(void) {
/* asan runtime depends on this function */
int symbol;
uint64_t stamp;
static bool noreentry;
struct StackFrame *frame;
if (!_cmpxchg(&noreentry, 0, 1)) return;
if (ftrace_enabled && g_symbols) {
if (ftrace_enabled) {
stamp = rdtsc();
frame = __builtin_frame_address(0);
frame = frame->next;
if ((symbol = __get_symbol(g_symbols, frame->addr)) != -1 &&
symbol != g_lastsymbol) {
g_lastsymbol = symbol;
kprintf("+ %*s%s %d\r\n", GetNestingLevel(frame) * 2, "",
__get_symbol_name(g_symbols, symbol),
(long)(unsignedsubtract(stamp, laststamp) / 3.3));
laststamp = X86_HAVE(RDTSCP) ? rdtscp(0) : rdtsc();
if (frame->addr != g_lastaddr) {
kprintf("+ %*s%t %d\r\n", GetNestingLevel(frame) * 2, "", frame->addr,
(long)(unsignedsubtract(stamp, g_laststamp) / 3.3));
g_laststamp = X86_HAVE(RDTSCP) ? rdtscp(0) : rdtsc();
g_lastaddr = frame->addr;
}
}
noreentry = 0;
}
textstartup void ftrace_install(void) {
if ((g_symbols = GetSymbolTable())) {
laststamp = kStartTsc;
g_lastsymbol = -1;
if (GetSymbolTable()) {
g_lastaddr = -1;
g_laststamp = kStartTsc;
g_skew = GetNestingLevelImpl(__builtin_frame_address(0));
ftrace_enabled = 1;
__hook(ftrace_hook, g_symbols);
__hook(ftrace_hook, GetSymbolTable());
} else {
kprintf("error: --ftrace failed to open symbol table\r\n");
}

View file

@ -50,7 +50,7 @@ char *GetInterpreterExecutableName(char *p, size_t n) {
e = errno;
if (n < 2) {
errno = ENAMETOOLONG;
} else if (IsWindows()) {
} else if (IsWindows() || IsXnu()) {
if (strlen(GetProgramExecutableName()) < n) {
strcpy(p, GetProgramExecutableName());
return p;

View file

@ -29,10 +29,12 @@
#include "libc/zip.h"
#include "libc/zipos/zipos.internal.h"
static struct SymbolTable *g_symtab;
/**
* Looks for `.symtab` in zip central directory.
*/
noasan static ssize_t FindSymtabInZip(struct Zipos *zipos) {
static ssize_t FindSymtabInZip(struct Zipos *zipos) {
size_t i, n, c;
c = GetZipCdirOffset(zipos->cdir);
n = GetZipCdirRecords(zipos->cdir);
@ -51,7 +53,7 @@ noasan static ssize_t FindSymtabInZip(struct Zipos *zipos) {
* Reads symbol table from zip directory.
* @note This code can't depend on dlmalloc()
*/
noasan static struct SymbolTable *GetSymbolTableFromZip(struct Zipos *zipos) {
static struct SymbolTable *GetSymbolTableFromZip(struct Zipos *zipos) {
ssize_t cf, lf;
size_t size, size2;
struct DeflateState ds;
@ -88,7 +90,7 @@ noasan static struct SymbolTable *GetSymbolTableFromZip(struct Zipos *zipos) {
* Reads symbol table from .com.dbg file.
* @note This code can't depend on dlmalloc()
*/
noasan static struct SymbolTable *GetSymbolTableFromElf(void) {
static struct SymbolTable *GetSymbolTableFromElf(void) {
return OpenSymbolTable(FindDebugBinary());
}
@ -112,24 +114,56 @@ noasan static struct SymbolTable *GetSymbolTableFromElf(void) {
*
* @return symbol table, or NULL w/ errno on first call
*/
noasan struct SymbolTable *GetSymbolTable(void) {
struct SymbolTable *GetSymbolTable(void) {
int ft, st;
struct Zipos *z;
static struct SymbolTable *t;
if (!t) {
if (!g_symtab) {
ft = g_ftrace, g_ftrace = 0;
st = __strace, __strace = 0;
if (weaken(__zipos_get) && (z = weaken(__zipos_get)())) {
if ((t = GetSymbolTableFromZip(z))) {
t->names = (uint32_t *)((char *)t + t->names_offset);
t->name_base = (char *)((char *)t + t->name_base_offset);
if ((g_symtab = GetSymbolTableFromZip(z))) {
g_symtab->names =
(uint32_t *)((char *)g_symtab + g_symtab->names_offset);
g_symtab->name_base =
(char *)((char *)g_symtab + g_symtab->name_base_offset);
}
}
if (!t) {
t = GetSymbolTableFromElf();
if (!g_symtab) {
g_symtab = GetSymbolTableFromElf();
}
g_ftrace = ft;
__strace = st;
}
return t;
return g_symtab;
}
/**
* Returns low index into symbol table for address.
*
* @param t if null will be auto-populated only if already open
* @return index or -1 if nothing found
*/
privileged int __get_symbol(struct SymbolTable *t, intptr_t a) {
/* asan runtime depends on this function */
unsigned l, m, r, n, k;
if (!t && g_symtab) {
t = g_symtab;
}
if (t) {
l = 0;
r = n = t->count;
k = a - t->addr_base;
while (l < r) {
m = (l + r) >> 1;
if (t->symbols[m].y < k) {
l = m + 1;
} else {
r = m;
}
}
if (l < n && t->symbols[l].x <= k && k <= t->symbols[l].y) {
return l;
}
}
return -1;
}

View file

@ -180,7 +180,7 @@ void *mremap(void *p, size_t n, size_t m, int f, ... /* void *q */) {
}
q = sys_mremap((void *)p, n, m, MREMAP_MAYMOVE | MREMAP_FIXED,
(void *)ADDR(a));
STRACE("sys_mremap(%p, %'zu, %'zu, %#b, %p) → %p", p, n, m,
KERNTRACE("sys_mremap(%p, %'zu, %'zu, %#b, %p) → %p", p, n, m,
MREMAP_MAYMOVE | MREMAP_FIXED, ADDR(a), q);
if (q == MAP_FAILED) return 0;
if (ReleaseMemoryIntervals(&_mmi, (uintptr_t)p >> 16,

View file

@ -100,6 +100,7 @@ long GetResourceLimit(int);
long GetMaxFd(void);
char *GetProgramExecutableName(void);
char *GetInterpreterExecutableName(char *, size_t);
void __printargs(const char *);
COSMOPOLITAN_C_END_
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */

View file

@ -75,11 +75,13 @@ o/$(MODE)/libc/runtime/hook.greg.o \
o/$(MODE)/libc/runtime/isheap.o \
o/$(MODE)/libc/runtime/memtrack.o \
o/$(MODE)/libc/runtime/memtracknt.o \
o/$(MODE)/libc/runtime/printargs.greg.o \
o/$(MODE)/libc/runtime/mman.greg.o \
o/$(MODE)/libc/runtime/print.greg.o \
o/$(MODE)/libc/runtime/stackchkfail.o \
o/$(MODE)/libc/runtime/stackchkfaillocal.o \
o/$(MODE)/libc/runtime/winmain.greg.o: \
o/$(MODE)/libc/runtime/winmain.greg.o \
o/$(MODE)/libc/runtime/getsymboltable.greg.o: \
OVERRIDE_CFLAGS += \
-ffreestanding \
$(NO_MAGIC)
@ -90,13 +92,6 @@ o/$(MODE)/libc/runtime/fork-nt.o: \
OVERRIDE_CPPFLAGS += \
-DSTACK_FRAME_UNLIMITED
o/$(MODE)/libc/runtime/printf.o \
o/$(MODE)/libc/runtime/memtrack.o \
o/$(MODE)/libc/runtime/mman.greg.o: \
OVERRIDE_CFLAGS += \
-ffreestanding \
-mgeneral-regs-only
o/$(MODE)/libc/runtime/qsort.o: \
OVERRIDE_CFLAGS += \
-Og

View file

@ -120,7 +120,7 @@ forceinline void MakeLongDoubleLongAgain(void) {
asm volatile("fldcw\t%0" : /* no outputs */ : "m"(x87cw));
}
__msabi static textwindows int WinCrashEarly(struct NtExceptionPointers *ep) {
__msabi static textwindows int OnEarlyWinCrash(struct NtExceptionPointers *ep) {
uint32_t wrote;
char buf[64], *p = buf;
*p++ = 'c';
@ -158,15 +158,16 @@ __msabi static textwindows wontreturn void WinMainNew(const char16_t *cmdline) {
if ((intptr_t)v_ntsubsystem == kNtImageSubsystemWindowsCui && version >= 10) {
__winmainpid = __pid;
rc = SetConsoleCP(kNtCpUtf8);
STRACE("SetConsoleCP(kNtCpUtf8) → %hhhd", rc);
NTTRACE("SetConsoleCP(kNtCpUtf8) → %hhhd", rc);
rc = SetConsoleOutputCP(kNtCpUtf8);
STRACE("SetConsoleOutputCP(kNtCpUtf8) → %hhhd", rc);
NTTRACE("SetConsoleOutputCP(kNtCpUtf8) → %hhhd", rc);
for (i = 0; i < 3; ++i) {
hand = GetStdHandle(kConsoleHandles[i]);
rc = GetConsoleMode(hand, __ntconsolemode + i);
STRACE("GetConsoleMode(%p, [%#x]) → %hhhd", hand, __ntconsolemode[i], rc);
NTTRACE("GetConsoleMode(%p, [%#x]) → %hhhd", hand, __ntconsolemode[i],
rc);
rc = SetConsoleMode(hand, kConsoleModes[i]);
STRACE("SetConsoleMode(%p, %#x) → %hhhd", hand, kConsoleModes[i], rc);
NTTRACE("SetConsoleMode(%p, %#x) → %hhhd", hand, kConsoleModes[i], rc);
}
}
_mmi.p = _mmi.s;
@ -176,8 +177,8 @@ __msabi static textwindows wontreturn void WinMainNew(const char16_t *cmdline) {
stacksize = GetStackSize();
allocsize = argsize + stacksize;
allocaddr = stackaddr - argsize;
STRACE("WinMainNew() mapping %'zu byte arg block + stack at %p", allocsize,
allocaddr);
NTTRACE("WinMainNew() mapping %'zu byte arg block + stack at %p", allocsize,
allocaddr);
MapViewOfFileEx(
(_mmi.p[0].h =
CreateFileMapping(-1, &kNtIsInheritable, kNtPageExecuteReadwrite,
@ -194,7 +195,7 @@ __msabi static textwindows wontreturn void WinMainNew(const char16_t *cmdline) {
_mmi.p[0].size = allocsize;
_mmi.i = 1;
wa = (struct WinArgs *)allocaddr;
STRACE("WinMainNew() loading arg block");
NTTRACE("WinMainNew() loading arg block");
count = GetDosArgv(cmdline, wa->argblock, ARRAYLEN(wa->argblock), wa->argv,
ARRAYLEN(wa->argv));
for (i = 0; wa->argv[0][i]; ++i) {
@ -203,13 +204,11 @@ __msabi static textwindows wontreturn void WinMainNew(const char16_t *cmdline) {
}
}
env16 = GetEnvironmentStrings();
STRACE("WinMainNew() loading environment");
NTTRACE("WinMainNew() loading environment");
GetDosEnviron(env16, wa->envblock, ARRAYLEN(wa->envblock) - 8, wa->envp,
ARRAYLEN(wa->envp) - 1);
FreeEnvironmentStrings(env16);
wa->auxv[0][0] = pushpop(AT_EXECFN);
wa->auxv[0][1] = (intptr_t)wa->argv[0];
STRACE("WinMainNew() switching stacks");
NTTRACE("WinMainNew() switching stacks");
_jmpstack((char *)(stackaddr + stacksize - (intptr_t)ape_stack_align), cosmo,
count, wa->argv, wa->envp, wa->auxv);
}
@ -255,13 +254,13 @@ __msabi textwindows int64_t WinMain(int64_t hInstance, int64_t hPrevInstance,
ts = rdtsc();
__nomultics = true;
__pid = GetCurrentProcessId();
__wincrashearly = AddVectoredExceptionHandler(1, (void *)WinCrashEarly);
__wincrashearly = AddVectoredExceptionHandler(1, (void *)OnEarlyWinCrash);
cmdline = GetCommandLine();
#ifdef SYSDEBUG
/* sloppy flag-only check for early initialization */
if (__strstr16(cmdline, u"--strace")) ++__strace;
#endif
STRACE("WinMain()");
NTTRACE("WinMain()");
MakeLongDoubleLongAgain();
if (weaken(WinSockInit)) weaken(WinSockInit)();
if (weaken(WinMainForked)) weaken(WinMainForked)();

View file

@ -144,6 +144,7 @@ ssize_t sys_recvfrom_nt(struct Fd *, const struct iovec *, size_t, uint32_t,
void WinSockInit(void) hidden;
int64_t __winsockerr(void) nocallback hidden;
int __fixupnewsockfd(int, int) hidden;
int __wsablock(int64_t, struct NtOverlapped *, uint32_t *, bool) hidden;
int64_t __winsockblock(int64_t, unsigned, int64_t) hidden;
struct SockFd *_dupsockfd(struct SockFd *) hidden;
int64_t GetNtBaseSocket(int64_t) hidden;

View file

@ -39,7 +39,7 @@ hidden struct NtWsaData kNtWsaData;
static textwindows void WinSockCleanup(void) {
int i, rc;
STRACE("WinSockCleanup()");
NTTRACE("WinSockCleanup()");
for (i = g_fds.n; i--;) {
if (g_fds.p[i].kind == kFdSocket) {
close(i);
@ -47,13 +47,13 @@ static textwindows void WinSockCleanup(void) {
}
// TODO(jart): Check WSACleanup() result code
rc = WSACleanup();
STRACE("WSACleanup() → %d% lm", rc);
NTTRACE("WSACleanup() → %d% lm", rc);
}
textwindows noasan void WinSockInit(void) {
int rc;
atexit(WinSockCleanup);
STRACE("WSAStartup()");
NTTRACE("WSAStartup()");
if ((rc = WSAStartup(VERSION, &kNtWsaData)) != 0 ||
kNtWsaData.wVersion != VERSION) {
ExitProcess(123);

View file

@ -16,7 +16,6 @@
TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE.
*/
#define ShouldUseMsabiAttribute() 1
#include "libc/assert.h"
#include "libc/calls/calls.h"
#include "libc/calls/internal.h"
@ -41,41 +40,34 @@
* @fileoverview Pollable Standard Input for the New Technology.
*/
__msabi extern typeof(CloseHandle) *const __imp_CloseHandle;
static textwindows bool IsEof(bool ok, uint32_t got) {
return (ok && !got) || (!ok && (__imp_GetLastError() == kNtErrorHandleEof ||
__imp_GetLastError() == kNtErrorBrokenPipe));
}
static textwindows uint32_t StdinWorkerThread(void *arg) {
char buf[512];
bool32 ok = true;
uint32_t i, rc, got, err, wrote;
struct NtStdinWorker w, *wp = arg;
STRACE("StdinWorkerThread(%ld → %ld → %ld) pid %d tid %d", wp->reader,
wp->writer, wp->consumer, getpid(), gettid());
NTTRACE("StdinWorkerThread(%ld → %ld → %ld) pid %d tid %d", wp->reader,
wp->writer, wp->consumer, getpid(), gettid());
__sync_lock_release(&wp->sync);
w = *wp;
do {
ok = __imp_ReadFile(w.reader, buf, sizeof(buf), &got, 0);
ok = ReadFile(w.reader, buf, sizeof(buf), &got, 0);
/* When writing to a non-blocking, byte-mode pipe handle with
insufficient buffer space, WriteFile returns TRUE with
*lpNumberOfBytesWritten < nNumberOfBytesToWrite.
Quoth MSDN WriteFile() */
for (i = 0; ok && i < got; i += wrote) {
ok = __imp_WriteFile(w.writer, buf + i, got - i, &wrote, 0);
ok = WriteFile(w.writer, buf + i, got - i, &wrote, 0);
}
} while (ok && got);
err = GetLastError();
if (!ok) {
err = __imp_GetLastError();
if (err == kNtErrorHandleEof || err == kNtErrorBrokenPipe ||
err == kNtErrorNoData) {
ok = true;
}
}
STRACE("StdinWorkerThread(%ld → %ld → %ld) → %hhhd %d", w.reader, w.writer,
w.consumer, __imp_GetLastError());
NTTRACE("StdinWorkerThread(%ld → %ld → %ld) → %hhhd %u", w.reader, w.writer,
w.consumer, err);
return !ok;
}
@ -87,7 +79,7 @@ static textwindows uint32_t StdinWorkerThread(void *arg) {
*/
textwindows struct NtStdinWorker *NewNtStdinWorker(int fd) {
struct NtStdinWorker *w;
STRACE("LaunchNtStdinWorker(%d) pid %d tid %d", fd, getpid(), gettid());
NTTRACE("LaunchNtStdinWorker(%d) pid %d tid %d", fd, getpid(), gettid());
assert(!g_fds.p[fd].worker);
assert(__isfdopen(fd));
if (!(w = calloc(1, sizeof(struct NtStdinWorker)))) return 0;
@ -136,7 +128,7 @@ textwindows struct NtStdinWorker *RefNtStdinWorker(struct NtStdinWorker *w) {
textwindows bool UnrefNtStdinWorker(struct NtStdinWorker *w) {
bool ok = true;
if (__atomic_sub_fetch(&w->refs, 1, __ATOMIC_SEQ_CST)) return true;
// w->consumer is freed by close_nt()
if (!CloseHandle(w->consumer)) ok = false;
if (!CloseHandle(w->writer)) ok = false;
if (!CloseHandle(w->reader)) ok = false;
if (!CloseHandle(w->worker)) ok = false;

View file

@ -24,11 +24,14 @@
#include "libc/calls/sigbits.h"
#include "libc/calls/strace.internal.h"
#include "libc/calls/struct/sigaction.h"
#include "libc/errno.h"
#include "libc/intrin/kprintf.h"
#include "libc/intrin/spinlock.h"
#include "libc/macros.internal.h"
#include "libc/mem/mem.h"
#include "libc/nt/enum/filetype.h"
#include "libc/nt/errors.h"
#include "libc/nt/files.h"
#include "libc/nt/ipc.h"
#include "libc/nt/runtime.h"
#include "libc/nt/struct/pollfd.h"
@ -37,13 +40,11 @@
#include "libc/sock/internal.h"
#include "libc/sock/ntstdin.internal.h"
#include "libc/sock/yoink.inc"
#include "libc/sysv/consts/o.h"
#include "libc/sysv/consts/poll.h"
#include "libc/sysv/consts/sig.h"
#include "libc/sysv/errfuns.h"
#undef STRACE // too verbosen
#define STRACE(...) // but don't want to delete
_Alignas(64) static char poll_lock;
/**
@ -60,7 +61,7 @@ textwindows int sys_poll_nt(struct pollfd *fds, uint64_t nfds, uint64_t *ms) {
struct sys_pollfd_nt sockfds[64];
int pipeindices[ARRAYLEN(pipefds)];
int sockindices[ARRAYLEN(sockfds)];
int i, sn, pn, failed, gotpipes, gotsocks, waitfor;
int i, sn, pn, failed, gotinvals, gotpipes, gotsocks, waitfor;
// check for interrupts early before doing work
if (_check_interrupts(false, g_fds.p)) return eintr();
@ -69,49 +70,53 @@ textwindows int sys_poll_nt(struct pollfd *fds, uint64_t nfds, uint64_t *ms) {
// we need to read static variables
// we might need to spawn threads and open pipes
_spinlock(&poll_lock);
for (failed = sn = pn = i = 0; i < nfds; ++i) {
_spinlock(&__fds_lock);
for (gotinvals = failed = sn = pn = i = 0; i < nfds; ++i) {
if (fds[i].fd < 0) continue;
if (__isfdopen(fds[i].fd)) {
if (__isfdkind(fds[i].fd, kFdSocket)) {
if (sn < ARRAYLEN(sockfds)) {
// the magnums for POLLIN/OUT/PRI on NT include the other ones too
// we need to clear ones like POLLNVAL or else WSAPoll shall whine
sockindices[sn] = i;
sockfds[sn].handle = g_fds.p[fds[i].fd].handle;
sockfds[sn].events = fds[i].events & (POLLPRI | POLLIN | POLLOUT);
sn += 1;
sockfds[sn].revents = 0;
++sn;
} else {
// too many socket fds
failed = enomem();
break;
}
} else if (fds[i].events & POLLIN) {
if (!g_fds.p[fds[i].fd].worker) {
if (!(g_fds.p[fds[i].fd].worker = NewNtStdinWorker(fds[i].fd))) {
// failed to launch stdin worker
failed = -1;
} else if (pn < ARRAYLEN(pipefds)) {
pipeindices[pn] = i;
pipefds[pn].handle = g_fds.p[fds[i].fd].handle;
pipefds[pn].events = 0;
pipefds[pn].revents = 0;
switch (g_fds.p[fds[i].fd].flags & O_ACCMODE) {
case O_RDONLY:
pipefds[pn].events = fds[i].events & POLLIN;
break;
}
}
if (pn < ARRAYLEN(pipefds)) {
pipeindices[pn] = i;
pipefds[pn].handle = g_fds.p[fds[i].fd].handle;
pipefds[pn].events = fds[i].events & (POLLPRI | POLLIN | POLLOUT);
pn += 1;
} else {
// too many non-socket fds
failed = enomem();
break;
case O_WRONLY:
pipefds[pn].events = fds[i].events & POLLOUT;
break;
case O_RDWR:
pipefds[pn].events = fds[i].events & (POLLIN | POLLOUT);
break;
default:
unreachable;
}
++pn;
} else {
// non-sock w/o pollin
failed = enotsock();
// too many non-socket fds
failed = enomem();
break;
}
} else {
// non-open file descriptor
failed = einval();
break;
++gotinvals;
}
}
_spunlock(&__fds_lock);
_spunlock(&poll_lock);
if (failed) {
// failed to create a polling solution
@ -122,49 +127,61 @@ textwindows int sys_poll_nt(struct pollfd *fds, uint64_t nfds, uint64_t *ms) {
for (;;) {
// see if input is available on non-sockets
for (gotpipes = i = 0; i < pn; ++i) {
ok = PeekNamedPipe(pipefds[i].handle, 0, 0, 0, &avail, 0);
STRACE("PeekNamedPipe(%ld, 0, 0, 0, [%'u], 0) → %hhhd% m",
pipefds[i].handle, avail, ok);
if (ok) {
if (avail) {
pipefds[i].revents = POLLIN;
gotpipes += 1;
if (pipefds[i].events & POLLOUT) {
// we have no way of polling if a non-socket is writeable yet
// therefore we assume that if it can happen, it shall happen
pipefds[i].revents = POLLOUT;
}
if (pipefds[i].events & POLLIN) {
if (GetFileType(pipefds[i].handle) == kNtFileTypePipe) {
ok = PeekNamedPipe(pipefds[i].handle, 0, 0, 0, &avail, 0);
POLLTRACE("PeekNamedPipe(%ld, 0, 0, 0, [%'u], 0) → %hhhd% m",
pipefds[i].handle, avail, ok);
if (ok) {
if (avail) {
pipefds[i].revents = POLLIN;
}
} else {
pipefds[i].revents = POLLERR;
}
} else {
pipefds[i].revents = 0;
// we have no way of polling if a non-socket is readable yet
// therefore we assume that if it can happen it shall happen
pipefds[i].revents = POLLIN;
}
} else {
pipefds[i].revents = POLLERR;
gotpipes += 1;
}
if (pipefds[i].revents) {
++gotpipes;
}
}
// if we haven't found any good results yet then here we
// compute a small time slice we don't mind sleeping for
waitfor = gotpipes ? 0 : MIN(__SIG_POLLING_INTERVAL_MS, *ms);
waitfor = gotinvals || gotpipes ? 0 : MIN(__SIG_POLLING_INTERVAL_MS, *ms);
if (sn) {
// we need to poll the socket handles separately because
// microsoft certainly loves to challenge us with coding
// please note that winsock will fail if we pass zero fd
STRACE("WSAPoll(%p, %u, %'d) out of %'lu", sockfds, sn, waitfor, *ms);
POLLTRACE("WSAPoll(%p, %u, %'d) out of %'lu", sockfds, sn, waitfor, *ms);
if ((gotsocks = WSAPoll(sockfds, sn, waitfor)) == -1) {
return __winsockerr();
}
*ms -= waitfor;
} else {
gotsocks = 0;
if (!gotpipes && waitfor) {
if (!gotinvals && !gotpipes && waitfor) {
// if we've only got pipes and none of them are ready
// then we'll just explicitly sleep for the time left
STRACE("SleepEx(%'d, false) out of %'lu", waitfor, *ms);
if (SleepEx(waitfor, true) == kNtWaitIoCompletion) {
STRACE("IOCP TRIGGERED EINTR");
return eintr();
POLLTRACE("SleepEx(%'d, false) out of %'lu", waitfor, *ms);
if (SleepEx(__SIG_POLLING_INTERVAL_MS, true) == kNtWaitIoCompletion) {
POLLTRACE("IOCP EINTR");
} else {
*ms -= waitfor;
}
*ms -= waitfor;
}
}
// we gave all the sockets and all the named pipes a shot
// if we found anything at all then it's time to end work
if (gotpipes || gotsocks || *ms <= 0) {
if (gotinvals || gotpipes || gotsocks || *ms <= 0) {
break;
}
// otherwise loop limitlessly for timeout to elapse while
@ -174,33 +191,22 @@ textwindows int sys_poll_nt(struct pollfd *fds, uint64_t nfds, uint64_t *ms) {
}
}
// we got some
// assemble the result
for (i = 0; i < pn; ++i) {
fds[pipeindices[i]].revents =
pipefds[i].handle < 0 ? 0 : pipefds[i].revents;
}
for (i = 0; i < sn; ++i) {
fds[sockindices[i]].revents =
sockfds[i].handle < 0 ? 0 : sockfds[i].revents;
}
return gotpipes + gotsocks;
}
static textexit void __freefds_workers(void) {
int i;
STRACE("__freefds_workers()");
for (i = g_fds.n; i--;) {
if (g_fds.p[i].kind && g_fds.p[i].worker) {
close(i);
// the system call is going to succeed
// it's now ok to start setting the output memory
for (i = 0; i < nfds; ++i) {
if (fds[i].fd < 0 || __isfdopen(fds[i].fd)) {
fds[i].revents = 0;
} else {
fds[i].revents = POLLNVAL;
}
}
}
for (i = 0; i < pn; ++i) {
fds[pipeindices[i]].revents = pipefds[i].revents;
}
for (i = 0; i < sn; ++i) {
fds[sockindices[i]].revents = sockfds[i].revents;
}
static textstartup void __freefds_workers_init(void) {
atexit(__freefds_workers);
// and finally return
return gotinvals + gotpipes + gotsocks;
}
const void *const __freefds_workers_ctor[] initarray = {
__freefds_workers_init,
};

View file

@ -28,13 +28,35 @@
/**
* Waits for something to happen on multiple file descriptors at once.
*
* Warning: XNU has an inconsistency with other platforms. If you have
* pollfds with fd0 and none of the meaningful events flags are added
* e.g. POLLIN then XNU won't check for POLLNVAL. This matters because
* one of the use-cases for poll() is quickly checking for open files.
*
* Note: Polling works best on Windows for sockets. We're able to poll
* input on named pipes. But for anything that isn't a socket, or pipe
* with POLLIN, (e.g. regular file) then POLLIN/POLLOUT are always set
* into revents if they're requested, provided they were opened with a
* mode that permits reading and/or writing.
*
* Note: Windows has a limit of 64 file descriptors and ENOMEM with -1
* is returned if that limit is exceeded. In practice the limit is not
* this low. For example, pollfds with fd<0 don't count. So the caller
* could flip the sign bit with a short timeout, to poll a larger set.
*
* @param fds[𝑖].fd should be a socket, input pipe, or conosle input
* @param fds[𝑖].events flags can have POLLIN, POLLOUT, and POLLPRI
* and if it's a negative number then the entry is ignored
* @param fds[𝑖].events flags can have POLLIN, POLLOUT, POLLPRI,
* POLLRDNORM, POLLWRNORM, POLLRDBAND, POLLWRBAND as well as
* POLLERR, POLLHUP, and POLLNVAL although the latter are
* always implied (assuming fd0) so they're ignored here
* @param timeout_ms if 0 means don't wait and -1 means wait forever
* @return number of items fds whose revents field has been set to
* nonzero to describe its events, or -1 w/ errno
* @return fds[𝑖].revents flags can have:
* (fds[𝑖].events & POLL{IN,OUT,PRI,HUP,ERR,NVAL})
* nonzero to describe its events, or 0 if the timeout elapsed,
* or -1 w/ errno
* @return fds[𝑖].revents is always zero initializaed and then will
* be populated with POLL{IN,OUT,PRI,HUP,ERR,NVAL} if something
* was determined about the file descriptor
* @asyncsignalsafe
* @threadsafe
* @norestart

View file

@ -20,15 +20,22 @@
#include "libc/calls/strace.internal.h"
#include "libc/calls/struct/sigset.h"
#include "libc/dce.h"
#include "libc/dns/dns.h"
#include "libc/intrin/describeflags.internal.h"
#include "libc/intrin/kprintf.h"
#include "libc/macros.internal.h"
#include "libc/nexgen32e/cpuid4.internal.h"
#include "libc/nexgen32e/kcpuids.h"
#include "libc/nexgen32e/x86feature.h"
#include "libc/nexgen32e/x86info.h"
#include "libc/nt/enum/startf.h"
#include "libc/nt/runtime.h"
#include "libc/nt/startupinfo.h"
#include "libc/nt/struct/ldrdatatableentry.h"
#include "libc/nt/struct/startupinfo.h"
#include "libc/nt/struct/teb.h"
#include "libc/runtime/internal.h"
#include "libc/runtime/memtrack.internal.h"
#include "libc/runtime/runtime.h"
#include "libc/runtime/stack.h"
#include "libc/sock/internal.h"
@ -37,8 +44,16 @@
#include "libc/sysv/consts/f.h"
#include "libc/sysv/consts/poll.h"
#include "libc/sysv/consts/sig.h"
#include "tool/decode/lib/idname.h"
#include "tool/decode/lib/x86idnames.h"
#define PRINT(FMT, ...) kprintf(STRACE_PROLOGUE FMT "%n", ##__VA_ARGS__)
STATIC_YOINK("strsignal"); // for kprintf()
#define PRINT(FMT, ...) \
do { \
kprintf(prologue); \
kprintf(FMT "%n", ##__VA_ARGS__); \
} while (0)
static const struct AuxiliaryValue {
const char *fmt;
@ -82,6 +97,15 @@ static const struct AuxiliaryValue {
{"%-14p", &AT_EHDRFLAGS, "AT_EHDRFLAGS"},
};
static const char *FindNameById(const struct IdName *names, unsigned long id) {
for (; names->name; names++) {
if (names->id == id) {
return names->name;
}
}
return NULL;
}
static const struct AuxiliaryValue *DescribeAuxv(unsigned long x) {
int i;
for (i = 0; i < ARRAYLEN(kAuxiliaryValues); ++i) {
@ -92,46 +116,202 @@ static const struct AuxiliaryValue *DescribeAuxv(unsigned long x) {
return NULL;
}
noasan textstartup void __printargs(void) {
#ifdef SYSDEBUG
int st;
/**
* Prints lots of information about this process, e.g.
*
* __printargs("");
*
* This is called automatically in MODE=dbg if `--strace` is used.
*
* @param prologue needs to be a .rodata kprintf string
*/
textstartup void __printargs(const char *prologue) {
long key;
char **env;
unsigned i;
sigset_t ss;
unsigned i, n;
uintptr_t *auxp;
struct utsname uts;
char path[PATH_MAX];
int x, st, ft, flags;
struct pollfd pfds[128];
struct AuxiliaryValue *auxinfo;
if (__strace <= 0) return;
st = __strace;
__strace = 0;
st = __strace, __strace = 0;
ft = g_ftrace, g_ftrace = 0;
PRINT("");
PRINT("SYSTEM");
if (!uname(&uts)) {
kprintf(prologue);
kprintf(" %s", uts.nodename);
if (*uts.sysname) {
kprintf(" on %s", uts.sysname);
if (*uts.release) {
kprintf(" %s", uts.release);
}
}
kprintf("%n");
} else {
PRINT(" uname() failed %m");
}
PRINT("");
PRINT("MICROPROCESSOR");
kprintf(prologue);
kprintf(" %.*s%.*s%.*s", 4, &KCPUIDS(0H, EBX), 4, &KCPUIDS(0H, EDX), 4,
&KCPUIDS(0H, ECX));
if (getx86processormodel(kX86ProcessorModelKey)) {
kprintf(" %s",
FindNameById(kX86MarchNames,
getx86processormodel(kX86ProcessorModelKey)->march));
}
if (getx86processormodel(kX86ProcessorModelKey)) {
kprintf(" (%s Grade)",
FindNameById(kX86GradeNames,
getx86processormodel(kX86ProcessorModelKey)->grade));
}
kprintf("%n");
if ((x = KCPUIDS(16H, EAX) & 0x7fff)) {
kprintf(prologue);
kprintf(" %dmhz %s", x, "freq");
if ((x = KCPUIDS(16H, EBX) & 0x7fff)) {
kprintf(" / %dmhz %s", x, "turbo");
}
if ((x = KCPUIDS(16H, ECX) & 0x7fff)) {
kprintf(" / %dmhz %s", x, "bus");
}
kprintf("%n");
}
if (X86_HAVE(HYPERVISOR)) {
unsigned eax, ebx, ecx, edx;
asm("push\t%%rbx\n\t"
"cpuid\n\t"
"mov\t%%ebx,%1\n\t"
"pop\t%%rbx"
: "=a"(eax), "=rm"(ebx), "=c"(ecx), "=d"(edx)
: "0"(0x40000000), "2"(0));
PRINT(" Running inside %.4s%.4s%.4s (eax=%#x)", &ebx, &ecx, &edx, eax);
}
CPUID4_ITERATE(i, {
PRINT(" L%d%s%s %u-way %,u byte cache w/%s "
"%,u sets of %,u byte lines shared across %u threads%s",
CPUID4_CACHE_LEVEL,
CPUID4_CACHE_TYPE == 1 ? " data"
: CPUID4_CACHE_TYPE == 2 ? " code"
: "",
CPUID4_IS_FULLY_ASSOCIATIVE ? " fully-associative" : "",
CPUID4_WAYS_OF_ASSOCIATIVITY, CPUID4_CACHE_SIZE_IN_BYTES,
CPUID4_PHYSICAL_LINE_PARTITIONS > 1 ? " physically partitioned" : "",
CPUID4_NUMBER_OF_SETS, CPUID4_SYSTEM_COHERENCY_LINE_SIZE,
CPUID4_MAX_THREADS_SHARING_CACHE,
CPUID4_COMPLEX_INDEXING ? " complexly-indexed" : "");
});
kprintf(prologue);
kprintf(" ");
if (X86_HAVE(SSE3)) kprintf(" SSE3");
if (X86_HAVE(SSSE3)) kprintf(" SSSE3");
if (X86_HAVE(SSE4_2)) kprintf(" SSE4_2");
if (X86_HAVE(POPCNT)) kprintf(" POPCNT");
if (X86_HAVE(AVX)) kprintf(" AVX");
if (X86_HAVE(AVX2)) kprintf(" AVX2");
if (X86_HAVE(FMA)) kprintf(" FMA");
if (X86_HAVE(BMI)) kprintf(" BMI");
if (X86_HAVE(BMI2)) kprintf(" BMI2");
if (X86_HAVE(ADX)) kprintf(" ADX");
if (X86_HAVE(F16C)) kprintf(" F16C");
if (X86_HAVE(SHA)) kprintf(" SHA");
if (X86_HAVE(AES)) kprintf(" AES");
if (X86_HAVE(RDRND)) kprintf(" RDRND");
if (X86_HAVE(RDSEED)) kprintf(" RDSEED");
if (X86_HAVE(RDTSCP)) kprintf(" RDTSCP");
if (X86_HAVE(RDPID)) kprintf(" RDPID");
if (X86_HAVE(LA57)) kprintf(" LA57");
if (X86_HAVE(FSGSBASE)) kprintf(" FSGSBASE");
kprintf("%n");
PRINT("");
PRINT("FILE DESCRIPTORS");
for (i = 0; i < ARRAYLEN(pfds); ++i) {
pfds[i].fd = i;
pfds[i].events = POLLIN | POLLOUT;
}
if ((n = poll(pfds, ARRAYLEN(pfds), 20)) != -1) {
for (i = 0; i < ARRAYLEN(pfds); ++i) {
if (i && (pfds[i].revents & POLLNVAL)) continue;
PRINT(" ☼ %d (revents=%#hx F_GETFL=%#x)", i, pfds[i].revents,
fcntl(i, F_GETFL));
}
} else {
PRINT(" poll() returned %d %m", n);
}
if (!sigprocmask(SIG_BLOCK, 0, &ss)) {
PRINT("");
PRINT("SIGNALS {%#lx, %#lx}", ss.__bits[0], ss.__bits[1]);
if (ss.__bits[0] || ss.__bits[1]) {
for (i = 0; i < 32; ++i) {
if (ss.__bits[0] & (1u << i)) {
PRINT(" ☼ %G (%d) is masked", i + 1, i + 1);
}
}
} else {
PRINT(" no signals blocked");
}
} else {
PRINT("");
PRINT("SIGNALS");
PRINT(" error: sigprocmask() failed %m");
}
PRINT("");
PRINT("ARGUMENTS (%p)", __argv);
for (i = 0; i < __argc; ++i) {
PRINT(" ☼ %s", __argv[i]);
if (*__argv) {
for (i = 0; i < __argc; ++i) {
PRINT(" ☼ %s", __argv[i]);
}
} else {
PRINT(" none");
}
PRINT("");
PRINT("ENVIRONMENT (%p)", __envp);
for (env = __envp; *env; ++env) {
PRINT(" ☼ %s", *env);
if (*__envp) {
for (env = __envp; *env; ++env) {
PRINT(" ☼ %s", *env);
}
} else {
PRINT(" none");
}
PRINT("");
PRINT("AUXILIARY (%p)", __auxv);
for (auxp = __auxv; *auxp; auxp += 2) {
if ((auxinfo = DescribeAuxv(auxp[0]))) {
ksnprintf(path, sizeof(path), auxinfo->fmt, auxp[1]);
PRINT(" ☼ %16s[%4ld] = %s", auxinfo->name, auxp[0], path);
} else {
PRINT(" ☼ %16s[%4ld] = %014p", "unknown", auxp[0], auxp[1]);
if (*__auxv) {
if (*__auxv) {
for (auxp = __auxv; *auxp; auxp += 2) {
if ((auxinfo = DescribeAuxv(auxp[0]))) {
ksnprintf(path, sizeof(path), auxinfo->fmt, auxp[1]);
PRINT(" ☼ %16s[%4ld] = %s", auxinfo->name, auxp[0], path);
} else {
PRINT(" ☼ %16s[%4ld] = %014p", "unknown", auxp[0], auxp[1]);
}
}
}
} else {
PRINT(" none");
}
PRINT("");
PRINT("SPECIALS");
umask((i = umask(022)));
PRINT(" ☼ %s = %#o", "umask()", i);
PRINT(" ☼ %s = %d", "getpid()", getpid());
PRINT(" ☼ %s = %d", "getppid()", getppid());
PRINT(" ☼ %s = %d", "getpgrp()", getpgrp());
PRINT(" ☼ %s = %d", "getsid()", getsid(0));
PRINT(" ☼ %s = %d", "getuid()", getuid());
PRINT(" ☼ %s = %d", "geteuid()", geteuid());
PRINT(" ☼ %s = %d", "getgid()", getgid());
PRINT(" ☼ %s = %d", "getegid()", getegid());
PRINT(" ☼ %s = %#s", "kTmpPath", kTmpPath);
PRINT(" ☼ %s = %#s", "kNtSystemDirectory", kNtSystemDirectory);
PRINT(" ☼ %s = %#s", "kNtWindowsDirectory", kNtWindowsDirectory);
@ -143,31 +323,9 @@ noasan textstartup void __printargs(void) {
PRINT(" ☼ %s = %p", "GetStaticStackAddr(0)", GetStaticStackAddr(0));
PRINT(" ☼ %s = %p", "GetStackSize()", GetStackSize());
if (!IsWindows()) {
PRINT("");
PRINT("OPEN FILE DESCRIPTORS");
for (i = 0; i < ARRAYLEN(pfds); ++i) {
pfds[i].fd = i;
pfds[i].events = 0;
}
if (sys_poll(pfds, ARRAYLEN(pfds), 0) != -1) {
for (i = 0; i < ARRAYLEN(pfds); ++i) {
if (~pfds[i].revents & POLLNVAL) {
PRINT(" ☼ %d (F_GETFL=%#x)", i, fcntl(i, F_GETFL));
}
}
}
}
if (!sigprocmask(SIG_BLOCK, 0, &ss) && (ss.__bits[0] || ss.__bits[1])) {
PRINT("");
PRINT("BLOCKED SIGNALS {%#lx, %#lx}", ss.__bits[0], ss.__bits[1]);
for (i = 0; i < 32; ++i) {
if (ss.__bits[0] & (1u << i)) {
PRINT(" ☼ %G (%d)", i + 1, i + 1);
}
}
}
PRINT("");
PRINT("MEMTRACK");
PrintMemoryIntervals(2, &_mmi);
if (IsWindows()) {
struct NtStartupInfo startinfo;
@ -234,12 +392,12 @@ noasan textstartup void __printargs(void) {
do {
const struct NtLdrDataTableEntry *dll =
(const struct NtLdrDataTableEntry *)ldr;
PRINT(" ☼ %.*!hs\t\t%'zu bytes", dll->FullDllName.Length,
dll->FullDllName.Data, dll->SizeOfImage);
PRINT(" ☼ %.*!hs (%'zukb)", dll->FullDllName.Length,
dll->FullDllName.Data, dll->SizeOfImage / 1024);
} while ((ldr = ldr->Next) && ldr != head);
}
PRINT("");
__strace = st;
#endif
g_ftrace = ft;
}

View file

@ -16,19 +16,11 @@
TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE.
*/
#include "libc/assert.h"
#include "libc/bits/weaken.h"
#include "libc/calls/internal.h"
#include "libc/calls/sig.internal.h"
#include "libc/calls/strace.internal.h"
#include "libc/intrin/kprintf.h"
#include "libc/log/backtrace.internal.h"
#include "libc/nt/enum/wait.h"
#include "libc/nt/errors.h"
#include "libc/calls/struct/iovec.h"
#include "libc/nt/struct/overlapped.h"
#include "libc/nt/winsock.h"
#include "libc/sock/internal.h"
#include "libc/sock/yoink.inc"
#include "libc/sysv/errfuns.h"
/**
@ -40,51 +32,16 @@
textwindows ssize_t sys_recv_nt(struct Fd *fd, const struct iovec *iov,
size_t iovlen, uint32_t flags) {
ssize_t rc;
uint32_t i, got = 0;
uint32_t got = 0;
struct NtIovec iovnt[16];
struct NtOverlapped overlapped = {.hEvent = WSACreateEvent()};
if (_check_interrupts(true, g_fds.p)) return eintr();
if (!WSARecv(fd->handle, iovnt, __iovec2nt(iovnt, iov, iovlen), &got, &flags,
&overlapped, NULL)) {
rc = got;
goto Finished;
} else {
rc = __wsablock(fd->handle, &overlapped, &flags, true);
}
if (WSAGetLastError() != kNtErrorIoPending) {
STRACE("WSARecv failed %lm");
rc = __winsockerr();
goto Finished;
}
for (;;) {
i = WSAWaitForMultipleEvents(1, &overlapped.hEvent, true,
__SIG_POLLING_INTERVAL_MS, true);
if (i == kNtWaitFailed) {
STRACE("WSAWaitForMultipleEvents failed %lm");
rc = __winsockerr();
goto Finished;
} else if (i == kNtWaitTimeout) {
if (_check_interrupts(true, g_fds.p)) {
rc = eintr();
goto Finished;
}
} else if (i == kNtWaitIoCompletion) {
STRACE("IOCP TRIGGERED EINTR");
} else {
break;
}
}
if (!WSAGetOverlappedResult(fd->handle, &overlapped, &got, false, &flags)) {
STRACE("WSAGetOverlappedResult failed %lm");
rc = __winsockerr();
goto Finished;
}
rc = got;
Finished:
WSACloseEvent(overlapped.hEvent);
return rc;
}

View file

@ -16,10 +16,8 @@
TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE.
*/
#include "libc/calls/sig.internal.h"
#include "libc/calls/strace.internal.h"
#include "libc/nt/enum/wait.h"
#include "libc/nt/errors.h"
#include "libc/calls/internal.h"
#include "libc/calls/struct/iovec.h"
#include "libc/nt/struct/overlapped.h"
#include "libc/nt/winsock.h"
#include "libc/sock/internal.h"
@ -36,52 +34,17 @@ textwindows ssize_t sys_recvfrom_nt(struct Fd *fd, const struct iovec *iov,
void *opt_out_srcaddr,
uint32_t *opt_inout_srcaddrsize) {
ssize_t rc;
uint32_t i, got = 0;
uint32_t got = 0;
struct NtIovec iovnt[16];
struct NtOverlapped overlapped = {.hEvent = WSACreateEvent()};
if (_check_interrupts(true, g_fds.p)) return eintr();
if (!WSARecvFrom(fd->handle, iovnt, __iovec2nt(iovnt, iov, iovlen), &got,
&flags, opt_out_srcaddr, opt_inout_srcaddrsize, &overlapped,
NULL)) {
rc = got;
goto Finished;
} else {
rc = __wsablock(fd->handle, &overlapped, &flags, true);
}
if (WSAGetLastError() != kNtErrorIoPending) {
STRACE("WSARecvFrom failed %lm");
rc = __winsockerr();
goto Finished;
}
for (;;) {
i = WSAWaitForMultipleEvents(1, &overlapped.hEvent, true,
__SIG_POLLING_INTERVAL_MS, true);
if (i == kNtWaitFailed) {
STRACE("WSAWaitForMultipleEvents failed %lm");
rc = __winsockerr();
goto Finished;
} else if (i == kNtWaitTimeout) {
if (_check_interrupts(true, g_fds.p)) {
rc = eintr();
goto Finished;
}
} else if (i == kNtWaitIoCompletion) {
STRACE("IOCP TRIGGERED EINTR");
} else {
break;
}
}
if (!WSAGetOverlappedResult(fd->handle, &overlapped, &got, false, &flags)) {
STRACE("WSAGetOverlappedResult failed %lm");
rc = __winsockerr();
goto Finished;
}
rc = got;
Finished:
WSACloseEvent(overlapped.hEvent);
return rc;
}

View file

@ -22,8 +22,11 @@
#include "libc/sock/select.h"
/**
* Does what poll() does except with a complicated bitset API.
* @note windows nt is limited to first 64 socket descriptors
* Does what poll() does except with bitset API.
*
* This system call is supported on all platforms. However, on Windows,
* this is polyfilled to translate into poll(). So it's recommended that
* poll() be used instead.
*/
int select(int nfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds,
struct timeval *timeout) {

View file

@ -16,17 +16,11 @@
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/calls/internal.h"
#include "libc/calls/sig.internal.h"
#include "libc/calls/strace.internal.h"
#include "libc/nt/enum/wait.h"
#include "libc/nt/errors.h"
#include "libc/calls/struct/iovec.h"
#include "libc/nt/struct/overlapped.h"
#include "libc/nt/winsock.h"
#include "libc/sock/internal.h"
#include "libc/sock/yoink.inc"
#include "libc/sysv/consts/fileno.h"
#include "libc/sysv/errfuns.h"
/**
@ -38,52 +32,16 @@
textwindows ssize_t sys_send_nt(int fd, const struct iovec *iov, size_t iovlen,
uint32_t flags) {
ssize_t rc;
uint32_t i, sent = 0;
uint32_t sent = 0;
struct NtIovec iovnt[16];
struct NtOverlapped overlapped = {.hEvent = WSACreateEvent()};
if (_check_interrupts(true, g_fds.p)) return eintr();
if (!WSASend(g_fds.p[fd].handle, iovnt, __iovec2nt(iovnt, iov, iovlen), &sent,
flags, &overlapped, NULL)) {
rc = sent;
goto Finished;
} else {
rc = __wsablock(g_fds.p[fd].handle, &overlapped, &flags, true);
}
if (WSAGetLastError() != kNtErrorIoPending) {
STRACE("WSASend failed %lm");
rc = __winsockerr();
goto Finished;
}
for (;;) {
i = WSAWaitForMultipleEvents(1, &overlapped.hEvent, true,
__SIG_POLLING_INTERVAL_MS, true);
if (i == kNtWaitFailed) {
STRACE("WSAWaitForMultipleEvents failed %lm");
rc = __winsockerr();
goto Finished;
} else if (i == kNtWaitTimeout) {
if (_check_interrupts(true, g_fds.p)) {
rc = eintr();
goto Finished;
}
} else if (i == kNtWaitIoCompletion) {
STRACE("IOCP TRIGGERED EINTR");
} else {
break;
}
}
if (!WSAGetOverlappedResult(g_fds.p[fd].handle, &overlapped, &sent, false,
&flags)) {
STRACE("WSAGetOverlappedResult failed %lm");
rc = __winsockerr();
goto Finished;
}
rc = sent;
Finished:
WSACloseEvent(overlapped.hEvent);
return rc;
}

View file

@ -16,10 +16,8 @@
TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE.
*/
#include "libc/calls/sig.internal.h"
#include "libc/calls/strace.internal.h"
#include "libc/nt/enum/wait.h"
#include "libc/nt/errors.h"
#include "libc/calls/internal.h"
#include "libc/calls/struct/iovec.h"
#include "libc/nt/struct/overlapped.h"
#include "libc/nt/winsock.h"
#include "libc/sock/internal.h"
@ -35,52 +33,16 @@ textwindows ssize_t sys_sendto_nt(int fd, const struct iovec *iov,
size_t iovlen, uint32_t flags,
void *opt_in_addr, uint32_t in_addrsize) {
ssize_t rc;
uint32_t i, sent = 0;
uint32_t sent = 0;
struct NtIovec iovnt[16];
struct NtOverlapped overlapped = {.hEvent = WSACreateEvent()};
if (_check_interrupts(true, g_fds.p)) return eintr();
if (!WSASendTo(g_fds.p[fd].handle, iovnt, __iovec2nt(iovnt, iov, iovlen),
&sent, flags, opt_in_addr, in_addrsize, &overlapped, NULL)) {
rc = sent;
goto Finished;
} else {
rc = __wsablock(g_fds.p[fd].handle, &overlapped, &flags, true);
}
if (WSAGetLastError() != kNtErrorIoPending) {
STRACE("WSASendTo failed %lm");
rc = __winsockerr();
goto Finished;
}
for (;;) {
i = WSAWaitForMultipleEvents(1, &overlapped.hEvent, true,
__SIG_POLLING_INTERVAL_MS, true);
if (i == kNtWaitFailed) {
STRACE("WSAWaitForMultipleEvents failed %lm");
rc = __winsockerr();
goto Finished;
} else if (i == kNtWaitTimeout) {
if (_check_interrupts(true, g_fds.p)) {
rc = eintr();
goto Finished;
}
} else if (i == kNtWaitIoCompletion) {
STRACE("IOCP TRIGGERED EINTR");
} else {
break;
}
}
if (!WSAGetOverlappedResult(g_fds.p[fd].handle, &overlapped, &sent, false,
&flags)) {
STRACE("WSAGetOverlappedResult failed %lm");
rc = __winsockerr();
goto Finished;
}
rc = sent;
Finished:
WSACloseEvent(overlapped.hEvent);
return rc;
}

44
libc/sock/stdinworker.c Normal file
View file

@ -0,0 +1,44 @@
/*-*- 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/internal.h"
#include "libc/calls/strace.internal.h"
#include "libc/runtime/runtime.h"
#include "libc/sock/ntstdin.internal.h"
#include "libc/sock/sock.h"
/* STATIC_YOINK("StdinWorker"); */
static textexit void StdinWorkerFree(void) {
int i;
NTTRACE("StdinWorkerFree()");
for (i = g_fds.n; i--;) {
if (g_fds.p[i].kind && g_fds.p[i].worker) {
close(i);
}
}
}
static textstartup void StdinWorkerInit(void) {
g_fds.p[0].worker = NewNtStdinWorker(0);
atexit(StdinWorkerFree);
}
const void *const StdinWorker[] initarray = {
StdinWorkerInit,
};

52
libc/sock/wsablock.c Normal file
View file

@ -0,0 +1,52 @@
/*-*- 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/sig.internal.h"
#include "libc/calls/strace.internal.h"
#include "libc/nt/enum/wait.h"
#include "libc/nt/errors.h"
#include "libc/sock/internal.h"
#include "libc/sock/sock.h"
#include "libc/sysv/errfuns.h"
textwindows int __wsablock(int64_t handle, struct NtOverlapped *overlapped,
uint32_t *flags, bool restartable) {
uint32_t i, got;
if (WSAGetLastError() != kNtErrorIoPending) {
NTTRACE("WSARecv failed %lm");
return __winsockerr();
}
for (;;) {
i = WSAWaitForMultipleEvents(1, &overlapped->hEvent, true,
__SIG_POLLING_INTERVAL_MS, true);
if (i == kNtWaitFailed) {
NTTRACE("WSAWaitForMultipleEvents failed %lm");
return __winsockerr();
} else if (i == kNtWaitTimeout || i == kNtWaitIoCompletion) {
if (_check_interrupts(restartable, g_fds.p)) return eintr();
POLLTRACE("WSAWaitForMultipleEvents...");
} else {
break;
}
}
if (!WSAGetOverlappedResult(handle, overlapped, &got, false, flags)) {
NTTRACE("WSAGetOverlappedResult failed %lm");
return __winsockerr();
}
return got;
}

View file

@ -1,2 +0,0 @@
.include "o/libc/sysv/macros.internal.inc"
.scall getegid,0xfff02b02b202b06c,globl

View file

@ -1,2 +0,0 @@
.include "o/libc/sysv/macros.internal.inc"
.scall getpgrp,0x051051051205106f,globl

View file

@ -0,0 +1,2 @@
.include "o/libc/sysv/macros.internal.inc"
.scall sys_getegid,0x02b02b02b202b06c,globl,hidden

Some files were not shown because too many files have changed in this diff Show more