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

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

403
libc/sock/printargs.greg.c Normal file
View file

@ -0,0 +1,403 @@
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi
Copyright 2021 Justine Alexandra Roberts Tunney
Permission to use, copy, modify, and/or distribute this software for
any purpose with or without fee is hereby granted, provided that the
above copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE.
*/
#include "libc/calls/calls.h"
#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"
#include "libc/sock/sock.h"
#include "libc/sysv/consts/auxv.h"
#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"
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;
long *id;
const char *name;
} kAuxiliaryValues[] = {
{"%-14p", &AT_EXECFD, "AT_EXECFD"},
{"%-14p", &AT_PHDR, "AT_PHDR"},
{"%-14p", &AT_PHENT, "AT_PHENT"},
{"%-14p", &AT_PHNUM, "AT_PHNUM"},
{"%-14p", &AT_PAGESZ, "AT_PAGESZ"},
{"%-14p", &AT_BASE, "AT_BASE"},
{"%-14p", &AT_ENTRY, "AT_ENTRY"},
{"%-14p", &AT_NOTELF, "AT_NOTELF"},
{"%-14d", &AT_UID, "AT_UID"},
{"%-14d", &AT_EUID, "AT_EUID"},
{"%-14d", &AT_GID, "AT_GID"},
{"%-14d", &AT_EGID, "AT_EGID"},
{"%-14d", &AT_CLKTCK, "AT_CLKTCK"},
{"%-14d", &AT_OSRELDATE, "AT_OSRELDATE"},
{"%-14p", &AT_PLATFORM, "AT_PLATFORM"},
{"%-14p", &AT_DCACHEBSIZE, "AT_DCACHEBSIZE"},
{"%-14p", &AT_ICACHEBSIZE, "AT_ICACHEBSIZE"},
{"%-14p", &AT_UCACHEBSIZE, "AT_UCACHEBSIZE"},
{"%-14p", &AT_SECURE, "AT_SECURE"},
{"%-14s", &AT_BASE_PLATFORM, "AT_BASE_PLATFORM"},
{"%-14p", &AT_RANDOM, "AT_RANDOM"},
{"%-14s", &AT_EXECFN, "AT_EXECFN"},
{"%-14p", &AT_SYSINFO_EHDR, "AT_SYSINFO_EHDR"},
{"%-14p", &AT_FLAGS, "AT_FLAGS"},
{"%-14p", &AT_HWCAP, "AT_HWCAP"},
{"%-14p", &AT_HWCAP2, "AT_HWCAP2"},
{"%-14p", &AT_STACKBASE, "AT_STACKBASE"},
{"%-14p", &AT_CANARY, "AT_CANARY"},
{"%-14p", &AT_CANARYLEN, "AT_CANARYLEN"},
{"%-14ld", &AT_NCPUS, "AT_NCPUS"},
{"%-14p", &AT_PAGESIZES, "AT_PAGESIZES"},
{"%-14d", &AT_PAGESIZESLEN, "AT_PAGESIZESLEN"},
{"%-14p", &AT_TIMEKEEP, "AT_TIMEKEEP"},
{"%-14p", &AT_STACKPROT, "AT_STACKPROT"},
{"%-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) {
if (*kAuxiliaryValues[i].id && x == *kAuxiliaryValues[i].id) {
return kAuxiliaryValues + i;
}
}
return NULL;
}
/**
* 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;
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;
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);
if (*__argv) {
for (i = 0; i < __argc; ++i) {
PRINT(" ☼ %s", __argv[i]);
}
} else {
PRINT(" none");
}
PRINT("");
PRINT("ENVIRONMENT (%p)", __envp);
if (*__envp) {
for (env = __envp; *env; ++env) {
PRINT(" ☼ %s", *env);
}
} else {
PRINT(" none");
}
PRINT("");
PRINT("AUXILIARY (%p)", __auxv);
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);
PRINT(" ☼ %s = %#s", "program_executable_name", GetProgramExecutableName());
PRINT(" ☼ %s = %#s", "GetInterpreterExecutableName()",
GetInterpreterExecutableName(path, sizeof(path)));
PRINT(" ☼ %s = %p", "RSP", __builtin_frame_address(0));
PRINT(" ☼ %s = %p", "GetStackAddr()", GetStackAddr(0));
PRINT(" ☼ %s = %p", "GetStaticStackAddr(0)", GetStaticStackAddr(0));
PRINT(" ☼ %s = %p", "GetStackSize()", GetStackSize());
PRINT("");
PRINT("MEMTRACK");
PrintMemoryIntervals(2, &_mmi);
if (IsWindows()) {
struct NtStartupInfo startinfo;
GetStartupInfo(&startinfo);
PRINT("");
PRINT("GETSTARTUPINFO");
if (startinfo.lpDesktop)
PRINT(" ☼ %s = %#!hs", "lpDesktop", startinfo.lpDesktop);
if (startinfo.lpTitle) PRINT(" ☼ %s = %#!hs", "lpTitle", startinfo.lpTitle);
if (startinfo.dwX) PRINT(" ☼ %s = %u", "dwX", startinfo.dwX);
if (startinfo.dwY) PRINT(" ☼ %s = %u", "dwY", startinfo.dwY);
if (startinfo.dwXSize) PRINT(" ☼ %s = %u", "dwXSize", startinfo.dwXSize);
if (startinfo.dwYSize) PRINT(" ☼ %s = %u", "dwYSize", startinfo.dwYSize);
if (startinfo.dwXCountChars)
PRINT(" ☼ %s = %u", "dwXCountChars", startinfo.dwXCountChars);
if (startinfo.dwYCountChars)
PRINT(" ☼ %s = %u", "dwYCountChars", startinfo.dwYCountChars);
if (startinfo.dwFillAttribute)
PRINT(" ☼ %s = %u", "dwFillAttribute", startinfo.dwFillAttribute);
if (startinfo.dwFlags)
PRINT(" ☼ %s = %s", "dwFlags", DescribeNtStartFlags(startinfo.dwFlags));
if (startinfo.wShowWindow)
PRINT(" ☼ %s = %hu", "wShowWindow", startinfo.wShowWindow);
if (startinfo.cbReserved2)
PRINT(" ☼ %s = %hu", "cbReserved2", startinfo.cbReserved2);
if (startinfo.hStdInput)
PRINT(" ☼ %s = %ld", "hStdInput", startinfo.hStdInput);
if (startinfo.hStdOutput)
PRINT(" ☼ %s = %ld", "hStdOutput", startinfo.hStdOutput);
if (startinfo.hStdError)
PRINT(" ☼ %s = %ld", "hStdError", startinfo.hStdError);
PRINT("");
PRINT("STANDARD HANDLES");
PRINT(" ☼ %s = %ld", "GetStdHandle(kNtStdInputHandle)",
GetStdHandle(kNtStdInputHandle));
PRINT(" ☼ %s = %ld", "GetStdHandle(kNtStdOutputHandle)",
GetStdHandle(kNtStdOutputHandle));
PRINT(" ☼ %s = %ld", "GetStdHandle(kNtStdErrorHandle)",
GetStdHandle(kNtStdErrorHandle));
PRINT("");
PRINT("TEB");
PRINT(" ☼ gs:0x%02x %s = %p", 0x00, "NtGetSeh()", _NtGetSeh());
PRINT(" ☼ gs:0x%02x %s = %p", 0x08, "NtGetStackHigh()", _NtGetStackHigh());
PRINT(" ☼ gs:0x%02x %s = %p", 0x10, "NtGetStackLow()", _NtGetStackLow());
PRINT(" ☼ gs:0x%02x %s = %p", 0x18, "_NtGetSubsystemTib()",
_NtGetSubsystemTib());
PRINT(" ☼ gs:0x%02x %s = %p", 0x20, "NtGetFib()", _NtGetFib());
PRINT(" ☼ gs:0x%02x %s = %p", 0x30, "NtGetTeb()", NtGetTeb());
PRINT(" ☼ gs:0x%02x %s = %p", 0x38, "NtGetEnv()", _NtGetEnv());
PRINT(" ☼ gs:0x%02x %s = %p", 0x40, "NtGetPid()", NtGetPid());
PRINT(" ☼ gs:0x%02x %s = %p", 0x48, "NtGetTid()", NtGetTid());
PRINT(" ☼ gs:0x%02x %s = %p", 0x50, "NtGetRpc()", _NtGetRpc());
PRINT(" ☼ gs:0x%02x %s = %p", 0x58, "NtGetTls()", _NtGetTls());
PRINT(" ☼ gs:0x%02x %s = %p", 0x60, "NtGetPeb()", NtGetPeb());
PRINT(" ☼ gs:0x%02x %s = %p", 0x68, "NtGetErr()", NtGetErr());
PRINT("");
PRINT("DEPENDENCIES");
struct NtLinkedList *head = &NtGetPeb()->Ldr->InLoadOrderModuleList;
struct NtLinkedList *ldr = head->Next;
do {
const struct NtLdrDataTableEntry *dll =
(const struct NtLdrDataTableEntry *)ldr;
PRINT(" ☼ %.*!hs (%'zukb)", dll->FullDllName.Length,
dll->FullDllName.Data, dll->SizeOfImage / 1024);
} while ((ldr = ldr->Next) && ldr != head);
}
PRINT("");
__strace = st;
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;
}