mirror of
https://github.com/jart/cosmopolitan.git
synced 2025-06-27 14:58:30 +00:00
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:
parent
933411ba99
commit
dc0ea6640e
127 changed files with 1354 additions and 866 deletions
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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,
|
||||
};
|
||||
|
|
|
@ -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 fd≥0 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 fd≥0) 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
403
libc/sock/printargs.greg.c
Normal 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;
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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
44
libc/sock/stdinworker.c
Normal 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
52
libc/sock/wsablock.c
Normal 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;
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue