mirror of
https://github.com/jart/cosmopolitan.git
synced 2025-05-29 00:32:29 +00:00
Make improvements
- Improved async signal safety of read() particularly for longjmp() - Started adding cancel cleanup handlers for locks / etc on Windows - Make /dev/tty work better particularly for uses like `foo | less` - Eagerly read console input into a linked list, so poll can signal - Fix some libc definitional bugs, which configure scripts detected
This commit is contained in:
parent
d6c2830850
commit
0c5dd7b342
85 changed files with 1062 additions and 671 deletions
52
ape/ape-m1.c
52
ape/ape-m1.c
|
@ -68,6 +68,16 @@ struct Syslib {
|
||||||
int (*pthread_attr_destroy)(pthread_attr_t *);
|
int (*pthread_attr_destroy)(pthread_attr_t *);
|
||||||
int (*pthread_attr_setstacksize)(pthread_attr_t *, size_t);
|
int (*pthread_attr_setstacksize)(pthread_attr_t *, size_t);
|
||||||
int (*pthread_attr_setguardsize)(pthread_attr_t *, size_t);
|
int (*pthread_attr_setguardsize)(pthread_attr_t *, size_t);
|
||||||
|
/* v4 (2023-09-19) */
|
||||||
|
void (*exit)(int);
|
||||||
|
long (*close)(int);
|
||||||
|
long (*munmap)(void *, size_t);
|
||||||
|
long (*openat)(int, const char *, int, int);
|
||||||
|
long (*write)(int, const void *, size_t);
|
||||||
|
long (*read)(int, void *, size_t);
|
||||||
|
long (*sigaction)(int, const struct sigaction *, struct sigaction *);
|
||||||
|
long (*pselect)(int, fd_set *, fd_set *, fd_set *, const struct timespec *, const sigset_t *);
|
||||||
|
long (*mprotect)(void *, size_t, int);
|
||||||
};
|
};
|
||||||
|
|
||||||
#define ELFCLASS32 1
|
#define ELFCLASS32 1
|
||||||
|
@ -792,14 +802,38 @@ static long sys_fork(void) {
|
||||||
return sysret(fork());
|
return sysret(fork());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static long sys_close(int fd) {
|
||||||
|
return sysret(close(fd));
|
||||||
|
}
|
||||||
|
|
||||||
static long sys_pipe(int pfds[2]) {
|
static long sys_pipe(int pfds[2]) {
|
||||||
return sysret(pipe(pfds));
|
return sysret(pipe(pfds));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static long sys_munmap(void *addr, size_t size) {
|
||||||
|
return sysret(munmap(addr, size));
|
||||||
|
}
|
||||||
|
|
||||||
|
static long sys_read(int fd, void *data, size_t size) {
|
||||||
|
return sysret(read(fd, data, size));
|
||||||
|
}
|
||||||
|
|
||||||
|
static long sys_mprotect(void *data, size_t size, int prot) {
|
||||||
|
return sysret(mprotect(data, size, prot));
|
||||||
|
}
|
||||||
|
|
||||||
|
static long sys_write(int fd, const void *data, size_t size) {
|
||||||
|
return sysret(write(fd, data, size));
|
||||||
|
}
|
||||||
|
|
||||||
static long sys_clock_gettime(int clock, struct timespec *ts) {
|
static long sys_clock_gettime(int clock, struct timespec *ts) {
|
||||||
return sysret(clock_gettime((clockid_t)clock, ts));
|
return sysret(clock_gettime((clockid_t)clock, ts));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static long sys_openat(int fd, const char *path, int flags, int mode) {
|
||||||
|
return sysret(openat(fd, path, flags, mode));
|
||||||
|
}
|
||||||
|
|
||||||
static long sys_nanosleep(const struct timespec *req, struct timespec *rem) {
|
static long sys_nanosleep(const struct timespec *req, struct timespec *rem) {
|
||||||
return sysret(nanosleep(req, rem));
|
return sysret(nanosleep(req, rem));
|
||||||
}
|
}
|
||||||
|
@ -809,6 +843,15 @@ static long sys_mmap(void *addr, size_t size, int prot, int flags, int fd,
|
||||||
return sysret((long)mmap(addr, size, prot, flags, fd, off));
|
return sysret((long)mmap(addr, size, prot, flags, fd, off));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static long sys_sigaction(int sig, const struct sigaction *act, struct sigaction *oact) {
|
||||||
|
return sysret(sigaction(sig, act, oact));
|
||||||
|
}
|
||||||
|
|
||||||
|
static long sys_pselect(int nfds, fd_set *readfds, fd_set *writefds, fd_set *errorfds,
|
||||||
|
const struct timespec *timeout, const sigset_t *sigmask) {
|
||||||
|
return sysret(pselect(nfds, readfds, writefds, errorfds, timeout, sigmask));
|
||||||
|
}
|
||||||
|
|
||||||
int main(int argc, char **argv, char **envp) {
|
int main(int argc, char **argv, char **envp) {
|
||||||
unsigned i;
|
unsigned i;
|
||||||
int c, n, fd, rc;
|
int c, n, fd, rc;
|
||||||
|
@ -852,6 +895,15 @@ int main(int argc, char **argv, char **envp) {
|
||||||
M->lib.pthread_attr_destroy = pthread_attr_destroy;
|
M->lib.pthread_attr_destroy = pthread_attr_destroy;
|
||||||
M->lib.pthread_attr_setstacksize = pthread_attr_setstacksize;
|
M->lib.pthread_attr_setstacksize = pthread_attr_setstacksize;
|
||||||
M->lib.pthread_attr_setguardsize = pthread_attr_setguardsize;
|
M->lib.pthread_attr_setguardsize = pthread_attr_setguardsize;
|
||||||
|
M->lib.exit = exit;
|
||||||
|
M->lib.close = sys_close;
|
||||||
|
M->lib.munmap = sys_munmap;
|
||||||
|
M->lib.openat = sys_openat;
|
||||||
|
M->lib.write = sys_write;
|
||||||
|
M->lib.read = sys_read;
|
||||||
|
M->lib.sigaction = sys_sigaction;
|
||||||
|
M->lib.pselect = sys_pselect;
|
||||||
|
M->lib.mprotect = sys_mprotect;
|
||||||
|
|
||||||
/* getenv("_") is close enough to at_execfn */
|
/* getenv("_") is close enough to at_execfn */
|
||||||
execfn = argc > 0 ? argv[0] : 0;
|
execfn = argc > 0 ? argv[0] : 0;
|
||||||
|
|
|
@ -86,7 +86,7 @@ IGNORE := $(shell $(MKDIR) $(TMPDIR))
|
||||||
|
|
||||||
ifneq ($(findstring aarch64,$(MODE)),)
|
ifneq ($(findstring aarch64,$(MODE)),)
|
||||||
ARCH = aarch64
|
ARCH = aarch64
|
||||||
HOSTS ?= pi silicon-wifi
|
HOSTS ?= pi silicon
|
||||||
else
|
else
|
||||||
ARCH = x86_64
|
ARCH = x86_64
|
||||||
HOSTS ?= freebsd rhel7 rhel5 xnu win10 openbsd netbsd
|
HOSTS ?= freebsd rhel7 rhel5 xnu win10 openbsd netbsd
|
||||||
|
|
|
@ -28,7 +28,7 @@ o/$(MODE)/%.com.ok: \
|
||||||
o/$(MODE)/tool/build/runit.com \
|
o/$(MODE)/tool/build/runit.com \
|
||||||
o/$(MODE)/tool/build/runitd.com \
|
o/$(MODE)/tool/build/runitd.com \
|
||||||
o/$(MODE)/%.com
|
o/$(MODE)/%.com
|
||||||
$(COMPILE) -wATEST -tT$@ $^ $(HOSTS)
|
@$(COMPILE) -wATEST -tT$@ $^ $(HOSTS)
|
||||||
|
|
||||||
.PHONY:
|
.PHONY:
|
||||||
o/tiny/tool/build/runit.com:
|
o/tiny/tool/build/runit.com:
|
||||||
|
|
|
@ -8,14 +8,17 @@
|
||||||
╚─────────────────────────────────────────────────────────────────*/
|
╚─────────────────────────────────────────────────────────────────*/
|
||||||
#endif
|
#endif
|
||||||
#include "dsp/tty/tty.h"
|
#include "dsp/tty/tty.h"
|
||||||
|
#include "libc/assert.h"
|
||||||
#include "libc/calls/calls.h"
|
#include "libc/calls/calls.h"
|
||||||
|
#include "libc/calls/internal.h"
|
||||||
#include "libc/calls/struct/sigaction.h"
|
#include "libc/calls/struct/sigaction.h"
|
||||||
|
#include "libc/calls/struct/sigset.h"
|
||||||
#include "libc/calls/termios.h"
|
#include "libc/calls/termios.h"
|
||||||
#include "libc/errno.h"
|
#include "libc/errno.h"
|
||||||
#include "libc/fmt/fmt.h"
|
#include "libc/fmt/fmt.h"
|
||||||
|
#include "libc/intrin/kprintf.h"
|
||||||
#include "libc/log/check.h"
|
#include "libc/log/check.h"
|
||||||
#include "libc/log/log.h"
|
#include "libc/log/log.h"
|
||||||
#include "libc/nt/runtime.h"
|
|
||||||
#include "libc/runtime/runtime.h"
|
#include "libc/runtime/runtime.h"
|
||||||
#include "libc/sock/select.h"
|
#include "libc/sock/select.h"
|
||||||
#include "libc/stdio/dprintf.h"
|
#include "libc/stdio/dprintf.h"
|
||||||
|
@ -36,29 +39,30 @@
|
||||||
#define PROBE_DISPLAY_SIZE "\e7\e[9979;9979H\e[6n\e8"
|
#define PROBE_DISPLAY_SIZE "\e7\e[9979;9979H\e[6n\e8"
|
||||||
|
|
||||||
char code[512];
|
char code[512];
|
||||||
|
int infd, outfd;
|
||||||
struct winsize wsize;
|
struct winsize wsize;
|
||||||
struct termios oldterm;
|
struct termios oldterm;
|
||||||
volatile bool resized, killed;
|
volatile bool resized, killed;
|
||||||
|
|
||||||
void onresize(void) {
|
void OnResize(int sig) {
|
||||||
resized = true;
|
resized = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void onkilled(int sig) {
|
void OnKilled(int sig) {
|
||||||
killed = true;
|
killed = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void restoretty(void) {
|
void RestoreTty(void) {
|
||||||
WRITE(1, DISABLE_MOUSE_TRACKING);
|
WRITE(outfd, DISABLE_MOUSE_TRACKING);
|
||||||
tcsetattr(1, TCSANOW, &oldterm);
|
tcsetattr(outfd, TCSANOW, &oldterm);
|
||||||
}
|
}
|
||||||
|
|
||||||
int rawmode(void) {
|
int EnableRawMode(void) {
|
||||||
static bool once;
|
static bool once;
|
||||||
struct termios t;
|
struct termios t;
|
||||||
if (!once) {
|
if (!once) {
|
||||||
if (!tcgetattr(1, &oldterm)) {
|
if (!tcgetattr(outfd, &oldterm)) {
|
||||||
atexit(restoretty);
|
atexit(RestoreTty);
|
||||||
} else {
|
} else {
|
||||||
perror("tcgetattr");
|
perror("tcgetattr");
|
||||||
}
|
}
|
||||||
|
@ -78,26 +82,26 @@ int rawmode(void) {
|
||||||
|
|
||||||
t.c_iflag &= ~(INPCK | ISTRIP | PARMRK | INLCR | IGNCR | ICRNL | IXON |
|
t.c_iflag &= ~(INPCK | ISTRIP | PARMRK | INLCR | IGNCR | ICRNL | IXON |
|
||||||
IGNBRK | BRKINT);
|
IGNBRK | BRKINT);
|
||||||
t.c_lflag &= ~(IEXTEN | ICANON | ECHO | ECHONL | ISIG);
|
t.c_lflag &= ~(IEXTEN | ICANON | ECHO | ECHONL /* | ISIG */);
|
||||||
t.c_cflag &= ~(CSIZE | PARENB);
|
t.c_cflag &= ~(CSIZE | PARENB);
|
||||||
t.c_oflag |= OPOST | ONLCR;
|
t.c_oflag |= OPOST | ONLCR;
|
||||||
t.c_cflag |= CS8;
|
t.c_cflag |= CS8;
|
||||||
t.c_iflag |= IUTF8;
|
t.c_iflag |= IUTF8;
|
||||||
|
|
||||||
if (tcsetattr(1, TCSANOW, &t)) {
|
if (tcsetattr(outfd, TCSANOW, &t)) {
|
||||||
perror("tcsetattr");
|
perror("tcsetattr");
|
||||||
}
|
}
|
||||||
|
|
||||||
/* WRITE(1, ENABLE_SAFE_PASTE); */
|
WRITE(outfd, ENABLE_MOUSE_TRACKING);
|
||||||
/* WRITE(1, ENABLE_MOUSE_TRACKING); */
|
/* WRITE(outfd, ENABLE_SAFE_PASTE); */
|
||||||
/* WRITE(1, PROBE_DISPLAY_SIZE); */
|
/* WRITE(outfd, PROBE_DISPLAY_SIZE); */
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void getsize(void) {
|
void GetTtySize(void) {
|
||||||
if (tcgetwinsize(1, &wsize) != -1) {
|
if (tcgetwinsize(outfd, &wsize) != -1) {
|
||||||
printf("termios says terminal size is %hu×%hu\r\n", wsize.ws_col,
|
dprintf(outfd, "termios says terminal size is %hu×%hu\r\n", wsize.ws_col,
|
||||||
wsize.ws_row);
|
wsize.ws_row);
|
||||||
} else {
|
} else {
|
||||||
perror("tcgetwinsize");
|
perror("tcgetwinsize");
|
||||||
}
|
}
|
||||||
|
@ -144,50 +148,63 @@ const char *describemouseevent(int e) {
|
||||||
// change the code above to enable ISIG if you want to trigger this
|
// change the code above to enable ISIG if you want to trigger this
|
||||||
// then press ctrl-c or ctrl-\ in your pseudoteletypewriter console
|
// then press ctrl-c or ctrl-\ in your pseudoteletypewriter console
|
||||||
void OnSignalThatWontEintrRead(int sig) {
|
void OnSignalThatWontEintrRead(int sig) {
|
||||||
dprintf(1, "got %s (read()ing will SA_RESTART)\n", strsignal(sig));
|
dprintf(outfd, "got %s (read()ing will SA_RESTART; try CTRL-D to exit)\n",
|
||||||
|
strsignal(sig));
|
||||||
|
}
|
||||||
|
|
||||||
|
void OnSignalThatWillEintrRead(int sig) {
|
||||||
|
dprintf(outfd, "got %s (read() operation will be aborted)\n", strsignal(sig));
|
||||||
}
|
}
|
||||||
|
|
||||||
int main(int argc, char *argv[]) {
|
int main(int argc, char *argv[]) {
|
||||||
int e, c, y, x, n, yn, xn;
|
int e, c, y, x, n, yn, xn;
|
||||||
|
infd = 0;
|
||||||
|
outfd = 1;
|
||||||
|
/* infd = outfd = open("/dev/tty", O_RDWR); */
|
||||||
|
signal(SIGTERM, OnKilled);
|
||||||
|
signal(SIGCONT, OnResize);
|
||||||
|
signal(SIGWINCH, OnResize);
|
||||||
signal(SIGINT, OnSignalThatWontEintrRead);
|
signal(SIGINT, OnSignalThatWontEintrRead);
|
||||||
signal(SIGQUIT, OnSignalThatWontEintrRead);
|
sigaction(SIGQUIT,
|
||||||
xsigaction(SIGTERM, onkilled, 0, 0, NULL);
|
&(struct sigaction){.sa_handler = OnSignalThatWillEintrRead}, 0);
|
||||||
xsigaction(SIGWINCH, onresize, 0, 0, NULL);
|
EnableRawMode();
|
||||||
xsigaction(SIGCONT, onresize, 0, 0, NULL);
|
GetTtySize();
|
||||||
rawmode();
|
|
||||||
getsize();
|
|
||||||
while (!killed) {
|
while (!killed) {
|
||||||
if (resized) {
|
if (resized) {
|
||||||
printf("SIGWINCH ");
|
dprintf(outfd, "SIGWINCH ");
|
||||||
getsize();
|
GetTtySize();
|
||||||
resized = false;
|
resized = false;
|
||||||
}
|
}
|
||||||
bzero(code, sizeof(code));
|
bzero(code, sizeof(code));
|
||||||
if ((n = readansi(0, code, sizeof(code))) == -1) {
|
if ((n = read(infd, code, sizeof(code))) == -1) {
|
||||||
if (errno == EINTR) continue;
|
if (errno == EINTR) {
|
||||||
|
dprintf(outfd, "read() was interrupted\n");
|
||||||
|
continue;
|
||||||
|
}
|
||||||
perror("read");
|
perror("read");
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
if (!n) {
|
if (!n) {
|
||||||
printf("got stdin eof\n");
|
dprintf(outfd, "got stdin eof\n");
|
||||||
exit(0);
|
exit(0);
|
||||||
}
|
}
|
||||||
printf("%`'.*s (got %d) ", n, code, n);
|
dprintf(outfd, "%`'.*s (got %d) ", n, code, n);
|
||||||
if (iscntrl(code[0]) && !code[1]) {
|
if (iscntrl(code[0]) && !code[1]) {
|
||||||
printf("is CTRL-%c a.k.a. ^%c\r\n", CTRL(code[0]), CTRL(code[0]));
|
dprintf(outfd, "is CTRL-%c a.k.a. ^%c\r\n", CTRL(code[0]), CTRL(code[0]));
|
||||||
if (code[0] == CTRL('C') || code[0] == CTRL('D')) break;
|
if (code[0] == CTRL('C') || code[0] == CTRL('D')) break;
|
||||||
} else if (startswith(code, "\e[") && endswith(code, "R")) {
|
} else if (startswith(code, "\e[") && endswith(code, "R")) {
|
||||||
yn = 1, xn = 1;
|
yn = 1, xn = 1;
|
||||||
sscanf(code, "\e[%d;%dR", &yn, &xn);
|
sscanf(code, "\e[%d;%dR", &yn, &xn);
|
||||||
printf("inband signalling says terminal size is %d×%d\r\n", xn, yn);
|
dprintf(outfd, "inband signalling says terminal size is %d×%d\r\n", xn,
|
||||||
|
yn);
|
||||||
} else if (startswith(code, "\e[<") &&
|
} else if (startswith(code, "\e[<") &&
|
||||||
(endswith(code, "m") || endswith(code, "M"))) {
|
(endswith(code, "m") || endswith(code, "M"))) {
|
||||||
e = 0, y = 1, x = 1;
|
e = 0, y = 1, x = 1;
|
||||||
sscanf(code, "\e[<%d;%d;%d%c", &e, &y, &x, &c);
|
sscanf(code, "\e[<%d;%d;%d%c", &e, &y, &x, &c);
|
||||||
printf("mouse %s at %d×%d\r\n", describemouseevent(e | (c == 'm') << 2),
|
dprintf(outfd, "mouse %s at %d×%d\r\n",
|
||||||
x, y);
|
describemouseevent(e | (c == 'm') << 2), x, y);
|
||||||
} else {
|
} else {
|
||||||
printf("\r\n");
|
dprintf(outfd, "\r\n");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
|
|
|
@ -1,14 +0,0 @@
|
||||||
#ifndef COSMOPOLITAN_LIBC_CALLS_CONSOLE_INTERNAL_H_
|
|
||||||
#define COSMOPOLITAN_LIBC_CALLS_CONSOLE_INTERNAL_H_
|
|
||||||
#include "libc/calls/struct/fd.internal.h"
|
|
||||||
#include "libc/nt/struct/inputrecord.h"
|
|
||||||
#if !(__ASSEMBLER__ + __LINKER__ + 0)
|
|
||||||
COSMOPOLITAN_C_START_
|
|
||||||
|
|
||||||
int CountConsoleInputBytes(int64_t);
|
|
||||||
int ConvertConsoleInputToAnsi(const struct NtInputRecord *, char[hasatleast 32],
|
|
||||||
uint16_t *, struct Fd *);
|
|
||||||
|
|
||||||
COSMOPOLITAN_C_END_
|
|
||||||
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
|
|
||||||
#endif /* COSMOPOLITAN_LIBC_CALLS_CONSOLE_INTERNAL_H_ */
|
|
|
@ -59,3 +59,5 @@ int fstatfs(int fd, struct statfs *sf) {
|
||||||
STRACE("fstatfs(%d, [%s]) → %d% m", fd, DescribeStatfs(rc, sf));
|
STRACE("fstatfs(%d, [%s]) → %d% m", fd, DescribeStatfs(rc, sf));
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
__weak_reference(fstatfs, fstatfs64);
|
||||||
|
|
|
@ -57,3 +57,5 @@ int getrlimit(int resource, struct rlimit *rlim) {
|
||||||
DescribeRlimit(rc, rlim), rc);
|
DescribeRlimit(rc, rlim), rc);
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
__weak_reference(getrlimit, getrlimit64);
|
||||||
|
|
|
@ -25,6 +25,9 @@ int __ensurefds(int);
|
||||||
int __ensurefds_unlocked(int);
|
int __ensurefds_unlocked(int);
|
||||||
void __printfds(void);
|
void __printfds(void);
|
||||||
uint32_t sys_getuid_nt(void);
|
uint32_t sys_getuid_nt(void);
|
||||||
|
int __pause_thread(uint32_t);
|
||||||
|
int CountConsoleInputBytes(int64_t);
|
||||||
|
int FlushConsoleInputBytes(int64_t);
|
||||||
|
|
||||||
forceinline int64_t __getfdhandleactual(int fd) {
|
forceinline int64_t __getfdhandleactual(int fd) {
|
||||||
return g_fds.p[fd].handle;
|
return g_fds.p[fd].handle;
|
||||||
|
|
|
@ -19,6 +19,7 @@
|
||||||
#include "libc/calls/internal.h"
|
#include "libc/calls/internal.h"
|
||||||
#include "libc/calls/sig.internal.h"
|
#include "libc/calls/sig.internal.h"
|
||||||
#include "libc/errno.h"
|
#include "libc/errno.h"
|
||||||
|
#include "libc/intrin/strace.internal.h"
|
||||||
#include "libc/intrin/weaken.h"
|
#include "libc/intrin/weaken.h"
|
||||||
#include "libc/sysv/errfuns.h"
|
#include "libc/sysv/errfuns.h"
|
||||||
#include "libc/thread/posixthread.internal.h"
|
#include "libc/thread/posixthread.internal.h"
|
||||||
|
@ -33,7 +34,9 @@ textwindows int _check_interrupts(int sigops) {
|
||||||
goto Interrupted;
|
goto Interrupted;
|
||||||
}
|
}
|
||||||
if (_weaken(__sig_check) && (status = _weaken(__sig_check)())) {
|
if (_weaken(__sig_check) && (status = _weaken(__sig_check)())) {
|
||||||
|
STRACE("syscall interrupted (status=%d, sigops=%d)", status, sigops);
|
||||||
if (status == 2 && (sigops & kSigOpRestartable)) {
|
if (status == 2 && (sigops & kSigOpRestartable)) {
|
||||||
|
STRACE("restarting system call");
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
err = EINTR;
|
err = EINTR;
|
||||||
|
|
|
@ -17,7 +17,6 @@
|
||||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||||
#include "libc/assert.h"
|
#include "libc/assert.h"
|
||||||
#include "libc/calls/console.internal.h"
|
|
||||||
#include "libc/calls/internal.h"
|
#include "libc/calls/internal.h"
|
||||||
#include "libc/calls/struct/fd.internal.h"
|
#include "libc/calls/struct/fd.internal.h"
|
||||||
#include "libc/calls/syscall-sysv.internal.h"
|
#include "libc/calls/syscall-sysv.internal.h"
|
||||||
|
@ -91,10 +90,9 @@ static int ioctl_default(int fd, unsigned long request, void *arg) {
|
||||||
}
|
}
|
||||||
|
|
||||||
static int ioctl_fionread(int fd, uint32_t *arg) {
|
static int ioctl_fionread(int fd, uint32_t *arg) {
|
||||||
|
int rc;
|
||||||
uint32_t cm;
|
uint32_t cm;
|
||||||
int64_t handle;
|
int64_t handle;
|
||||||
uint32_t avail;
|
|
||||||
int rc, e = errno;
|
|
||||||
if (!IsWindows()) {
|
if (!IsWindows()) {
|
||||||
return sys_ioctl(fd, FIONREAD, arg);
|
return sys_ioctl(fd, FIONREAD, arg);
|
||||||
} else if (__isfdopen(fd)) {
|
} else if (__isfdopen(fd)) {
|
||||||
|
@ -106,19 +104,18 @@ static int ioctl_fionread(int fd, uint32_t *arg) {
|
||||||
return _weaken(__winsockerr)();
|
return _weaken(__winsockerr)();
|
||||||
}
|
}
|
||||||
} else if (GetFileType(handle) == kNtFileTypePipe) {
|
} else if (GetFileType(handle) == kNtFileTypePipe) {
|
||||||
|
uint32_t avail;
|
||||||
if (PeekNamedPipe(handle, 0, 0, 0, &avail, 0)) {
|
if (PeekNamedPipe(handle, 0, 0, 0, &avail, 0)) {
|
||||||
*arg = avail;
|
*arg = avail;
|
||||||
return 0;
|
return 0;
|
||||||
|
} else if (GetLastError() == kNtErrorBrokenPipe) {
|
||||||
|
return 0;
|
||||||
} else {
|
} else {
|
||||||
return __winerr();
|
return __winerr();
|
||||||
}
|
}
|
||||||
} else if (GetConsoleMode(handle, &cm)) {
|
} else if (GetConsoleMode(handle, &cm)) {
|
||||||
avail = CountConsoleInputBytes(handle);
|
int bytes = CountConsoleInputBytes(handle);
|
||||||
if (avail == -1u && errno == ENODATA) {
|
return MAX(0, bytes);
|
||||||
errno = e;
|
|
||||||
avail = 0;
|
|
||||||
}
|
|
||||||
return avail;
|
|
||||||
} else {
|
} else {
|
||||||
return eopnotsupp();
|
return eopnotsupp();
|
||||||
}
|
}
|
||||||
|
|
|
@ -144,33 +144,13 @@ static textwindows int sys_open_nt_console(int dirfd,
|
||||||
const struct NtMagicPaths *mp,
|
const struct NtMagicPaths *mp,
|
||||||
uint32_t flags, int32_t mode,
|
uint32_t flags, int32_t mode,
|
||||||
size_t fd) {
|
size_t fd) {
|
||||||
uint32_t cm;
|
|
||||||
int input, output;
|
|
||||||
if ((__isfdopen((input = STDIN_FILENO)) &&
|
|
||||||
GetConsoleMode(g_fds.p[input].handle, &cm)) &&
|
|
||||||
((__isfdopen((output = STDOUT_FILENO)) &&
|
|
||||||
GetConsoleMode(g_fds.p[output].handle, &cm)) ||
|
|
||||||
(__isfdopen((output = STDERR_FILENO)) &&
|
|
||||||
GetConsoleMode(g_fds.p[output].handle, &cm)))) {
|
|
||||||
// this is an ugly hack that works for observed usage patterns
|
|
||||||
g_fds.p[fd].handle = g_fds.p[input].handle;
|
|
||||||
g_fds.p[fd].extra = g_fds.p[output].handle;
|
|
||||||
g_fds.p[fd].dontclose = true;
|
|
||||||
g_fds.p[input].dontclose = true;
|
|
||||||
g_fds.p[output].dontclose = true;
|
|
||||||
} else if ((g_fds.p[fd].handle = sys_open_nt_impl(
|
|
||||||
dirfd, mp->conin, (flags & ~O_ACCMODE) | O_RDONLY, mode,
|
|
||||||
kNtFileFlagOverlapped)) != -1) {
|
|
||||||
g_fds.p[fd].extra =
|
|
||||||
sys_open_nt_impl(dirfd, mp->conout, (flags & ~O_ACCMODE) | O_WRONLY,
|
|
||||||
mode, kNtFileFlagOverlapped);
|
|
||||||
npassert(g_fds.p[fd].extra != -1);
|
|
||||||
} else {
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
g_fds.p[fd].kind = kFdConsole;
|
g_fds.p[fd].kind = kFdConsole;
|
||||||
g_fds.p[fd].flags = flags;
|
g_fds.p[fd].flags = flags;
|
||||||
g_fds.p[fd].mode = mode;
|
g_fds.p[fd].mode = mode;
|
||||||
|
g_fds.p[fd].handle = CreateFile(u"CONIN$", kNtGenericRead | kNtGenericWrite,
|
||||||
|
kNtFileShareRead, 0, kNtOpenExisting, 0, 0);
|
||||||
|
g_fds.p[fd].extra = CreateFile(u"CONOUT$", kNtGenericRead | kNtGenericWrite,
|
||||||
|
kNtFileShareWrite, 0, kNtOpenExisting, 0, 0);
|
||||||
return fd;
|
return fd;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
0
libc/calls/overlap.h
Executable file
0
libc/calls/overlap.h
Executable file
31
libc/calls/overlapped.c
Normal file
31
libc/calls/overlapped.c
Normal 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 2023 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/overlap.h"
|
||||||
|
#include "libc/calls/overlapped.internal.h"
|
||||||
|
#include "libc/nt/files.h"
|
||||||
|
#include "libc/nt/runtime.h"
|
||||||
|
#include "libc/nt/thread.h"
|
||||||
|
|
||||||
|
void overlapped_cleanup_callback(void *arg) {
|
||||||
|
uint32_t got;
|
||||||
|
struct OverlappedCleanup *cleanup = arg;
|
||||||
|
CancelIoEx(cleanup->handle, cleanup->overlap);
|
||||||
|
GetOverlappedResult(cleanup->handle, cleanup->overlap, &got, true);
|
||||||
|
CloseHandle(cleanup->overlap->hEvent);
|
||||||
|
}
|
25
libc/calls/overlapped.internal.h
Normal file
25
libc/calls/overlapped.internal.h
Normal file
|
@ -0,0 +1,25 @@
|
||||||
|
#ifndef COSMOPOLITAN_LIBC_CALLS_OVERLAPPED_INTERNAL_H_
|
||||||
|
#define COSMOPOLITAN_LIBC_CALLS_OVERLAPPED_INTERNAL_H_
|
||||||
|
#include "libc/nt/struct/overlapped.h"
|
||||||
|
#if !(__ASSEMBLER__ + __LINKER__ + 0)
|
||||||
|
COSMOPOLITAN_C_START_
|
||||||
|
|
||||||
|
#define overlapped_cleanup_push(handle, overlap) \
|
||||||
|
{ \
|
||||||
|
struct OverlappedCleanup overlapped_cleanup = {handle, overlap}; \
|
||||||
|
pthread_cleanup_push(overlapped_cleanup_callback, &overlapped_cleanup);
|
||||||
|
|
||||||
|
#define overlapped_cleanup_pop() \
|
||||||
|
pthread_cleanup_pop(false); \
|
||||||
|
}
|
||||||
|
|
||||||
|
struct OverlappedCleanup {
|
||||||
|
int64_t handle;
|
||||||
|
struct NtOverlapped *overlap;
|
||||||
|
};
|
||||||
|
|
||||||
|
void overlapped_cleanup_callback(void *);
|
||||||
|
|
||||||
|
COSMOPOLITAN_C_END_
|
||||||
|
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
|
||||||
|
#endif /* COSMOPOLITAN_LIBC_CALLS_OVERLAPPED_INTERNAL_H_ */
|
|
@ -19,22 +19,11 @@
|
||||||
#include "libc/calls/internal.h"
|
#include "libc/calls/internal.h"
|
||||||
#include "libc/calls/sig.internal.h"
|
#include "libc/calls/sig.internal.h"
|
||||||
#include "libc/calls/syscall_support-nt.internal.h"
|
#include "libc/calls/syscall_support-nt.internal.h"
|
||||||
#include "libc/errno.h"
|
|
||||||
#include "libc/nt/synchronization.h"
|
|
||||||
#include "libc/thread/posixthread.internal.h"
|
|
||||||
#include "libc/thread/tls.h"
|
|
||||||
|
|
||||||
textwindows int sys_pause_nt(void) {
|
textwindows int sys_pause_nt(void) {
|
||||||
int rc;
|
int rc;
|
||||||
while (!(rc = _check_interrupts(0))) {
|
while (!(rc = _check_interrupts(0))) {
|
||||||
struct PosixThread *pt = _pthread_self();
|
if ((rc = __pause_thread(__SIG_SIG_INTERVAL_MS))) {
|
||||||
pt->abort_errno = 0;
|
|
||||||
pt->pt_flags |= PT_INSEMAPHORE;
|
|
||||||
WaitForSingleObject(pt->semaphore, __SIG_SIG_INTERVAL_MS);
|
|
||||||
pt->pt_flags &= ~PT_INSEMAPHORE;
|
|
||||||
if (pt->abort_errno) {
|
|
||||||
errno = pt->abort_errno;
|
|
||||||
rc = -1;
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -37,7 +37,9 @@
|
||||||
*
|
*
|
||||||
* However this has a tinier footprint and better logging.
|
* However this has a tinier footprint and better logging.
|
||||||
*
|
*
|
||||||
* @return -1 w/ errno set to EINTR
|
* @return -1 w/ errno
|
||||||
|
* @raise ECANCELED if this thread was canceled in masked mode
|
||||||
|
* @raise EINTR if interrupted by a signal
|
||||||
* @cancellationpoint
|
* @cancellationpoint
|
||||||
* @see sigsuspend()
|
* @see sigsuspend()
|
||||||
* @norestart
|
* @norestart
|
||||||
|
|
|
@ -16,41 +16,21 @@
|
||||||
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
||||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||||
#include "libc/assert.h"
|
|
||||||
#include "libc/calls/calls.h"
|
#include "libc/calls/calls.h"
|
||||||
#include "libc/calls/console.internal.h"
|
|
||||||
#include "libc/calls/struct/fd.internal.h"
|
|
||||||
#include "libc/calls/syscall_support-nt.internal.h"
|
|
||||||
#include "libc/errno.h"
|
#include "libc/errno.h"
|
||||||
#include "libc/macros.internal.h"
|
#include "libc/nt/synchronization.h"
|
||||||
#include "libc/nt/console.h"
|
#include "libc/thread/posixthread.internal.h"
|
||||||
#include "libc/nt/struct/inputrecord.h"
|
|
||||||
#ifdef __x86_64__
|
|
||||||
|
|
||||||
int CountConsoleInputBytes(int64_t handle) {
|
textwindows int __pause_thread(uint32_t ms) {
|
||||||
char buf[32];
|
uint32_t status;
|
||||||
int rc, e = errno;
|
struct PosixThread *pt = _pthread_self();
|
||||||
uint16_t utf16hs = 0;
|
pt->pt_flags |= PT_INSEMAPHORE;
|
||||||
uint32_t i, n, count;
|
status = WaitForSingleObject(pt->semaphore, ms);
|
||||||
struct NtInputRecord records[64];
|
if (status == -1u) notpossible;
|
||||||
if (PeekConsoleInput(handle, records, ARRAYLEN(records), &n)) {
|
if (!(pt->pt_flags & PT_INSEMAPHORE)) {
|
||||||
for (rc = i = 0; i < n; ++i) {
|
errno = pt->abort_errno;
|
||||||
count = ConvertConsoleInputToAnsi(records + i, buf, &utf16hs, 0);
|
return -1;
|
||||||
if (count == -1) {
|
|
||||||
unassert(errno == ENODATA);
|
|
||||||
if (!rc) {
|
|
||||||
rc = -1;
|
|
||||||
} else {
|
|
||||||
errno = e;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
rc += count;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
rc = __winerr();
|
|
||||||
}
|
}
|
||||||
return rc;
|
pt->pt_flags &= ~PT_INSEMAPHORE;
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif /* __x86_64__ */
|
|
|
@ -35,7 +35,7 @@
|
||||||
* Permits system operations, e.g.
|
* Permits system operations, e.g.
|
||||||
*
|
*
|
||||||
* __pledge_mode = PLEDGE_PENALTY_KILL_PROCESS | PLEDGE_STDERR_LOGGING;
|
* __pledge_mode = PLEDGE_PENALTY_KILL_PROCESS | PLEDGE_STDERR_LOGGING;
|
||||||
* if (pledge("stdio rfile tty", 0)) {
|
* if (pledge("stdio rpath tty", 0)) {
|
||||||
* perror("pledge");
|
* perror("pledge");
|
||||||
* exit(1);
|
* exit(1);
|
||||||
* }
|
* }
|
||||||
|
|
|
@ -16,13 +16,16 @@
|
||||||
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
||||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||||
|
#include "libc/assert.h"
|
||||||
#include "libc/calls/calls.h"
|
#include "libc/calls/calls.h"
|
||||||
#include "libc/calls/console.internal.h"
|
|
||||||
#include "libc/calls/internal.h"
|
#include "libc/calls/internal.h"
|
||||||
#include "libc/calls/sig.internal.h"
|
#include "libc/calls/sig.internal.h"
|
||||||
#include "libc/calls/state.internal.h"
|
#include "libc/calls/state.internal.h"
|
||||||
#include "libc/calls/struct/sigaction.h"
|
#include "libc/calls/struct/sigaction.h"
|
||||||
|
#include "libc/calls/struct/timespec.h"
|
||||||
|
#include "libc/dce.h"
|
||||||
#include "libc/errno.h"
|
#include "libc/errno.h"
|
||||||
|
#include "libc/intrin/atomic.h"
|
||||||
#include "libc/intrin/bits.h"
|
#include "libc/intrin/bits.h"
|
||||||
#include "libc/intrin/strace.internal.h"
|
#include "libc/intrin/strace.internal.h"
|
||||||
#include "libc/macros.internal.h"
|
#include "libc/macros.internal.h"
|
||||||
|
@ -46,38 +49,37 @@
|
||||||
#include "libc/sysv/consts/sig.h"
|
#include "libc/sysv/consts/sig.h"
|
||||||
#include "libc/sysv/errfuns.h"
|
#include "libc/sysv/errfuns.h"
|
||||||
#include "libc/thread/posixthread.internal.h"
|
#include "libc/thread/posixthread.internal.h"
|
||||||
|
#include "libc/thread/tls.h"
|
||||||
|
|
||||||
#ifdef __x86_64__
|
#ifdef __x86_64__
|
||||||
|
|
||||||
/*
|
// Polls on the New Technology.
|
||||||
* Polls on the New Technology.
|
//
|
||||||
*
|
// This function is used to implement poll() and select(). You may poll
|
||||||
* This function is used to implement poll() and select(). You may poll
|
// on both sockets and files at the same time. We also poll for signals
|
||||||
* on both sockets and files at the same time. We also poll for signals
|
// while poll is polling.
|
||||||
* while poll is polling.
|
textwindows int sys_poll_nt(struct pollfd *fds, uint64_t nfds, uint32_t *ms,
|
||||||
*/
|
|
||||||
textwindows int sys_poll_nt(struct pollfd *fds, uint64_t nfds, uint64_t *ms,
|
|
||||||
const sigset_t *sigmask) {
|
const sigset_t *sigmask) {
|
||||||
bool ok;
|
bool ok;
|
||||||
|
uint64_t m;
|
||||||
|
bool interrupted;
|
||||||
sigset_t oldmask;
|
sigset_t oldmask;
|
||||||
uint32_t avail, cm;
|
uint32_t cm, avail, waitfor;
|
||||||
struct sys_pollfd_nt pipefds[8];
|
struct sys_pollfd_nt pipefds[8];
|
||||||
struct sys_pollfd_nt sockfds[64];
|
struct sys_pollfd_nt sockfds[64];
|
||||||
int pipeindices[ARRAYLEN(pipefds)];
|
int pipeindices[ARRAYLEN(pipefds)];
|
||||||
int sockindices[ARRAYLEN(sockfds)];
|
int sockindices[ARRAYLEN(sockfds)];
|
||||||
int i, rc, sn, pn, gotinvals, gotpipes, gotsocks, waitfor;
|
int i, rc, sn, pn, gotinvals, gotpipes, gotsocks;
|
||||||
|
|
||||||
// check for interrupts early before doing work
|
#if IsModeDbg()
|
||||||
if (sigmask) {
|
struct timespec noearlier =
|
||||||
__sig_mask(SIG_SETMASK, sigmask, &oldmask);
|
timespec_add(timespec_real(), timespec_frommillis(ms ? *ms : -1u));
|
||||||
}
|
#endif
|
||||||
if ((rc = _check_interrupts(0))) {
|
|
||||||
goto ReturnPath;
|
|
||||||
}
|
|
||||||
|
|
||||||
// do the planning
|
// do the planning
|
||||||
// we need to read static variables
|
// we need to read static variables
|
||||||
// we might need to spawn threads and open pipes
|
// we might need to spawn threads and open pipes
|
||||||
|
m = atomic_exchange(&__get_tls()->tib_sigmask, -1);
|
||||||
__fds_lock();
|
__fds_lock();
|
||||||
for (gotinvals = rc = sn = pn = i = 0; i < nfds; ++i) {
|
for (gotinvals = rc = sn = pn = i = 0; i < nfds; ++i) {
|
||||||
if (fds[i].fd < 0) continue;
|
if (fds[i].fd < 0) continue;
|
||||||
|
@ -125,9 +127,10 @@ textwindows int sys_poll_nt(struct pollfd *fds, uint64_t nfds, uint64_t *ms,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
__fds_unlock();
|
__fds_unlock();
|
||||||
|
atomic_store_explicit(&__get_tls()->tib_sigmask, m, memory_order_release);
|
||||||
if (rc) {
|
if (rc) {
|
||||||
// failed to create a polling solution
|
// failed to create a polling solution
|
||||||
goto ReturnPath;
|
goto Finished;
|
||||||
}
|
}
|
||||||
|
|
||||||
// perform the i/o and sleeping and looping
|
// perform the i/o and sleeping and looping
|
||||||
|
@ -152,17 +155,8 @@ textwindows int sys_poll_nt(struct pollfd *fds, uint64_t nfds, uint64_t *ms,
|
||||||
pipefds[i].revents |= POLLERR;
|
pipefds[i].revents |= POLLERR;
|
||||||
}
|
}
|
||||||
} else if (GetConsoleMode(pipefds[i].handle, &cm)) {
|
} else if (GetConsoleMode(pipefds[i].handle, &cm)) {
|
||||||
int e = errno;
|
if (CountConsoleInputBytes(pipefds[i].handle)) {
|
||||||
avail = CountConsoleInputBytes(pipefds[i].handle);
|
|
||||||
if (avail > 0) {
|
|
||||||
pipefds[i].revents |= POLLIN;
|
pipefds[i].revents |= POLLIN;
|
||||||
} else if (avail == -1u) {
|
|
||||||
if (errno == ENODATA) {
|
|
||||||
pipefds[i].revents |= POLLIN;
|
|
||||||
} else {
|
|
||||||
pipefds[i].revents |= POLLERR;
|
|
||||||
}
|
|
||||||
errno = e;
|
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// we have no way of polling if a non-socket is readable yet
|
// we have no way of polling if a non-socket is readable yet
|
||||||
|
@ -176,42 +170,35 @@ textwindows int sys_poll_nt(struct pollfd *fds, uint64_t nfds, uint64_t *ms,
|
||||||
}
|
}
|
||||||
// if we haven't found any good results yet then here we
|
// if we haven't found any good results yet then here we
|
||||||
// compute a small time slice we don't mind sleeping for
|
// compute a small time slice we don't mind sleeping for
|
||||||
waitfor = gotinvals || gotpipes ? 0 : MIN(__SIG_POLL_INTERVAL_MS, *ms);
|
|
||||||
if (sn) {
|
if (sn) {
|
||||||
#if _NTTRACE
|
|
||||||
POLLTRACE("WSAPoll(%p, %u, %'d) out of %'lu", sockfds, sn, waitfor, *ms);
|
|
||||||
#endif
|
|
||||||
if ((gotsocks = WSAPoll(sockfds, sn, 0)) == -1) {
|
if ((gotsocks = WSAPoll(sockfds, sn, 0)) == -1) {
|
||||||
rc = __winsockerr();
|
return __winsockerr();
|
||||||
goto ReturnPath;
|
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
gotsocks = 0;
|
gotsocks = 0;
|
||||||
}
|
}
|
||||||
|
waitfor = MIN(__SIG_POLL_INTERVAL_MS, *ms);
|
||||||
if (!gotinvals && !gotsocks && !gotpipes && waitfor) {
|
if (!gotinvals && !gotsocks && !gotpipes && waitfor) {
|
||||||
POLLTRACE("sleeping for %'d out of %'lu ms", waitfor, *ms);
|
POLLTRACE("poll() sleeping for %'d out of %'u ms", waitfor, *ms);
|
||||||
struct PosixThread *pt = _pthread_self();
|
struct PosixThread *pt = _pthread_self();
|
||||||
pt->abort_errno = 0;
|
pt->abort_errno = 0;
|
||||||
pt->pt_flags |= PT_INSEMAPHORE;
|
if (sigmask) __sig_mask(SIG_SETMASK, sigmask, &oldmask);
|
||||||
WaitForSingleObject(pt->semaphore, waitfor);
|
interrupted = _check_interrupts(0) || __pause_thread(waitfor);
|
||||||
pt->pt_flags &= ~PT_INSEMAPHORE;
|
if (sigmask) __sig_mask(SIG_SETMASK, &oldmask, 0);
|
||||||
if (pt->abort_errno) {
|
if (interrupted) return -1;
|
||||||
errno = pt->abort_errno;
|
if (*ms != -1u) {
|
||||||
rc = -1;
|
if (waitfor < *ms) {
|
||||||
goto ReturnPath;
|
*ms -= waitfor;
|
||||||
|
} else {
|
||||||
|
*ms = 0;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
*ms -= waitfor; // todo: make more resilient
|
|
||||||
}
|
}
|
||||||
// we gave all the sockets and all the named pipes a shot
|
// 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 we found anything at all then it's time to end work
|
||||||
if (gotinvals || gotpipes || gotsocks || *ms <= 0) {
|
if (gotinvals || gotpipes || gotsocks || !*ms) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
// otherwise loop limitlessly for timeout to elapse while
|
|
||||||
// checking for signal delivery interrupts, along the way
|
|
||||||
if ((rc = _check_interrupts(0))) {
|
|
||||||
goto ReturnPath;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// the system call is going to succeed
|
// the system call is going to succeed
|
||||||
|
@ -233,10 +220,16 @@ textwindows int sys_poll_nt(struct pollfd *fds, uint64_t nfds, uint64_t *ms,
|
||||||
// and finally return
|
// and finally return
|
||||||
rc = gotinvals + gotpipes + gotsocks;
|
rc = gotinvals + gotpipes + gotsocks;
|
||||||
|
|
||||||
ReturnPath:
|
Finished:
|
||||||
if (sigmask) {
|
|
||||||
__sig_mask(SIG_SETMASK, &oldmask, 0);
|
#if IsModeDbg()
|
||||||
|
struct timespec ended = timespec_real();
|
||||||
|
if (!rc && timespec_cmp(ended, noearlier) < 0) {
|
||||||
|
STRACE("poll() ended %'ld ns too soon!",
|
||||||
|
timespec_tonanos(timespec_sub(noearlier, ended)));
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -68,7 +68,6 @@
|
||||||
int poll(struct pollfd *fds, size_t nfds, int timeout_ms) {
|
int poll(struct pollfd *fds, size_t nfds, int timeout_ms) {
|
||||||
int rc;
|
int rc;
|
||||||
size_t n;
|
size_t n;
|
||||||
uint64_t millis;
|
|
||||||
BEGIN_CANCELLATION_POINT;
|
BEGIN_CANCELLATION_POINT;
|
||||||
|
|
||||||
if (IsAsan() &&
|
if (IsAsan() &&
|
||||||
|
@ -81,9 +80,9 @@ int poll(struct pollfd *fds, size_t nfds, int timeout_ms) {
|
||||||
rc = sys_poll_metal(fds, nfds, timeout_ms);
|
rc = sys_poll_metal(fds, nfds, timeout_ms);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
millis = timeout_ms;
|
|
||||||
BEGIN_BLOCKING_OPERATION;
|
BEGIN_BLOCKING_OPERATION;
|
||||||
rc = sys_poll_nt(fds, nfds, &millis, 0);
|
uint32_t ms = timeout_ms >= 0 ? timeout_ms : -1u;
|
||||||
|
rc = sys_poll_nt(fds, nfds, &ms, 0);
|
||||||
END_BLOCKING_OPERATION;
|
END_BLOCKING_OPERATION;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -64,7 +64,6 @@ int ppoll(struct pollfd *fds, size_t nfds, const struct timespec *timeout,
|
||||||
const sigset_t *sigmask) {
|
const sigset_t *sigmask) {
|
||||||
size_t n;
|
size_t n;
|
||||||
int e, rc;
|
int e, rc;
|
||||||
uint64_t millis;
|
|
||||||
sigset_t oldmask;
|
sigset_t oldmask;
|
||||||
struct timespec ts, *tsp;
|
struct timespec ts, *tsp;
|
||||||
BEGIN_CANCELLATION_POINT;
|
BEGIN_CANCELLATION_POINT;
|
||||||
|
@ -84,22 +83,24 @@ int ppoll(struct pollfd *fds, size_t nfds, const struct timespec *timeout,
|
||||||
}
|
}
|
||||||
rc = sys_ppoll(fds, nfds, tsp, sigmask, 8);
|
rc = sys_ppoll(fds, nfds, tsp, sigmask, 8);
|
||||||
if (rc == -1 && errno == ENOSYS) {
|
if (rc == -1 && errno == ENOSYS) {
|
||||||
|
int ms;
|
||||||
errno = e;
|
errno = e;
|
||||||
if (!timeout ||
|
if (!timeout || ckd_add(&ms, timeout->tv_sec,
|
||||||
ckd_add(&millis, timeout->tv_sec, timeout->tv_nsec / 1000000)) {
|
(timeout->tv_nsec + 999999) / 1000000)) {
|
||||||
millis = -1;
|
ms = -1;
|
||||||
}
|
}
|
||||||
if (sigmask) sys_sigprocmask(SIG_SETMASK, sigmask, &oldmask);
|
if (sigmask) sys_sigprocmask(SIG_SETMASK, sigmask, &oldmask);
|
||||||
rc = poll(fds, nfds, millis);
|
rc = poll(fds, nfds, ms);
|
||||||
if (sigmask) sys_sigprocmask(SIG_SETMASK, &oldmask, 0);
|
if (sigmask) sys_sigprocmask(SIG_SETMASK, &oldmask, 0);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
uint32_t ms;
|
||||||
if (!timeout ||
|
if (!timeout ||
|
||||||
ckd_add(&millis, timeout->tv_sec, timeout->tv_nsec / 1000000)) {
|
ckd_add(&ms, timeout->tv_sec, (timeout->tv_nsec + 999999) / 1000000)) {
|
||||||
millis = -1;
|
ms = -1u;
|
||||||
}
|
}
|
||||||
BEGIN_BLOCKING_OPERATION;
|
BEGIN_BLOCKING_OPERATION;
|
||||||
rc = sys_poll_nt(fds, nfds, &millis, sigmask);
|
rc = sys_poll_nt(fds, nfds, &ms, sigmask);
|
||||||
END_BLOCKING_OPERATION;
|
END_BLOCKING_OPERATION;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -16,20 +16,18 @@
|
||||||
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
||||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||||
#include "libc/calls/calls.h"
|
|
||||||
#include "libc/calls/console.internal.h"
|
|
||||||
#include "libc/calls/internal.h"
|
#include "libc/calls/internal.h"
|
||||||
#include "libc/calls/sig.internal.h"
|
#include "libc/calls/sig.internal.h"
|
||||||
#include "libc/calls/state.internal.h"
|
|
||||||
#include "libc/calls/struct/fd.internal.h"
|
#include "libc/calls/struct/fd.internal.h"
|
||||||
#include "libc/calls/struct/iovec.h"
|
#include "libc/calls/struct/iovec.h"
|
||||||
#include "libc/calls/struct/iovec.internal.h"
|
|
||||||
#include "libc/calls/struct/timespec.h"
|
|
||||||
#include "libc/calls/syscall_support-nt.internal.h"
|
#include "libc/calls/syscall_support-nt.internal.h"
|
||||||
#include "libc/calls/wincrash.internal.h"
|
#include "libc/calls/ttydefaults.h"
|
||||||
#include "libc/errno.h"
|
#include "libc/errno.h"
|
||||||
#include "libc/fmt/itoa.h"
|
#include "libc/fmt/itoa.h"
|
||||||
|
#include "libc/intrin/atomic.h"
|
||||||
|
#include "libc/intrin/dll.h"
|
||||||
#include "libc/intrin/nomultics.internal.h"
|
#include "libc/intrin/nomultics.internal.h"
|
||||||
|
#include "libc/intrin/strace.internal.h"
|
||||||
#include "libc/intrin/weaken.h"
|
#include "libc/intrin/weaken.h"
|
||||||
#include "libc/macros.internal.h"
|
#include "libc/macros.internal.h"
|
||||||
#include "libc/nt/console.h"
|
#include "libc/nt/console.h"
|
||||||
|
@ -39,95 +37,95 @@
|
||||||
#include "libc/nt/errors.h"
|
#include "libc/nt/errors.h"
|
||||||
#include "libc/nt/events.h"
|
#include "libc/nt/events.h"
|
||||||
#include "libc/nt/files.h"
|
#include "libc/nt/files.h"
|
||||||
#include "libc/nt/ipc.h"
|
|
||||||
#include "libc/nt/runtime.h"
|
#include "libc/nt/runtime.h"
|
||||||
#include "libc/nt/struct/inputrecord.h"
|
#include "libc/nt/struct/inputrecord.h"
|
||||||
#include "libc/nt/struct/overlapped.h"
|
|
||||||
#include "libc/nt/synchronization.h"
|
#include "libc/nt/synchronization.h"
|
||||||
#include "libc/nt/thread.h"
|
#include "libc/nt/thread.h"
|
||||||
#include "libc/nt/thunk/msabi.h"
|
#include "libc/nt/thunk/msabi.h"
|
||||||
#include "libc/str/str.h"
|
#include "libc/str/str.h"
|
||||||
#include "libc/str/utf16.h"
|
#include "libc/str/utf16.h"
|
||||||
#include "libc/sysv/consts/o.h"
|
#include "libc/sysv/consts/o.h"
|
||||||
#include "libc/sysv/consts/sa.h"
|
|
||||||
#include "libc/sysv/consts/sicode.h"
|
|
||||||
#include "libc/sysv/consts/sig.h"
|
#include "libc/sysv/consts/sig.h"
|
||||||
#include "libc/sysv/consts/termios.h"
|
#include "libc/sysv/consts/termios.h"
|
||||||
#include "libc/sysv/errfuns.h"
|
#include "libc/sysv/errfuns.h"
|
||||||
#include "libc/thread/posixthread.internal.h"
|
#include "libc/thread/thread.h"
|
||||||
#include "libc/thread/tls.h"
|
#include "libc/thread/tls.h"
|
||||||
|
|
||||||
#ifdef __x86_64__
|
#ifdef __x86_64__
|
||||||
|
|
||||||
__msabi extern typeof(CloseHandle) *const __imp_CloseHandle;
|
__msabi extern typeof(CloseHandle) *const __imp_CloseHandle;
|
||||||
|
|
||||||
static const struct {
|
static const struct {
|
||||||
uint16_t vk;
|
int vk;
|
||||||
uint32_t normal_str;
|
int normal_str;
|
||||||
uint32_t shift_str;
|
int shift_str;
|
||||||
uint32_t ctrl_str;
|
int ctrl_str;
|
||||||
uint32_t shift_ctrl_str;
|
int shift_ctrl_str;
|
||||||
} kVirtualKey[] = {
|
} kVirtualKey[] = {
|
||||||
#define SW(s) W4(s "\0\0")
|
#define S(s) W(s "\0\0")
|
||||||
#define W4(s) (s[3] + 0u) << 24 | s[2] << 16 | s[1] << 8 | s[0]
|
#define W(s) (s[3] << 24 | s[2] << 16 | s[1] << 8 | s[0])
|
||||||
#define VK(vk, normal_str, shift_str, ctrl_str, shift_ctrl_str) \
|
{kNtVkUp, S("A"), S("1;2A"), S("1;5A"), S("1;6A")},
|
||||||
{ vk, SW(normal_str), SW(shift_str), SW(ctrl_str), SW(shift_ctrl_str) }
|
{kNtVkDown, S("B"), S("1;2B"), S("1;5B"), S("1;6B")},
|
||||||
VK(kNtVkInsert, "2~", "2;2~", "2;5~", "2;6~"),
|
{kNtVkLeft, S("D"), S("1;2D"), S("1;5D"), S("1;6D")},
|
||||||
VK(kNtVkEnd, "4~", "4;2~", "4;5~", "4;6~"),
|
{kNtVkRight, S("C"), S("1;2C"), S("1;5C"), S("1;6C")},
|
||||||
VK(kNtVkDown, "B", "1;2B", "1;5B", "1;6B"),
|
{kNtVkInsert, S("2~"), S("2;2~"), S("2;5~"), S("2;6~")},
|
||||||
VK(kNtVkNext, "6~", "6;2~", "6;5~", "6;6~"),
|
{kNtVkDelete, S("3~"), S("3;2~"), S("3;5~"), S("3;6~")},
|
||||||
VK(kNtVkLeft, "D", "1;2D", "1;5D", "1;6D"),
|
{kNtVkHome, S("H"), S("1;2H"), S("1;5H"), S("1;6H")},
|
||||||
VK(kNtVkClear, "G", "1;2G", "1;5G", "1;6G"),
|
{kNtVkEnd, S("F"), S("1;2F"), S("1;5F"), S("1;6F")},
|
||||||
VK(kNtVkRight, "C", "1;2C", "1;5C", "1;6C"),
|
{kNtVkPrior, S("5~"), S("5;2~"), S("5;5~"), S("5;6~")},
|
||||||
VK(kNtVkUp, "A", "1;2A", "1;5A", "1;6A"),
|
{kNtVkNext, S("6~"), S("6;2~"), S("6;5~"), S("6;6~")},
|
||||||
VK(kNtVkHome, "1~", "1;2~", "1;5~", "1;6~"),
|
{kNtVkF1, -S("OP"), S("1;2P"), S("11^"), S("1;6P")},
|
||||||
VK(kNtVkPrior, "5~", "5;2~", "5;5~", "5;6~"),
|
{kNtVkF2, -S("OQ"), S("1;2Q"), S("12^"), S("1;6Q")},
|
||||||
VK(kNtVkDelete, "3~", "3;2~", "3;5~", "3;6~"),
|
{kNtVkF3, -S("OR"), S("1;2R"), S("13^"), S("1;6R")},
|
||||||
VK(kNtVkNumpad0, "2~", "2;2~", "2;5~", "2;6~"),
|
{kNtVkF4, -S("OS"), S("1;2S"), S("14^"), S("1;6S")},
|
||||||
VK(kNtVkNumpad1, "4~", "4;2~", "4;5~", "4;6~"),
|
{kNtVkF5, S("15~"), S("28~"), S("15^"), S("28^")},
|
||||||
VK(kNtVkNumpad2, "B", "1;2B", "1;5B", "1;6B"),
|
{kNtVkF6, S("17~"), S("29~"), S("17^"), S("29^")},
|
||||||
VK(kNtVkNumpad3, "6~", "6;2~", "6;5~", "6;6~"),
|
{kNtVkF7, S("18~"), S("31~"), S("18^"), S("31^")},
|
||||||
VK(kNtVkNumpad4, "D", "1;2D", "1;5D", "1;6D"),
|
{kNtVkF8, S("19~"), S("32~"), S("19^"), S("32^")},
|
||||||
VK(kNtVkNumpad5, "G", "1;2G", "1;5G", "1;6G"),
|
{kNtVkF9, S("20~"), S("33~"), S("20^"), S("33^")},
|
||||||
VK(kNtVkNumpad6, "C", "1;2C", "1;5C", "1;6C"),
|
{kNtVkF10, S("21~"), S("34~"), S("21^"), S("34^")},
|
||||||
VK(kNtVkNumpad7, "A", "1;2A", "1;5A", "1;6A"),
|
{kNtVkF11, S("23~"), S("23$"), S("23^"), S("23@")},
|
||||||
VK(kNtVkNumpad8, "1~", "1;2~", "1;5~", "1;6~"),
|
{kNtVkF12, S("24~"), S("24$"), S("24^"), S("24@")},
|
||||||
VK(kNtVkNumpad9, "5~", "5;2~", "5;5~", "5;6~"),
|
#undef W
|
||||||
VK(kNtVkDecimal, "3~", "3;2~", "3;5~", "3;6~"),
|
#undef S
|
||||||
VK(kNtVkF1, "[A", "23~", "11^", "23^"),
|
|
||||||
VK(kNtVkF2, "[B", "24~", "12^", "24^"),
|
|
||||||
VK(kNtVkF3, "[C", "25~", "13^", "25^"),
|
|
||||||
VK(kNtVkF4, "[D", "26~", "14^", "26^"),
|
|
||||||
VK(kNtVkF5, "[E", "28~", "15^", "28^"),
|
|
||||||
VK(kNtVkF6, "17~", "29~", "17^", "29^"),
|
|
||||||
VK(kNtVkF7, "18~", "31~", "18^", "31^"),
|
|
||||||
VK(kNtVkF8, "19~", "32~", "19^", "32^"),
|
|
||||||
VK(kNtVkF9, "20~", "33~", "20^", "33^"),
|
|
||||||
VK(kNtVkF10, "21~", "34~", "21^", "34^"),
|
|
||||||
VK(kNtVkF11, "23~", "23$", "23^", "23@"),
|
|
||||||
VK(kNtVkF12, "24~", "24$", "24^", "24@"),
|
|
||||||
#undef VK
|
|
||||||
#undef W4
|
|
||||||
#undef SW
|
|
||||||
};
|
};
|
||||||
|
|
||||||
static textwindows int ProcessSignal(int sig, struct Fd *f) {
|
#define KEYSTROKE_CONTAINER(e) DLL_CONTAINER(struct Keystroke, elem, e)
|
||||||
if (f) {
|
|
||||||
if (_weaken(__sig_raise)) {
|
struct Keystroke {
|
||||||
pthread_mutex_unlock(&f->lock);
|
char buf[32];
|
||||||
_weaken(__sig_raise)(sig, SI_KERNEL);
|
unsigned buflen;
|
||||||
pthread_mutex_lock(&f->lock);
|
struct Dll elem;
|
||||||
if (!(__sighandflags[sig] & SA_RESTART)) {
|
};
|
||||||
return eintr();
|
|
||||||
}
|
struct Keystrokes {
|
||||||
} else if (sig != SIGWINCH) {
|
struct Dll *list;
|
||||||
TerminateThisProcess(sig);
|
struct Dll *free;
|
||||||
}
|
bool end_of_file;
|
||||||
}
|
uint16_t utf16hs;
|
||||||
return 0;
|
unsigned allocated;
|
||||||
|
pthread_mutex_t lock;
|
||||||
|
struct Keystroke pool[32];
|
||||||
|
};
|
||||||
|
|
||||||
|
static struct Keystrokes __keystroke;
|
||||||
|
|
||||||
|
static textwindows void LockKeystrokes(void) {
|
||||||
|
pthread_mutex_lock(&__keystroke.lock);
|
||||||
}
|
}
|
||||||
|
|
||||||
static textwindows uint32_t GetVirtualKey(uint16_t vk, bool shift, bool ctrl) {
|
static textwindows void UnlockKeystrokes(void) {
|
||||||
|
pthread_mutex_unlock(&__keystroke.lock);
|
||||||
|
}
|
||||||
|
|
||||||
|
static textwindows uint64_t BlockSignals(void) {
|
||||||
|
return atomic_exchange(&__get_tls()->tib_sigmask, -1);
|
||||||
|
}
|
||||||
|
|
||||||
|
static textwindows void UnblockSignals(uint64_t mask) {
|
||||||
|
atomic_store_explicit(&__get_tls()->tib_sigmask, mask, memory_order_release);
|
||||||
|
}
|
||||||
|
|
||||||
|
static textwindows int GetVirtualKey(uint16_t vk, bool shift, bool ctrl) {
|
||||||
for (int i = 0; i < ARRAYLEN(kVirtualKey); ++i) {
|
for (int i = 0; i < ARRAYLEN(kVirtualKey); ++i) {
|
||||||
if (kVirtualKey[i].vk == vk) {
|
if (kVirtualKey[i].vk == vk) {
|
||||||
if (shift && ctrl) {
|
if (shift && ctrl) {
|
||||||
|
@ -144,33 +142,7 @@ static textwindows uint32_t GetVirtualKey(uint16_t vk, bool shift, bool ctrl) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Manual CMD.EXE echoing for when !ICANON && ECHO is the case.
|
static textwindows int ProcessKeyEvent(const struct NtInputRecord *r, char *p) {
|
||||||
static textwindows void EchoTerminalInput(struct Fd *f, char *p, size_t n) {
|
|
||||||
int64_t hOutput;
|
|
||||||
if (f->kind == kFdConsole) {
|
|
||||||
hOutput = f->extra;
|
|
||||||
} else {
|
|
||||||
hOutput = g_fds.p[1].handle;
|
|
||||||
}
|
|
||||||
if (__ttymagic & kFdTtyEchoRaw) {
|
|
||||||
WriteFile(hOutput, p, n, 0, 0);
|
|
||||||
} else {
|
|
||||||
size_t i;
|
|
||||||
for (i = 0; i < n; ++i) {
|
|
||||||
if (isascii(p[i]) && iscntrl(p[i]) && p[i] != '\n' && p[i] != '\t') {
|
|
||||||
char ctl[2];
|
|
||||||
ctl[0] = '^';
|
|
||||||
ctl[1] = p[i] ^ 0100;
|
|
||||||
WriteFile(hOutput, ctl, 2, 0, 0);
|
|
||||||
} else {
|
|
||||||
WriteFile(hOutput, p + i, 1, 0, 0);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static textwindows int ProcessKeyEvent(const struct NtInputRecord *r, char *p,
|
|
||||||
uint16_t *utf16hs, struct Fd *f) {
|
|
||||||
|
|
||||||
uint16_t c = r->Event.KeyEvent.uChar.UnicodeChar;
|
uint16_t c = r->Event.KeyEvent.uChar.UnicodeChar;
|
||||||
uint16_t vk = r->Event.KeyEvent.wVirtualKeyCode;
|
uint16_t vk = r->Event.KeyEvent.wVirtualKeyCode;
|
||||||
|
@ -181,23 +153,10 @@ static textwindows int ProcessKeyEvent(const struct NtInputRecord *r, char *p,
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
// ignore numpad being used to compose a character
|
|
||||||
if ((cks & kNtLeftAltPressed) && !(cks & kNtEnhancedKey) &&
|
|
||||||
(vk == kNtVkInsert || vk == kNtVkEnd || vk == kNtVkDown ||
|
|
||||||
vk == kNtVkNext || vk == kNtVkLeft || vk == kNtVkClear ||
|
|
||||||
vk == kNtVkRight || vk == kNtVkHome || vk == kNtVkUp ||
|
|
||||||
vk == kNtVkPrior || vk == kNtVkNumpad0 || vk == kNtVkNumpad1 ||
|
|
||||||
vk == kNtVkNumpad2 || vk == kNtVkNumpad3 || vk == kNtVkNumpad4 ||
|
|
||||||
vk == kNtVkNumpad5 || vk == kNtVkNumpad6 || vk == kNtVkNumpad7 ||
|
|
||||||
vk == kNtVkNumpad8 || vk == kNtVkNumpad9)) {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
int n = 0;
|
|
||||||
|
|
||||||
// process virtual keys
|
// process virtual keys
|
||||||
|
int n = 0;
|
||||||
if (!c) {
|
if (!c) {
|
||||||
uint32_t w;
|
int w;
|
||||||
w = GetVirtualKey(vk, !!(cks & kNtShiftPressed),
|
w = GetVirtualKey(vk, !!(cks & kNtShiftPressed),
|
||||||
!!(cks & (kNtLeftCtrlPressed | kNtRightCtrlPressed)));
|
!!(cks & (kNtLeftCtrlPressed | kNtRightCtrlPressed)));
|
||||||
if (!w) return 0;
|
if (!w) return 0;
|
||||||
|
@ -205,7 +164,11 @@ static textwindows int ProcessKeyEvent(const struct NtInputRecord *r, char *p,
|
||||||
if (cks & (kNtLeftAltPressed | kNtRightAltPressed)) {
|
if (cks & (kNtLeftAltPressed | kNtRightAltPressed)) {
|
||||||
p[n++] = 033;
|
p[n++] = 033;
|
||||||
}
|
}
|
||||||
p[n++] = '[';
|
if (w > 0) {
|
||||||
|
p[n++] = '[';
|
||||||
|
} else {
|
||||||
|
w = -w;
|
||||||
|
}
|
||||||
do p[n++] = w;
|
do p[n++] = w;
|
||||||
while ((w >>= 8));
|
while ((w >>= 8));
|
||||||
return n;
|
return n;
|
||||||
|
@ -213,11 +176,11 @@ static textwindows int ProcessKeyEvent(const struct NtInputRecord *r, char *p,
|
||||||
|
|
||||||
// translate utf-16 into utf-32
|
// translate utf-16 into utf-32
|
||||||
if (IsHighSurrogate(c)) {
|
if (IsHighSurrogate(c)) {
|
||||||
*utf16hs = c;
|
__keystroke.utf16hs = c;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
if (IsLowSurrogate(c)) {
|
if (IsLowSurrogate(c)) {
|
||||||
c = MergeUtf16(*utf16hs, c);
|
c = MergeUtf16(__keystroke.utf16hs, c);
|
||||||
}
|
}
|
||||||
|
|
||||||
// enter sends \r in a raw terminals
|
// enter sends \r in a raw terminals
|
||||||
|
@ -240,15 +203,21 @@ static textwindows int ProcessKeyEvent(const struct NtInputRecord *r, char *p,
|
||||||
// handle ctrl-c and ctrl-\, which tcsetattr() is able to remap
|
// handle ctrl-c and ctrl-\, which tcsetattr() is able to remap
|
||||||
if (!(__ttymagic & kFdTtyNoIsigs)) {
|
if (!(__ttymagic & kFdTtyNoIsigs)) {
|
||||||
if (c == __vintr && __vintr != _POSIX_VDISABLE) {
|
if (c == __vintr && __vintr != _POSIX_VDISABLE) {
|
||||||
return ProcessSignal(SIGINT, f);
|
STRACE("encountered CTRL(%#c) c_cc[VINTR] will raise SIGINT", CTRL(c));
|
||||||
|
__get_tls()->tib_sigpending |= 1ull << (SIGINT - 1);
|
||||||
|
return 0;
|
||||||
} else if (c == __vquit && __vquit != _POSIX_VDISABLE) {
|
} else if (c == __vquit && __vquit != _POSIX_VDISABLE) {
|
||||||
return ProcessSignal(SIGQUIT, f);
|
STRACE("encountered CTRL(%#c) c_cc[VQUITR] will raise SIGQUIT", CTRL(c));
|
||||||
|
__get_tls()->tib_sigpending |= 1ull << (SIGQUIT - 1);
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// handle ctrl-d the end of file keystroke
|
// handle ctrl-d the end of file keystroke
|
||||||
if (c == __veof && __veof != _POSIX_VDISABLE) {
|
if (c == __veof && __veof != _POSIX_VDISABLE) {
|
||||||
return enodata();
|
STRACE("encountered CTRL(%#c) c_cc[VEOF] closing console input", CTRL(c));
|
||||||
|
__keystroke.end_of_file = true;
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
// insert esc prefix when alt is held
|
// insert esc prefix when alt is held
|
||||||
|
@ -269,11 +238,11 @@ static textwindows int ProcessKeyEvent(const struct NtInputRecord *r, char *p,
|
||||||
// - write(1, "\e[?1000;1002;1015;1006h") to enable
|
// - write(1, "\e[?1000;1002;1015;1006h") to enable
|
||||||
// - write(1, "\e[?1000;1002;1015;1006l") to disable
|
// - write(1, "\e[?1000;1002;1015;1006l") to disable
|
||||||
// See o//examples/ttyinfo.com and o//tool/viz/life.com
|
// See o//examples/ttyinfo.com and o//tool/viz/life.com
|
||||||
static textwindows int ProcessMouseEvent(const struct NtInputRecord *r, char *b,
|
static textwindows int ProcessMouseEvent(const struct NtInputRecord *r,
|
||||||
struct Fd *f) {
|
char *b) {
|
||||||
int e = 0;
|
int e = 0;
|
||||||
char *p = b;
|
char *p = b;
|
||||||
uint32_t currentbs = f ? f->mousebuttons : 0;
|
uint32_t currentbs = __mousebuttons;
|
||||||
uint32_t ev = r->Event.MouseEvent.dwEventFlags;
|
uint32_t ev = r->Event.MouseEvent.dwEventFlags;
|
||||||
uint32_t bs = r->Event.MouseEvent.dwButtonState;
|
uint32_t bs = r->Event.MouseEvent.dwButtonState;
|
||||||
ev &= kNtMouseMoved | kNtMouseWheeled;
|
ev &= kNtMouseMoved | kNtMouseWheeled;
|
||||||
|
@ -320,98 +289,195 @@ static textwindows int ProcessMouseEvent(const struct NtInputRecord *r, char *b,
|
||||||
} else {
|
} else {
|
||||||
*p++ = 'M'; // down
|
*p++ = 'M'; // down
|
||||||
}
|
}
|
||||||
if (f) {
|
__mousebuttons = bs;
|
||||||
f->mousebuttons = bs;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return p - b;
|
return p - b;
|
||||||
}
|
}
|
||||||
|
|
||||||
textwindows int ConvertConsoleInputToAnsi(const struct NtInputRecord *r,
|
static textwindows int ConvertConsoleInputToAnsi(const struct NtInputRecord *r,
|
||||||
char p[hasatleast 32],
|
char p[hasatleast 32]) {
|
||||||
uint16_t *utf16hs, struct Fd *f) {
|
|
||||||
switch (r->EventType) {
|
switch (r->EventType) {
|
||||||
case kNtKeyEvent:
|
case kNtKeyEvent:
|
||||||
return ProcessKeyEvent(r, p, utf16hs, f);
|
return ProcessKeyEvent(r, p);
|
||||||
case kNtMouseEvent:
|
case kNtMouseEvent:
|
||||||
return ProcessMouseEvent(r, p, f);
|
return ProcessMouseEvent(r, p);
|
||||||
case kNtWindowBufferSizeEvent:
|
case kNtWindowBufferSizeEvent:
|
||||||
return ProcessSignal(SIGWINCH, f);
|
STRACE("detected console resize will raise SIGWINCH");
|
||||||
|
__get_tls()->tib_sigpending |= 1ull << (SIGWINCH - 1);
|
||||||
|
return 0;
|
||||||
default:
|
default:
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static textwindows ssize_t ReadFromWindowsConsole(struct Fd *f, void *data,
|
static textwindows struct Keystroke *NewKeystroke(void) {
|
||||||
size_t size) {
|
struct Dll *e;
|
||||||
ssize_t rc;
|
struct Keystroke *k = 0;
|
||||||
int e = errno;
|
int i, n = ARRAYLEN(__keystroke.pool);
|
||||||
uint16_t utf16hs = 0;
|
if (atomic_load_explicit(&__keystroke.allocated, memory_order_acquire) < n &&
|
||||||
pthread_mutex_lock(&f->lock);
|
(i = atomic_fetch_add(&__keystroke.allocated, 1)) < n) {
|
||||||
for (;;) {
|
k = __keystroke.pool + i;
|
||||||
if (f->eoftty) {
|
} else if ((e = dll_first(__keystroke.free))) {
|
||||||
rc = 0;
|
k = KEYSTROKE_CONTAINER(e);
|
||||||
break;
|
dll_remove(&__keystroke.free, &k->elem);
|
||||||
}
|
} else {
|
||||||
uint32_t got = MIN(size, f->buflen);
|
return 0;
|
||||||
uint32_t remain = f->buflen - got;
|
}
|
||||||
if (got) memcpy(data, f->buf, got);
|
bzero(k, sizeof(*k));
|
||||||
if (remain) memmove(f->buf, f->buf + got, remain);
|
dll_init(&k->elem);
|
||||||
f->buflen = remain;
|
return k;
|
||||||
if (got) {
|
}
|
||||||
rc = got;
|
|
||||||
break;
|
static textwindows void IngestConsoleInputRecord(struct NtInputRecord *r) {
|
||||||
}
|
int len;
|
||||||
uint32_t events_available;
|
struct Keystroke *k;
|
||||||
if (!GetNumberOfConsoleInputEvents(f->handle, &events_available)) {
|
char buf[sizeof(k->buf)];
|
||||||
rc = __winerr();
|
if ((len = ConvertConsoleInputToAnsi(r, buf))) {
|
||||||
break;
|
if ((k = NewKeystroke())) {
|
||||||
}
|
memcpy(k->buf, buf, sizeof(k->buf));
|
||||||
if (events_available) {
|
k->buflen = len;
|
||||||
uint32_t n;
|
dll_make_last(&__keystroke.list, &k->elem);
|
||||||
struct NtInputRecord r;
|
|
||||||
if (!ReadConsoleInput(f->handle, &r, 1, &n)) {
|
|
||||||
rc = __winerr();
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
rc = ConvertConsoleInputToAnsi(&r, f->buf, &utf16hs, f);
|
|
||||||
if (rc == -1) {
|
|
||||||
if (errno == ENODATA) {
|
|
||||||
f->eoftty = true;
|
|
||||||
errno = e;
|
|
||||||
rc = 0;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
f->buflen = rc;
|
|
||||||
} else {
|
} else {
|
||||||
if (f->flags & O_NONBLOCK) {
|
STRACE("ran out of memory to hold keystroke %#.*s", len, buf);
|
||||||
rc = 0;
|
}
|
||||||
break;
|
}
|
||||||
}
|
}
|
||||||
uint32_t ms = __SIG_POLL_INTERVAL_MS;
|
|
||||||
if (__ttymagic & kFdTtyNoBlock) {
|
static textwindows void IngestConsoleInput(int64_t handle) {
|
||||||
if (!__vtime) {
|
uint32_t i, n;
|
||||||
rc = 0;
|
struct NtInputRecord records[16];
|
||||||
break;
|
if (!__keystroke.end_of_file) {
|
||||||
} else {
|
do {
|
||||||
ms = __vtime * 100;
|
if (GetNumberOfConsoleInputEvents(handle, &n)) {
|
||||||
|
if (n) {
|
||||||
|
n = MIN(ARRAYLEN(records), n);
|
||||||
|
if (ReadConsoleInput(handle, records, n, &n)) {
|
||||||
|
for (i = 0; i < n && !__keystroke.end_of_file; ++i) {
|
||||||
|
IngestConsoleInputRecord(records + i);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
STRACE("ReadConsoleInput failed w/ %d", GetLastError());
|
||||||
|
__keystroke.end_of_file = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
} else {
|
||||||
if ((rc = _check_interrupts(kSigOpRestartable))) {
|
STRACE("GetNumberOfConsoleInputRecords failed w/ %d", GetLastError());
|
||||||
|
__keystroke.end_of_file = true;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
struct PosixThread *pt = _pthread_self();
|
} while (n == ARRAYLEN(records));
|
||||||
pt->pt_flags |= PT_INSEMAPHORE;
|
}
|
||||||
WaitForSingleObject(pt->semaphore, ms);
|
}
|
||||||
pt->pt_flags &= ~PT_INSEMAPHORE;
|
|
||||||
if (pt->abort_errno == ECANCELED) {
|
textwindows int FlushConsoleInputBytes(int64_t handle) {
|
||||||
rc = ecanceled();
|
int rc;
|
||||||
break;
|
uint64_t m;
|
||||||
|
m = BlockSignals();
|
||||||
|
LockKeystrokes();
|
||||||
|
if (FlushConsoleInputBuffer(handle)) {
|
||||||
|
dll_make_first(&__keystroke.free, __keystroke.list);
|
||||||
|
__keystroke.list = 0;
|
||||||
|
rc = 0;
|
||||||
|
} else {
|
||||||
|
rc = __winerr();
|
||||||
|
}
|
||||||
|
UnlockKeystrokes();
|
||||||
|
UnblockSignals(m);
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
textwindows int CountConsoleInputBytes(int64_t handle) {
|
||||||
|
int count = 0;
|
||||||
|
struct Dll *e;
|
||||||
|
uint64_t m = BlockSignals();
|
||||||
|
LockKeystrokes();
|
||||||
|
IngestConsoleInput(handle);
|
||||||
|
for (e = dll_first(__keystroke.list); e; e = dll_next(__keystroke.list, e)) {
|
||||||
|
count += KEYSTROKE_CONTAINER(e)->buflen;
|
||||||
|
}
|
||||||
|
if (!count && __keystroke.end_of_file) {
|
||||||
|
count = -1;
|
||||||
|
}
|
||||||
|
UnlockKeystrokes();
|
||||||
|
UnblockSignals(m);
|
||||||
|
return count;
|
||||||
|
}
|
||||||
|
|
||||||
|
static textwindows bool DigestConsoleInput(void *data, size_t size, int *rc) {
|
||||||
|
struct Dll *e;
|
||||||
|
if ((e = dll_first(__keystroke.list))) {
|
||||||
|
struct Keystroke *k = KEYSTROKE_CONTAINER(e);
|
||||||
|
uint32_t got = MIN(size, k->buflen);
|
||||||
|
uint32_t remain = k->buflen - got;
|
||||||
|
if (got) memcpy(data, k->buf, got);
|
||||||
|
if (remain) memmove(k->buf, k->buf + got, remain);
|
||||||
|
if (!remain) {
|
||||||
|
dll_remove(&__keystroke.list, e);
|
||||||
|
dll_make_first(&__keystroke.free, e);
|
||||||
|
}
|
||||||
|
k->buflen = remain;
|
||||||
|
if (got) {
|
||||||
|
*rc = got;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
} else if (__keystroke.end_of_file) {
|
||||||
|
*rc = 0;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Manual CMD.EXE echoing for when !ICANON && ECHO is the case.
|
||||||
|
static textwindows void EchoTerminalInput(struct Fd *f, char *p, size_t n) {
|
||||||
|
int64_t hOutput;
|
||||||
|
if (f->kind == kFdConsole) {
|
||||||
|
hOutput = f->extra;
|
||||||
|
} else {
|
||||||
|
hOutput = g_fds.p[1].handle;
|
||||||
|
}
|
||||||
|
if (__ttymagic & kFdTtyEchoRaw) {
|
||||||
|
WriteFile(hOutput, p, n, 0, 0);
|
||||||
|
} else {
|
||||||
|
size_t i;
|
||||||
|
for (i = 0; i < n; ++i) {
|
||||||
|
if (isascii(p[i]) && iscntrl(p[i]) && p[i] != '\n' && p[i] != '\t') {
|
||||||
|
char ctl[2];
|
||||||
|
ctl[0] = '^';
|
||||||
|
ctl[1] = p[i] ^ 0100;
|
||||||
|
WriteFile(hOutput, ctl, 2, 0, 0);
|
||||||
|
} else {
|
||||||
|
WriteFile(hOutput, p + i, 1, 0, 0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
pthread_mutex_unlock(&f->lock);
|
}
|
||||||
|
|
||||||
|
static textwindows ssize_t ReadFromWindowsConsole(struct Fd *f, void *data,
|
||||||
|
size_t size) {
|
||||||
|
int rc = -1;
|
||||||
|
for (;;) {
|
||||||
|
bool done = false;
|
||||||
|
uint64_t m;
|
||||||
|
m = BlockSignals();
|
||||||
|
LockKeystrokes();
|
||||||
|
IngestConsoleInput(f->handle);
|
||||||
|
done = DigestConsoleInput(data, size, &rc);
|
||||||
|
UnlockKeystrokes();
|
||||||
|
UnblockSignals(m);
|
||||||
|
if (done) break;
|
||||||
|
if (f->flags & O_NONBLOCK) return eagain();
|
||||||
|
uint32_t ms = __SIG_POLL_INTERVAL_MS;
|
||||||
|
if (__ttymagic & kFdTtyNoBlock) {
|
||||||
|
if (!__vtime) {
|
||||||
|
return 0;
|
||||||
|
} else {
|
||||||
|
ms = __vtime * 100;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (_check_interrupts(kSigOpRestartable)) return -1;
|
||||||
|
if (__pause_thread(ms)) return -1;
|
||||||
|
}
|
||||||
if (rc > 0 && (__ttymagic & kFdTtyEchoing)) {
|
if (rc > 0 && (__ttymagic & kFdTtyEchoing)) {
|
||||||
EchoTerminalInput(f, data, size);
|
EchoTerminalInput(f, data, size);
|
||||||
}
|
}
|
||||||
|
@ -510,6 +576,12 @@ textwindows ssize_t sys_read_nt_impl(int fd, void *data, size_t size,
|
||||||
return got;
|
return got;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
errno_t err;
|
||||||
|
if (_weaken(pthread_testcancel_np) &&
|
||||||
|
(err = _weaken(pthread_testcancel_np)())) {
|
||||||
|
return ecanceled();
|
||||||
|
}
|
||||||
|
|
||||||
switch (GetLastError()) {
|
switch (GetLastError()) {
|
||||||
case kNtErrorBrokenPipe: // broken pipe
|
case kNtErrorBrokenPipe: // broken pipe
|
||||||
case kNtErrorNoData: // closing named pipe
|
case kNtErrorNoData: // closing named pipe
|
||||||
|
|
|
@ -97,3 +97,5 @@ int setrlimit(int resource, const struct rlimit *rlim) {
|
||||||
DescribeRlimit(0, rlim), rc);
|
DescribeRlimit(0, rlim), rc);
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
__weak_reference(setrlimit, setrlimit64);
|
||||||
|
|
|
@ -26,6 +26,7 @@
|
||||||
#include "libc/calls/state.internal.h"
|
#include "libc/calls/state.internal.h"
|
||||||
#include "libc/calls/struct/sigaction.h"
|
#include "libc/calls/struct/sigaction.h"
|
||||||
#include "libc/calls/struct/siginfo.h"
|
#include "libc/calls/struct/siginfo.h"
|
||||||
|
#include "libc/calls/struct/sigset.internal.h"
|
||||||
#include "libc/calls/struct/ucontext.internal.h"
|
#include "libc/calls/struct/ucontext.internal.h"
|
||||||
#include "libc/calls/ucontext.h"
|
#include "libc/calls/ucontext.h"
|
||||||
#include "libc/dce.h"
|
#include "libc/dce.h"
|
||||||
|
@ -49,6 +50,7 @@
|
||||||
#include "libc/nt/struct/ntexceptionpointers.h"
|
#include "libc/nt/struct/ntexceptionpointers.h"
|
||||||
#include "libc/nt/synchronization.h"
|
#include "libc/nt/synchronization.h"
|
||||||
#include "libc/nt/thread.h"
|
#include "libc/nt/thread.h"
|
||||||
|
#include "libc/runtime/runtime.h"
|
||||||
#include "libc/str/str.h"
|
#include "libc/str/str.h"
|
||||||
#include "libc/sysv/consts/sa.h"
|
#include "libc/sysv/consts/sa.h"
|
||||||
#include "libc/sysv/consts/sicode.h"
|
#include "libc/sysv/consts/sicode.h"
|
||||||
|
@ -124,19 +126,21 @@ static textwindows bool __sig_start(struct PosixThread *pt, int sig,
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static textwindows sigaction_f __sig_handler(unsigned rva) {
|
||||||
|
return (sigaction_f)(__executable_start + rva);
|
||||||
|
}
|
||||||
|
|
||||||
static textwindows void __sig_call(int sig, siginfo_t *si, ucontext_t *ctx,
|
static textwindows void __sig_call(int sig, siginfo_t *si, ucontext_t *ctx,
|
||||||
unsigned rva, unsigned flags,
|
unsigned rva, unsigned flags,
|
||||||
struct CosmoTib *tib) {
|
struct CosmoTib *tib) {
|
||||||
sigaction_f handler;
|
|
||||||
handler = (sigaction_f)(__executable_start + rva);
|
|
||||||
++__sig.count;
|
++__sig.count;
|
||||||
if (__sig_should_use_altstack(flags, tib)) {
|
if (__sig_should_use_altstack(flags, tib)) {
|
||||||
tib->tib_sigstack_flags |= SS_ONSTACK;
|
tib->tib_sigstack_flags |= SS_ONSTACK;
|
||||||
__stack_call(sig, si, ctx, 0, handler,
|
__stack_call(sig, si, ctx, 0, __sig_handler(rva),
|
||||||
tib->tib_sigstack_addr + tib->tib_sigstack_size);
|
tib->tib_sigstack_addr + tib->tib_sigstack_size);
|
||||||
tib->tib_sigstack_flags &= ~SS_ONSTACK;
|
tib->tib_sigstack_flags &= ~SS_ONSTACK;
|
||||||
} else {
|
} else {
|
||||||
handler(sig, si, ctx);
|
__sig_handler(rva)(sig, si, ctx);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -151,21 +155,29 @@ textwindows int __sig_raise(int sig, int sic) {
|
||||||
nc.ContextFlags = kNtContextAll;
|
nc.ContextFlags = kNtContextAll;
|
||||||
GetThreadContext(GetCurrentThread(), &nc);
|
GetThreadContext(GetCurrentThread(), &nc);
|
||||||
_ntcontext2linux(&ctx, &nc);
|
_ntcontext2linux(&ctx, &nc);
|
||||||
STRACE("raising %G", sig);
|
|
||||||
if (!(flags & SA_NODEFER)) {
|
if (!(flags & SA_NODEFER)) {
|
||||||
tib->tib_sigmask |= 1ull << (sig - 1);
|
tib->tib_sigmask |= 1ull << (sig - 1);
|
||||||
}
|
}
|
||||||
|
STRACE("entering raise(%G) signal handler %t with mask %s → %s", sig,
|
||||||
|
__sig_handler(rva), DescribeSigset(0, &ctx.uc_sigmask),
|
||||||
|
DescribeSigset(0, &(sigset_t){{pt->tib->tib_sigmask}}));
|
||||||
__sig_call(sig, &si, &ctx, rva, flags, tib);
|
__sig_call(sig, &si, &ctx, rva, flags, tib);
|
||||||
|
STRACE("leaving raise(%G) signal handler %t with mask %s → %s", sig,
|
||||||
|
__sig_handler(rva),
|
||||||
|
DescribeSigset(0, &(sigset_t){{pt->tib->tib_sigmask}}),
|
||||||
|
DescribeSigset(0, &ctx.uc_sigmask));
|
||||||
tib->tib_sigmask = ctx.uc_sigmask.__bits[0];
|
tib->tib_sigmask = ctx.uc_sigmask.__bits[0];
|
||||||
return (flags & SA_RESTART) ? 2 : 1;
|
return (flags & SA_RESTART) ? 2 : 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
textwindows void __sig_cancel(struct PosixThread *pt) {
|
textwindows void __sig_cancel(struct PosixThread *pt, unsigned flags) {
|
||||||
atomic_int *futex;
|
atomic_int *futex;
|
||||||
if (_weaken(WakeByAddressSingle) &&
|
if (_weaken(WakeByAddressSingle) &&
|
||||||
(futex = atomic_load_explicit(&pt->pt_futex, memory_order_acquire))) {
|
(futex = atomic_load_explicit(&pt->pt_futex, memory_order_acquire))) {
|
||||||
|
STRACE("canceling futex");
|
||||||
_weaken(WakeByAddressSingle)(futex);
|
_weaken(WakeByAddressSingle)(futex);
|
||||||
} else if (pt->iohandle > 0) {
|
} else if (!(flags & SA_RESTART) && pt->iohandle > 0) {
|
||||||
|
STRACE("canceling i/o operation");
|
||||||
if (!CancelIoEx(pt->iohandle, pt->ioverlap)) {
|
if (!CancelIoEx(pt->iohandle, pt->ioverlap)) {
|
||||||
int err = GetLastError();
|
int err = GetLastError();
|
||||||
if (err != kNtErrorNotFound) {
|
if (err != kNtErrorNotFound) {
|
||||||
|
@ -173,9 +185,13 @@ textwindows void __sig_cancel(struct PosixThread *pt) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else if (pt->pt_flags & PT_INSEMAPHORE) {
|
} else if (pt->pt_flags & PT_INSEMAPHORE) {
|
||||||
|
STRACE("canceling semaphore");
|
||||||
|
pt->pt_flags &= ~PT_INSEMAPHORE;
|
||||||
if (!ReleaseSemaphore(pt->semaphore, 1, 0)) {
|
if (!ReleaseSemaphore(pt->semaphore, 1, 0)) {
|
||||||
STRACE("ReleaseSemaphore() failed w/ %d", GetLastError());
|
STRACE("ReleaseSemaphore() failed w/ %d", GetLastError());
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
STRACE("canceling asynchronously");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -194,16 +210,25 @@ static textwindows wontreturn void __sig_panic(const char *msg) {
|
||||||
|
|
||||||
static textwindows wontreturn void __sig_tramp(struct SignalFrame *sf) {
|
static textwindows wontreturn void __sig_tramp(struct SignalFrame *sf) {
|
||||||
ucontext_t ctx = {0};
|
ucontext_t ctx = {0};
|
||||||
sigaction_f handler = (sigaction_f)(__executable_start + sf->rva);
|
int sig = sf->si.si_signo;
|
||||||
STRACE("__sig_tramp(%G, %t)", sf->si.si_signo, handler);
|
|
||||||
_ntcontext2linux(&ctx, sf->nc);
|
_ntcontext2linux(&ctx, sf->nc);
|
||||||
ctx.uc_sigmask.__bits[0] = sf->pt->tib->tib_sigmask;
|
ctx.uc_sigmask.__bits[0] =
|
||||||
|
atomic_load_explicit(&sf->pt->tib->tib_sigmask, memory_order_acquire);
|
||||||
if (!(sf->flags & SA_NODEFER)) {
|
if (!(sf->flags & SA_NODEFER)) {
|
||||||
sf->pt->tib->tib_sigmask |= 1ull << (sf->si.si_signo - 1);
|
sf->pt->tib->tib_sigmask |= 1ull << (sig - 1);
|
||||||
}
|
}
|
||||||
++__sig.count;
|
++__sig.count;
|
||||||
handler(sf->si.si_signo, &sf->si, &ctx);
|
STRACE("entering __sig_tramp(%G, %t) with mask %s → %s", sig,
|
||||||
sf->pt->tib->tib_sigmask = ctx.uc_sigmask.__bits[0];
|
__sig_handler(sf->rva), DescribeSigset(0, &ctx.uc_sigmask),
|
||||||
|
DescribeSigset(0, &(sigset_t){{sf->pt->tib->tib_sigmask}}));
|
||||||
|
__sig_handler(sf->rva)(sig, &sf->si, &ctx);
|
||||||
|
STRACE("leaving __sig_tramp(%G, %t) with mask %s → %s", sig,
|
||||||
|
__sig_handler(sf->rva),
|
||||||
|
DescribeSigset(0, &(sigset_t){{sf->pt->tib->tib_sigmask}}),
|
||||||
|
DescribeSigset(0, &ctx.uc_sigmask));
|
||||||
|
atomic_store_explicit(&sf->pt->tib->tib_sigmask, ctx.uc_sigmask.__bits[0],
|
||||||
|
memory_order_release);
|
||||||
|
// TDOO(jart): Do we need to do a __sig_check() here?
|
||||||
_ntlinux2context(sf->nc, &ctx);
|
_ntlinux2context(sf->nc, &ctx);
|
||||||
SetThreadContext(GetCurrentThread(), sf->nc);
|
SetThreadContext(GetCurrentThread(), sf->nc);
|
||||||
__sig_panic("SetThreadContext(GetCurrentThread)");
|
__sig_panic("SetThreadContext(GetCurrentThread)");
|
||||||
|
@ -259,7 +284,7 @@ static textwindows int __sig_killer(struct PosixThread *pt, int sig, int sic) {
|
||||||
}
|
}
|
||||||
ResumeThread(th); // doesn't actually resume if doing blocking i/o
|
ResumeThread(th); // doesn't actually resume if doing blocking i/o
|
||||||
pt->abort_errno = EINTR;
|
pt->abort_errno = EINTR;
|
||||||
__sig_cancel(pt); // we can wake it up immediately by canceling it
|
__sig_cancel(pt, flags); // we can wake it up immediately by canceling it
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -431,7 +456,7 @@ __msabi textwindows dontinstrument bool32 __sig_console(uint32_t dwCtrlType) {
|
||||||
|
|
||||||
static textwindows int __sig_checkem(atomic_ulong *sigs, struct CosmoTib *tib,
|
static textwindows int __sig_checkem(atomic_ulong *sigs, struct CosmoTib *tib,
|
||||||
const char *thing, int id) {
|
const char *thing, int id) {
|
||||||
bool handler_was_called = false;
|
int handler_was_called = 0;
|
||||||
uint64_t pending, masked, deliverable;
|
uint64_t pending, masked, deliverable;
|
||||||
pending = atomic_load_explicit(sigs, memory_order_acquire);
|
pending = atomic_load_explicit(sigs, memory_order_acquire);
|
||||||
masked = atomic_load_explicit(&tib->tib_sigmask, memory_order_acquire);
|
masked = atomic_load_explicit(&tib->tib_sigmask, memory_order_acquire);
|
||||||
|
@ -454,12 +479,12 @@ static textwindows int __sig_checkem(atomic_ulong *sigs, struct CosmoTib *tib,
|
||||||
// didn't have the SA_RESTART flag, and `2`, which means SA_RESTART
|
// didn't have the SA_RESTART flag, and `2`, which means SA_RESTART
|
||||||
// handlers were called (or `3` if both were the case).
|
// handlers were called (or `3` if both were the case).
|
||||||
textwindows int __sig_check(void) {
|
textwindows int __sig_check(void) {
|
||||||
bool handler_was_called = false;
|
int handler_was_called = false;
|
||||||
struct CosmoTib *tib = __get_tls();
|
struct CosmoTib *tib = __get_tls();
|
||||||
handler_was_called |=
|
handler_was_called |=
|
||||||
__sig_checkem(&tib->tib_sigpending, tib, "tid", tib->tib_tid);
|
__sig_checkem(&tib->tib_sigpending, tib, "tid", tib->tib_tid);
|
||||||
handler_was_called |= __sig_checkem(&__sig.pending, tib, "pid", getpid());
|
handler_was_called |= __sig_checkem(&__sig.pending, tib, "pid", getpid());
|
||||||
POLLTRACE("__sig_check() → %hhhd", handler_was_called);
|
POLLTRACE("__sig_check() → %d", handler_was_called);
|
||||||
return handler_was_called;
|
return handler_was_called;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -26,7 +26,7 @@ int __sig_check(void);
|
||||||
int __sig_kill(struct PosixThread *, int, int);
|
int __sig_kill(struct PosixThread *, int, int);
|
||||||
int __sig_mask(int, const sigset_t *, sigset_t *);
|
int __sig_mask(int, const sigset_t *, sigset_t *);
|
||||||
int __sig_raise(int, int);
|
int __sig_raise(int, int);
|
||||||
void __sig_cancel(struct PosixThread *);
|
void __sig_cancel(struct PosixThread *, unsigned);
|
||||||
void __sig_generate(int, int);
|
void __sig_generate(int, int);
|
||||||
void __sig_init(void);
|
void __sig_init(void);
|
||||||
|
|
||||||
|
|
|
@ -70,17 +70,7 @@ int sigsuspend(const sigset_t *ignore) {
|
||||||
} else {
|
} else {
|
||||||
__sig_mask(SIG_SETMASK, arg, &save);
|
__sig_mask(SIG_SETMASK, arg, &save);
|
||||||
while (!(rc = _check_interrupts(0))) {
|
while (!(rc = _check_interrupts(0))) {
|
||||||
struct PosixThread *pt;
|
if ((rc = __pause_thread(__SIG_SIG_INTERVAL_MS))) break;
|
||||||
pt = _pthread_self();
|
|
||||||
pt->abort_errno = 0;
|
|
||||||
pt->pt_flags |= PT_INSEMAPHORE;
|
|
||||||
WaitForSingleObject(pt->semaphore, __SIG_SIG_INTERVAL_MS);
|
|
||||||
pt->pt_flags &= ~PT_INSEMAPHORE;
|
|
||||||
if (pt->abort_errno) {
|
|
||||||
errno = pt->abort_errno;
|
|
||||||
rc = -1;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
__sig_mask(SIG_SETMASK, &save, 0);
|
__sig_mask(SIG_SETMASK, &save, 0);
|
||||||
}
|
}
|
||||||
|
|
|
@ -66,3 +66,5 @@ int statfs(const char *path, struct statfs *sf) {
|
||||||
STRACE("statfs(%#s, [%s]) → %d% m", path, DescribeStatfs(rc, sf));
|
STRACE("statfs(%#s, [%s]) → %d% m", path, DescribeStatfs(rc, sf));
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
__weak_reference(statfs, statfs64);
|
||||||
|
|
|
@ -31,15 +31,12 @@ struct Fd {
|
||||||
char kind;
|
char kind;
|
||||||
bool eoftty;
|
bool eoftty;
|
||||||
bool dontclose;
|
bool dontclose;
|
||||||
unsigned char buflen;
|
|
||||||
unsigned flags;
|
unsigned flags;
|
||||||
unsigned mode;
|
unsigned mode;
|
||||||
int64_t handle;
|
int64_t handle;
|
||||||
int64_t extra;
|
int64_t extra;
|
||||||
int64_t pointer;
|
int64_t pointer;
|
||||||
pthread_mutex_t lock;
|
pthread_mutex_t lock;
|
||||||
unsigned char mousebuttons;
|
|
||||||
char buf[32];
|
|
||||||
};
|
};
|
||||||
|
|
||||||
struct StdinRelay {
|
struct StdinRelay {
|
||||||
|
|
|
@ -67,30 +67,7 @@ static dontinline textwindows int sys_tcflush_nt(int fd, int queue) {
|
||||||
if (queue == TCOFLUSH) {
|
if (queue == TCOFLUSH) {
|
||||||
return 0; // windows console output is never buffered
|
return 0; // windows console output is never buffered
|
||||||
}
|
}
|
||||||
FlushConsoleInputBuffer(hConin);
|
return FlushConsoleInputBytes(hConin);
|
||||||
int rc = 0;
|
|
||||||
int e = errno;
|
|
||||||
int oldflags = g_fds.p[fd].flags;
|
|
||||||
g_fds.p[fd].flags |= O_NONBLOCK;
|
|
||||||
for (;;) {
|
|
||||||
char buf[512];
|
|
||||||
ssize_t got = sys_read_nt_impl(fd, buf, 512, -1);
|
|
||||||
if (!got) {
|
|
||||||
break;
|
|
||||||
} else if (got == -1) {
|
|
||||||
if (errno == EAGAIN) {
|
|
||||||
errno = e;
|
|
||||||
} else if (errno == EINTR) {
|
|
||||||
errno = e;
|
|
||||||
continue;
|
|
||||||
} else {
|
|
||||||
rc = -1;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
g_fds.p[fd].flags = oldflags;
|
|
||||||
return rc;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -25,6 +25,7 @@
|
||||||
#include "libc/macros.internal.h"
|
#include "libc/macros.internal.h"
|
||||||
#include "libc/nt/console.h"
|
#include "libc/nt/console.h"
|
||||||
#include "libc/nt/enum/consolemodeflags.h"
|
#include "libc/nt/enum/consolemodeflags.h"
|
||||||
|
#include "libc/nt/runtime.h"
|
||||||
#include "libc/nt/struct/consolescreenbufferinfoex.h"
|
#include "libc/nt/struct/consolescreenbufferinfoex.h"
|
||||||
#include "libc/str/str.h"
|
#include "libc/str/str.h"
|
||||||
#include "libc/sysv/consts/baud.internal.h"
|
#include "libc/sysv/consts/baud.internal.h"
|
||||||
|
|
|
@ -50,11 +50,40 @@ typedef uint32_t nlink_t; /* uint16_t on xnu */
|
||||||
#define TIME_T_MIN (-TIME_T_MAX - 1)
|
#define TIME_T_MIN (-TIME_T_MAX - 1)
|
||||||
|
|
||||||
#if defined(_LARGEFILE64_SOURCE) || defined(_GNU_SOURCE)
|
#if defined(_LARGEFILE64_SOURCE) || defined(_GNU_SOURCE)
|
||||||
#define blkcnt64_t blkcnt_t
|
#define F_GETLK64 F_GETLK
|
||||||
#define fsblkcnt64_t fsblkcnt_t
|
#define F_SETLK64 F_SETLK
|
||||||
#define fsfilcnt64_t fsfilcnt_t
|
#define F_SETLKW64 F_SETLKW
|
||||||
#define ino64_t ino_t
|
#define RLIM64_INFINITY RLIM_INFINITY
|
||||||
#define off64_t off_t
|
#define RLIM64_SAVED_CUR RLIM_SAVED_CUR
|
||||||
|
#define RLIM64_SAVED_MAX RLIM_SAVED_MAX
|
||||||
|
#define alphasort64 alphasort
|
||||||
|
#define blkcnt64_t blkcnt_t
|
||||||
|
#define dirent64 dirent
|
||||||
|
#define flock64 flock
|
||||||
|
#define fsfilcnt64_t fsfilcnt_t
|
||||||
|
#define fstat64 fstat
|
||||||
|
#define fstatat64 fstatat
|
||||||
|
#define fstatfs64 fstatfs
|
||||||
|
#define getrlimit64 getrlimit
|
||||||
|
#define ino64_t ino_t
|
||||||
|
#define lockf64 lockf
|
||||||
|
#define lstat64 lstat
|
||||||
|
#define mmap64 mmap
|
||||||
|
#define off64_t off_t
|
||||||
|
#define open64 open
|
||||||
|
#define openat64 openat
|
||||||
|
#define posix_fadvise64 posix_fadvise
|
||||||
|
#define posix_fallocate64 posix_fallocate
|
||||||
|
#define readdir64 readdir
|
||||||
|
#define readdir64_r readdir_r
|
||||||
|
#define rlim64_t rlim_t
|
||||||
|
#define rlimit64 rlimit
|
||||||
|
#define scandir64 scandir
|
||||||
|
#define sendfile64 sendfile
|
||||||
|
#define setrlimit64 setrlimit
|
||||||
|
#define stat64 stat
|
||||||
|
#define statfs64 statfs
|
||||||
|
#define versionsort64 versionsort
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
|
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
|
||||||
|
|
|
@ -86,10 +86,6 @@ static textwindows ssize_t sys_write_nt_impl(int fd, void *data, size_t size,
|
||||||
if (!pwriting) {
|
if (!pwriting) {
|
||||||
offset = 0;
|
offset = 0;
|
||||||
}
|
}
|
||||||
if (seekable && !pwriting) {
|
|
||||||
pthread_mutex_lock(&f->lock);
|
|
||||||
offset = f->pointer;
|
|
||||||
}
|
|
||||||
|
|
||||||
// To use the tty mouse events feature:
|
// To use the tty mouse events feature:
|
||||||
// - write(1, "\e[?1000;1002;1015;1006h") to enable
|
// - write(1, "\e[?1000;1002;1015;1006h") to enable
|
||||||
|
@ -161,6 +157,11 @@ static textwindows ssize_t sys_write_nt_impl(int fd, void *data, size_t size,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (seekable && !pwriting) {
|
||||||
|
pthread_mutex_lock(&f->lock);
|
||||||
|
offset = f->pointer;
|
||||||
|
}
|
||||||
|
|
||||||
struct NtOverlapped overlap = {.hEvent = CreateEvent(0, 0, 0, 0),
|
struct NtOverlapped overlap = {.hEvent = CreateEvent(0, 0, 0, 0),
|
||||||
.Pointer = offset};
|
.Pointer = offset};
|
||||||
ok = WriteFile(handle, data, size, 0, &overlap);
|
ok = WriteFile(handle, data, size, 0, &overlap);
|
||||||
|
@ -212,6 +213,12 @@ static textwindows ssize_t sys_write_nt_impl(int fd, void *data, size_t size,
|
||||||
return sent;
|
return sent;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
errno_t err;
|
||||||
|
if (_weaken(pthread_testcancel_np) &&
|
||||||
|
(err = _weaken(pthread_testcancel_np)())) {
|
||||||
|
return ecanceled();
|
||||||
|
}
|
||||||
|
|
||||||
switch (GetLastError()) {
|
switch (GetLastError()) {
|
||||||
// case kNtErrorInvalidHandle:
|
// case kNtErrorInvalidHandle:
|
||||||
// return ebadf(); /* handled by consts.sh */
|
// return ebadf(); /* handled by consts.sh */
|
||||||
|
|
61
libc/intrin/describefdset.c
Normal file
61
libc/intrin/describefdset.c
Normal file
|
@ -0,0 +1,61 @@
|
||||||
|
/*-*- 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/dce.h"
|
||||||
|
#include "libc/intrin/asan.internal.h"
|
||||||
|
#include "libc/intrin/bsr.h"
|
||||||
|
#include "libc/intrin/kprintf.h"
|
||||||
|
#include "libc/sock/select.h"
|
||||||
|
#include "libc/sock/select.internal.h"
|
||||||
|
|
||||||
|
#define N 100
|
||||||
|
|
||||||
|
#define append(...) o += ksnprintf(buf + o, N - o, __VA_ARGS__)
|
||||||
|
|
||||||
|
const char *(DescribeFdSet)(char buf[N], ssize_t rc, int nfds, fd_set *fds) {
|
||||||
|
int o = 0;
|
||||||
|
|
||||||
|
if (!fds) return "NULL";
|
||||||
|
if ((!IsAsan() && kisdangerous(fds)) ||
|
||||||
|
(IsAsan() && !__asan_is_valid(fds, sizeof(*fds) * nfds))) {
|
||||||
|
ksnprintf(buf, N, "%p", fds);
|
||||||
|
return buf;
|
||||||
|
}
|
||||||
|
|
||||||
|
append("{");
|
||||||
|
|
||||||
|
bool gotsome = false;
|
||||||
|
for (int fd = 0; fd < nfds; fd += 64) {
|
||||||
|
uint64_t w = fds->fds_bits[fd >> 6];
|
||||||
|
while (w) {
|
||||||
|
unsigned o = _bsr(w);
|
||||||
|
w &= ~((uint64_t)1 << o);
|
||||||
|
if (fd + o < nfds) {
|
||||||
|
if (!gotsome) {
|
||||||
|
gotsome = true;
|
||||||
|
append(", ");
|
||||||
|
append("%d", fd);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
append("}");
|
||||||
|
|
||||||
|
return buf;
|
||||||
|
}
|
|
@ -19,6 +19,7 @@
|
||||||
#include "libc/calls/state.internal.h"
|
#include "libc/calls/state.internal.h"
|
||||||
#include "libc/calls/struct/fd.internal.h"
|
#include "libc/calls/struct/fd.internal.h"
|
||||||
#include "libc/calls/ttydefaults.h"
|
#include "libc/calls/ttydefaults.h"
|
||||||
|
#include "libc/dce.h"
|
||||||
#include "libc/intrin/atomic.h"
|
#include "libc/intrin/atomic.h"
|
||||||
#include "libc/intrin/extend.internal.h"
|
#include "libc/intrin/extend.internal.h"
|
||||||
#include "libc/intrin/getenv.internal.h"
|
#include "libc/intrin/getenv.internal.h"
|
||||||
|
@ -26,6 +27,12 @@
|
||||||
#include "libc/intrin/nomultics.internal.h"
|
#include "libc/intrin/nomultics.internal.h"
|
||||||
#include "libc/intrin/pushpop.internal.h"
|
#include "libc/intrin/pushpop.internal.h"
|
||||||
#include "libc/intrin/weaken.h"
|
#include "libc/intrin/weaken.h"
|
||||||
|
#include "libc/nt/console.h"
|
||||||
|
#include "libc/nt/createfile.h"
|
||||||
|
#include "libc/nt/enum/accessmask.h"
|
||||||
|
#include "libc/nt/enum/creationdisposition.h"
|
||||||
|
#include "libc/nt/enum/fileflagandattributes.h"
|
||||||
|
#include "libc/nt/enum/filesharemode.h"
|
||||||
#include "libc/nt/runtime.h"
|
#include "libc/nt/runtime.h"
|
||||||
#include "libc/runtime/memtrack.internal.h"
|
#include "libc/runtime/memtrack.internal.h"
|
||||||
#include "libc/runtime/runtime.h"
|
#include "libc/runtime/runtime.h"
|
||||||
|
@ -116,10 +123,10 @@ textstartup void __init_fds(int argc, char **argv, char **envp) {
|
||||||
SetupWinStd(fds, 0, kNtStdInputHandle, sockset);
|
SetupWinStd(fds, 0, kNtStdInputHandle, sockset);
|
||||||
SetupWinStd(fds, 1, kNtStdOutputHandle, sockset);
|
SetupWinStd(fds, 1, kNtStdOutputHandle, sockset);
|
||||||
SetupWinStd(fds, 2, kNtStdErrorHandle, sockset);
|
SetupWinStd(fds, 2, kNtStdErrorHandle, sockset);
|
||||||
|
__veof = CTRL('D');
|
||||||
|
__vintr = CTRL('C');
|
||||||
|
__vquit = CTRL('\\');
|
||||||
}
|
}
|
||||||
fds->p[1].flags = O_WRONLY | O_APPEND;
|
fds->p[1].flags = O_WRONLY | O_APPEND;
|
||||||
fds->p[2].flags = O_WRONLY | O_APPEND;
|
fds->p[2].flags = O_WRONLY | O_APPEND;
|
||||||
__veof = CTRL('D');
|
|
||||||
__vintr = CTRL('C');
|
|
||||||
__vquit = CTRL('\\');
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -25,3 +25,4 @@ unsigned char __veof;
|
||||||
unsigned char __vintr;
|
unsigned char __vintr;
|
||||||
unsigned char __vquit;
|
unsigned char __vquit;
|
||||||
unsigned char __vtime;
|
unsigned char __vtime;
|
||||||
|
unsigned char __mousebuttons;
|
||||||
|
|
|
@ -11,6 +11,7 @@ extern unsigned char __veof;
|
||||||
extern unsigned char __vintr;
|
extern unsigned char __vintr;
|
||||||
extern unsigned char __vquit;
|
extern unsigned char __vquit;
|
||||||
extern unsigned char __vtime;
|
extern unsigned char __vtime;
|
||||||
|
extern unsigned char __mousebuttons;
|
||||||
|
|
||||||
COSMOPOLITAN_C_END_
|
COSMOPOLITAN_C_END_
|
||||||
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
|
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
|
||||||
|
|
|
@ -16,13 +16,12 @@
|
||||||
COSMOPOLITAN_C_START_
|
COSMOPOLITAN_C_START_
|
||||||
|
|
||||||
#ifdef SYSDEBUG
|
#ifdef SYSDEBUG
|
||||||
#define STRACE(FMT, ...) \
|
#define STRACE(FMT, ...) \
|
||||||
do { \
|
do { \
|
||||||
if (UNLIKELY(__strace > 0) && strace_enabled(0) > 0) { \
|
if (UNLIKELY(strace_enter())) { \
|
||||||
ftrace_enabled(-1); \
|
__stracef(STRACE_PROLOGUE FMT "\n", ##__VA_ARGS__); \
|
||||||
__stracef(STRACE_PROLOGUE FMT "\n", ##__VA_ARGS__); \
|
ftrace_enabled(+1); \
|
||||||
ftrace_enabled(+1); \
|
} \
|
||||||
} \
|
|
||||||
} while (0)
|
} while (0)
|
||||||
#else
|
#else
|
||||||
#define STRACE(FMT, ...) (void)0
|
#define STRACE(FMT, ...) (void)0
|
||||||
|
|
31
libc/intrin/strace_enter.c
Normal file
31
libc/intrin/strace_enter.c
Normal 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 2023 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/runtime/runtime.h"
|
||||||
|
#ifdef SYSDEBUG
|
||||||
|
|
||||||
|
dontinstrument bool strace_enter(void) {
|
||||||
|
if (strace_enabled(0) > 0) {
|
||||||
|
ftrace_enabled(-1);
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif /* SYSDEBUG */
|
|
@ -29,7 +29,7 @@
|
||||||
#define INT16_MAX __INT16_MAX__
|
#define INT16_MAX __INT16_MAX__
|
||||||
#define INT32_MAX __INT32_MAX__
|
#define INT32_MAX __INT32_MAX__
|
||||||
#define INT64_MAX __INT64_MAX__
|
#define INT64_MAX __INT64_MAX__
|
||||||
#define WINT_MAX __WCHAR_MAX__
|
#define WINT_MAX __WINT_MAX__
|
||||||
#define WCHAR_MAX __WCHAR_MAX__
|
#define WCHAR_MAX __WCHAR_MAX__
|
||||||
#define INTPTR_MAX __INTPTR_MAX__
|
#define INTPTR_MAX __INTPTR_MAX__
|
||||||
#define PTRDIFF_MAX __PTRDIFF_MAX__
|
#define PTRDIFF_MAX __PTRDIFF_MAX__
|
||||||
|
@ -55,7 +55,7 @@
|
||||||
#define INT64_MIN (-INT64_MAX - 1)
|
#define INT64_MIN (-INT64_MAX - 1)
|
||||||
#define INTMAX_MIN (-INTMAX_MAX - 1)
|
#define INTMAX_MIN (-INTMAX_MAX - 1)
|
||||||
#define INTPTR_MIN (-INTPTR_MAX - 1)
|
#define INTPTR_MIN (-INTPTR_MAX - 1)
|
||||||
#define WINT_MIN (-WINT_MAX - 1)
|
#define WINT_MIN __WINT_MIN__
|
||||||
#define WCHAR_MIN (-WCHAR_MAX - 1)
|
#define WCHAR_MIN (-WCHAR_MAX - 1)
|
||||||
#define PTRDIFF_MIN (-PTRDIFF_MAX - 1)
|
#define PTRDIFF_MIN (-PTRDIFF_MAX - 1)
|
||||||
|
|
||||||
|
|
|
@ -30,6 +30,7 @@
|
||||||
#include "libc/runtime/memtrack.internal.h"
|
#include "libc/runtime/memtrack.internal.h"
|
||||||
#include "libc/runtime/runtime.h"
|
#include "libc/runtime/runtime.h"
|
||||||
#include "libc/stdio/stdio.h"
|
#include "libc/stdio/stdio.h"
|
||||||
|
#include "libc/str/str.h"
|
||||||
|
|
||||||
__static_yoink("strerror_wr");
|
__static_yoink("strerror_wr");
|
||||||
|
|
||||||
|
@ -69,11 +70,10 @@ relegated void __check_fail(const char *suffix, //
|
||||||
va_end(va);
|
va_end(va);
|
||||||
kprintf("\n");
|
kprintf("\n");
|
||||||
}
|
}
|
||||||
kprintf("\t%m\n\t%s%s", SUBTLE, program_invocation_name);
|
kprintf("\t%s\n\t%s%s", strerror(errno), SUBTLE, program_invocation_name);
|
||||||
for (i = 1; i < __argc; ++i) {
|
for (i = 1; i < __argc; ++i) {
|
||||||
kprintf(" %s", __argv[i]);
|
kprintf(" %s", __argv[i]);
|
||||||
}
|
}
|
||||||
kprintf("%s\n", RESET);
|
kprintf("%s\n", RESET);
|
||||||
__die();
|
__die();
|
||||||
__builtin_unreachable();
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -47,7 +47,7 @@ relegated wontreturn void __die(void) {
|
||||||
strcpy(host, "unknown");
|
strcpy(host, "unknown");
|
||||||
gethostname(host, sizeof(host));
|
gethostname(host, sizeof(host));
|
||||||
kprintf("%serror: %s on %s pid %d tid %d has perished%s\n"
|
kprintf("%serror: %s on %s pid %d tid %d has perished%s\n"
|
||||||
" cosmoaddr2line %s%s %s\n",
|
"cosmoaddr2line %s%s %s\n",
|
||||||
__nocolor ? "" : "\e[1;31m", program_invocation_short_name, host,
|
__nocolor ? "" : "\e[1;31m", program_invocation_short_name, host,
|
||||||
getpid(), gettid(), __nocolor ? "" : "\e[0m", __argv[0],
|
getpid(), gettid(), __nocolor ? "" : "\e[0m", __argv[0],
|
||||||
endswith(__argv[0], ".com") ? ".dbg" : "",
|
endswith(__argv[0], ".com") ? ".dbg" : "",
|
||||||
|
|
|
@ -9,7 +9,7 @@ struct CritbitNode {
|
||||||
unsigned otherbits;
|
unsigned otherbits;
|
||||||
};
|
};
|
||||||
|
|
||||||
int PutEnvImpl(char *, bool);
|
int __putenv(char *, bool);
|
||||||
|
|
||||||
COSMOPOLITAN_C_END_
|
COSMOPOLITAN_C_END_
|
||||||
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
|
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
|
||||||
|
|
|
@ -19,31 +19,28 @@
|
||||||
#include "libc/intrin/getenv.internal.h"
|
#include "libc/intrin/getenv.internal.h"
|
||||||
#include "libc/intrin/leaky.internal.h"
|
#include "libc/intrin/leaky.internal.h"
|
||||||
#include "libc/intrin/strace.internal.h"
|
#include "libc/intrin/strace.internal.h"
|
||||||
#include "libc/intrin/weaken.h"
|
|
||||||
#include "libc/macros.internal.h"
|
#include "libc/macros.internal.h"
|
||||||
#include "libc/mem/internal.h"
|
#include "libc/mem/internal.h"
|
||||||
#include "libc/mem/mem.h"
|
#include "libc/mem/mem.h"
|
||||||
#include "libc/runtime/runtime.h"
|
#include "libc/runtime/runtime.h"
|
||||||
#include "libc/sysv/errfuns.h"
|
#include "libc/sysv/errfuns.h"
|
||||||
|
|
||||||
#define ToUpper(c) ((c) >= 'a' && (c) <= 'z' ? (c) - 'a' + 'A' : (c))
|
|
||||||
|
|
||||||
static char **expected;
|
static char **expected;
|
||||||
static size_t capacity;
|
static size_t capacity;
|
||||||
|
|
||||||
static size_t GetEnvironLen(char **env) {
|
static size_t __lenenv(char **env) {
|
||||||
char **p = env;
|
char **p = env;
|
||||||
while (*p) ++p;
|
while (*p) ++p;
|
||||||
return p - env;
|
return p - env;
|
||||||
}
|
}
|
||||||
|
|
||||||
static char **GrowEnviron(char **a) {
|
static char **__growenv(char **a) {
|
||||||
size_t n, c;
|
size_t n, c;
|
||||||
char **b, **p;
|
char **b, **p;
|
||||||
if (!a) a = environ;
|
if (!a) a = environ;
|
||||||
n = a ? GetEnvironLen(a) : 0;
|
n = a ? __lenenv(a) : 0;
|
||||||
c = MAX(16ul, n) << 1;
|
c = MAX(8ul, n) << 1;
|
||||||
if (_weaken(malloc) && (b = _weaken(malloc)(c * sizeof(char *)))) {
|
if ((b = malloc(c * sizeof(char *)))) {
|
||||||
if (a) {
|
if (a) {
|
||||||
for (p = b; *a;) {
|
for (p = b; *a;) {
|
||||||
*p++ = *a++;
|
*p++ = *a++;
|
||||||
|
@ -56,18 +53,17 @@ static char **GrowEnviron(char **a) {
|
||||||
capacity = c;
|
capacity = c;
|
||||||
return b;
|
return b;
|
||||||
} else {
|
} else {
|
||||||
enomem();
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
IGNORE_LEAKS(GrowEnviron)
|
IGNORE_LEAKS(__growenv)
|
||||||
|
|
||||||
int PutEnvImpl(char *s, bool overwrite) {
|
int __putenv(char *s, bool overwrite) {
|
||||||
char **p;
|
char **p;
|
||||||
struct Env e;
|
struct Env e;
|
||||||
if (!(p = environ)) {
|
if (!(p = environ)) {
|
||||||
if (!(p = GrowEnviron(0))) {
|
if (!(p = __growenv(0))) {
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -83,7 +79,7 @@ int PutEnvImpl(char *s, bool overwrite) {
|
||||||
capacity = e.i;
|
capacity = e.i;
|
||||||
}
|
}
|
||||||
if (e.i + 1 >= capacity) {
|
if (e.i + 1 >= capacity) {
|
||||||
if (!(p = GrowEnviron(p))) {
|
if (!(p = __growenv(p))) {
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -99,13 +95,13 @@ int PutEnvImpl(char *s, bool overwrite) {
|
||||||
* become part of the environment; changes to its memory will change
|
* become part of the environment; changes to its memory will change
|
||||||
* the environment too
|
* the environment too
|
||||||
* @return 0 on success, or non-zero w/ errno on error
|
* @return 0 on success, or non-zero w/ errno on error
|
||||||
* @raise ENOMEM if we require more vespene gas
|
* @raise ENOMEM if out of memory
|
||||||
* @see setenv(), getenv()
|
* @see setenv(), getenv()
|
||||||
* @threadunsafe
|
* @threadunsafe
|
||||||
*/
|
*/
|
||||||
int putenv(char *s) {
|
int putenv(char *s) {
|
||||||
int rc;
|
int rc;
|
||||||
rc = PutEnvImpl(s, true);
|
rc = __putenv(s, true);
|
||||||
STRACE("putenv(%#s) → %d% m", s, rc);
|
STRACE("putenv(%#s) → %d% m", s, rc);
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
|
@ -18,7 +18,6 @@
|
||||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||||
#include "libc/intrin/leaky.internal.h"
|
#include "libc/intrin/leaky.internal.h"
|
||||||
#include "libc/intrin/strace.internal.h"
|
#include "libc/intrin/strace.internal.h"
|
||||||
#include "libc/intrin/weaken.h"
|
|
||||||
#include "libc/mem/internal.h"
|
#include "libc/mem/internal.h"
|
||||||
#include "libc/mem/mem.h"
|
#include "libc/mem/mem.h"
|
||||||
#include "libc/runtime/runtime.h"
|
#include "libc/runtime/runtime.h"
|
||||||
|
@ -29,8 +28,8 @@
|
||||||
* Copies variable to environment.
|
* Copies variable to environment.
|
||||||
*
|
*
|
||||||
* @return 0 on success, or -1 w/ errno and environment is unchanged
|
* @return 0 on success, or -1 w/ errno and environment is unchanged
|
||||||
* @raise ENOMEM if out of memory or malloc() wasn't linked
|
|
||||||
* @raise EINVAL if `name` is empty or contains `'='`
|
* @raise EINVAL if `name` is empty or contains `'='`
|
||||||
|
* @raise ENOMEM if out of memory
|
||||||
* @see putenv(), getenv()
|
* @see putenv(), getenv()
|
||||||
* @threadunsafe
|
* @threadunsafe
|
||||||
*/
|
*/
|
||||||
|
@ -38,19 +37,14 @@ int setenv(const char *name, const char *value, int overwrite) {
|
||||||
int rc;
|
int rc;
|
||||||
char *s;
|
char *s;
|
||||||
size_t n, m;
|
size_t n, m;
|
||||||
const char *t;
|
if (!name || !*name || !value || strchr(name, '=')) return einval();
|
||||||
if (!name || !*name || !value) return einval();
|
if ((s = malloc((n = strlen(name)) + 1 + (m = strlen(value)) + 1))) {
|
||||||
for (t = name; *t; ++t) {
|
memcpy(mempcpy(mempcpy(s, name, n), "=", 1), value, m + 1);
|
||||||
if (*t == '=') return einval();
|
rc = __putenv(s, overwrite);
|
||||||
|
} else {
|
||||||
|
rc = -1;
|
||||||
}
|
}
|
||||||
n = strlen(name);
|
STRACE("setenv(%#s, %#s, %hhhd) → %d% m", name, value, overwrite, rc);
|
||||||
m = strlen(value);
|
|
||||||
if (!_weaken(malloc) || !(s = _weaken(malloc)(n + 1 + m + 1))) {
|
|
||||||
return enomem();
|
|
||||||
}
|
|
||||||
memcpy(mempcpy(mempcpy(s, name, n), "=", 1), value, m + 1);
|
|
||||||
rc = PutEnvImpl(s, overwrite);
|
|
||||||
STRACE("setenv(%#s, %#s, %d) → %d% m", name, value, overwrite, rc);
|
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
|
@ -25,6 +25,6 @@
|
||||||
*/
|
*/
|
||||||
wchar_t *wcsdup(const wchar_t *s) {
|
wchar_t *wcsdup(const wchar_t *s) {
|
||||||
size_t len = wcslen(s);
|
size_t len = wcslen(s);
|
||||||
char *s2 = malloc((len + 1) * sizeof(wchar_t));
|
wchar_t *s2 = malloc((len + 1) * sizeof(wchar_t));
|
||||||
return s2 ? memcpy(s2, s, (len + 1) * sizeof(wchar_t)) : NULL;
|
return s2 ? wmemcpy(s2, s, len + 1) : NULL;
|
||||||
}
|
}
|
||||||
|
|
|
@ -28,8 +28,8 @@
|
||||||
#define kNtVkAccept 0x1E
|
#define kNtVkAccept 0x1E
|
||||||
#define kNtVkModechange 0x1F
|
#define kNtVkModechange 0x1F
|
||||||
#define kNtVkSpace 0x20
|
#define kNtVkSpace 0x20
|
||||||
#define kNtVkPrior 0x21
|
#define kNtVkPrior 0x21 /* page up */
|
||||||
#define kNtVkNext 0x22
|
#define kNtVkNext 0x22 /* page down */
|
||||||
#define kNtVkEnd 0x23
|
#define kNtVkEnd 0x23
|
||||||
#define kNtVkHome 0x24
|
#define kNtVkHome 0x24
|
||||||
#define kNtVkLeft 0x25
|
#define kNtVkLeft 0x25
|
||||||
|
|
|
@ -180,9 +180,6 @@ static keywords void sys_execve_nt_relay(intptr_t h, long b, long c, long d) {
|
||||||
|
|
||||||
// close more handles
|
// close more handles
|
||||||
__imp_SetConsoleCtrlHandler((void *)sys_execve_nt_event, 1);
|
__imp_SetConsoleCtrlHandler((void *)sys_execve_nt_event, 1);
|
||||||
PurgeThread(g_fds.stdin.thread);
|
|
||||||
PurgeHandle(g_fds.stdin.reader);
|
|
||||||
PurgeHandle(g_fds.stdin.writer);
|
|
||||||
for (i = 0; i < g_fds.n; ++i) {
|
for (i = 0; i < g_fds.n; ++i) {
|
||||||
if (g_fds.p[i].kind != kFdEmpty) {
|
if (g_fds.p[i].kind != kFdEmpty) {
|
||||||
PurgeHandle(g_fds.p[i].handle);
|
PurgeHandle(g_fds.p[i].handle);
|
||||||
|
|
|
@ -58,8 +58,7 @@ static bool IsApeFile(const char *path) {
|
||||||
return true;
|
return true;
|
||||||
} else {
|
} else {
|
||||||
bool res = false;
|
bool res = false;
|
||||||
BLOCK_CANCELLATIONS;
|
BLOCK_SIGNALS;
|
||||||
BEGIN_CANCELLATION_POINT;
|
|
||||||
int fd;
|
int fd;
|
||||||
char buf[8];
|
char buf[8];
|
||||||
int flags = O_RDONLY | O_NOCTTY | O_NONBLOCK | O_CLOEXEC;
|
int flags = O_RDONLY | O_NOCTTY | O_NONBLOCK | O_CLOEXEC;
|
||||||
|
@ -67,8 +66,7 @@ static bool IsApeFile(const char *path) {
|
||||||
res = sys_pread(fd, buf, 8, 0, 0) == 8 && IsApeLoadable(buf);
|
res = sys_pread(fd, buf, 8, 0, 0) == 8 && IsApeLoadable(buf);
|
||||||
sys_close(fd);
|
sys_close(fd);
|
||||||
}
|
}
|
||||||
END_CANCELLATION_POINT;
|
ALLOW_SIGNALS;
|
||||||
ALLOW_CANCELLATIONS;
|
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -199,10 +199,7 @@ textwindows void WinMainForked(void) {
|
||||||
char16_t fvar[21 + 1 + 21 + 1];
|
char16_t fvar[21 + 1 + 21 + 1];
|
||||||
uint32_t i, varlen, oldprot, savepid;
|
uint32_t i, varlen, oldprot, savepid;
|
||||||
long mapcount, mapcapacity, specialz;
|
long mapcount, mapcapacity, specialz;
|
||||||
|
|
||||||
struct StdinRelay stdin;
|
|
||||||
struct Fds *fds = __veil("r", &g_fds);
|
struct Fds *fds = __veil("r", &g_fds);
|
||||||
stdin = fds->stdin;
|
|
||||||
|
|
||||||
// check to see if the process was actually forked
|
// check to see if the process was actually forked
|
||||||
// this variable should have the pipe handle numba
|
// this variable should have the pipe handle numba
|
||||||
|
@ -282,7 +279,6 @@ textwindows void WinMainForked(void) {
|
||||||
|
|
||||||
// rewrap the stdin named pipe hack
|
// rewrap the stdin named pipe hack
|
||||||
// since the handles closed on fork
|
// since the handles closed on fork
|
||||||
fds->stdin = stdin;
|
|
||||||
fds->p[0].handle = GetStdHandle(kNtStdInputHandle);
|
fds->p[0].handle = GetStdHandle(kNtStdInputHandle);
|
||||||
fds->p[1].handle = GetStdHandle(kNtStdOutputHandle);
|
fds->p[1].handle = GetStdHandle(kNtStdOutputHandle);
|
||||||
fds->p[2].handle = GetStdHandle(kNtStdErrorHandle);
|
fds->p[2].handle = GetStdHandle(kNtStdErrorHandle);
|
||||||
|
|
|
@ -18,11 +18,14 @@
|
||||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||||
#include "libc/calls/calls.h"
|
#include "libc/calls/calls.h"
|
||||||
#include "libc/errno.h"
|
#include "libc/errno.h"
|
||||||
|
#include "libc/intrin/atomic.h"
|
||||||
#include "libc/intrin/dll.h"
|
#include "libc/intrin/dll.h"
|
||||||
#include "libc/nt/errors.h"
|
#include "libc/nt/errors.h"
|
||||||
#include "libc/nt/runtime.h"
|
#include "libc/nt/runtime.h"
|
||||||
#include "libc/proc/proc.internal.h"
|
#include "libc/proc/proc.internal.h"
|
||||||
#include "libc/sysv/errfuns.h"
|
#include "libc/sysv/errfuns.h"
|
||||||
|
#include "libc/thread/thread.h"
|
||||||
|
#include "libc/thread/tls.h"
|
||||||
#ifdef __x86_64__
|
#ifdef __x86_64__
|
||||||
|
|
||||||
static textwindows int sys_kill_nt_impl(int pid, int sig) {
|
static textwindows int sys_kill_nt_impl(int pid, int sig) {
|
||||||
|
@ -50,7 +53,6 @@ static textwindows int sys_kill_nt_impl(int pid, int sig) {
|
||||||
}
|
}
|
||||||
|
|
||||||
textwindows int sys_kill_nt(int pid, int sig) {
|
textwindows int sys_kill_nt(int pid, int sig) {
|
||||||
int rc;
|
|
||||||
if (!(0 <= sig && sig <= 64)) return einval();
|
if (!(0 <= sig && sig <= 64)) return einval();
|
||||||
|
|
||||||
// XXX: NT doesn't really have process groups. For instance the
|
// XXX: NT doesn't really have process groups. For instance the
|
||||||
|
@ -66,9 +68,14 @@ textwindows int sys_kill_nt(int pid, int sig) {
|
||||||
return raise(sig);
|
return raise(sig);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int rc;
|
||||||
|
uint64_t m;
|
||||||
|
m = atomic_exchange(&__get_tls()->tib_sigmask, -1);
|
||||||
__proc_lock();
|
__proc_lock();
|
||||||
|
pthread_cleanup_push((void *)__proc_unlock, 0);
|
||||||
rc = sys_kill_nt_impl(pid, sig);
|
rc = sys_kill_nt_impl(pid, sig);
|
||||||
__proc_unlock();
|
pthread_cleanup_pop(true);
|
||||||
|
atomic_store_explicit(&__get_tls()->tib_sigmask, m, memory_order_release);
|
||||||
|
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
|
@ -144,7 +144,7 @@ textwindows struct Proc *__proc_new(void) {
|
||||||
struct Dll *e;
|
struct Dll *e;
|
||||||
struct Proc *proc = 0;
|
struct Proc *proc = 0;
|
||||||
int i, n = ARRAYLEN(__proc.pool);
|
int i, n = ARRAYLEN(__proc.pool);
|
||||||
if (atomic_load_explicit(&__proc.allocated, memory_order_relaxed) < n &&
|
if (atomic_load_explicit(&__proc.allocated, memory_order_acquire) < n &&
|
||||||
(i = atomic_fetch_add(&__proc.allocated, 1)) < n) {
|
(i = atomic_fetch_add(&__proc.allocated, 1)) < n) {
|
||||||
proc = __proc.pool + i;
|
proc = __proc.pool + i;
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -26,6 +26,7 @@
|
||||||
#include "libc/cosmo.h"
|
#include "libc/cosmo.h"
|
||||||
#include "libc/errno.h"
|
#include "libc/errno.h"
|
||||||
#include "libc/fmt/conv.h"
|
#include "libc/fmt/conv.h"
|
||||||
|
#include "libc/intrin/atomic.h"
|
||||||
#include "libc/intrin/dll.h"
|
#include "libc/intrin/dll.h"
|
||||||
#include "libc/intrin/strace.internal.h"
|
#include "libc/intrin/strace.internal.h"
|
||||||
#include "libc/macros.internal.h"
|
#include "libc/macros.internal.h"
|
||||||
|
@ -38,6 +39,7 @@
|
||||||
#include "libc/str/str.h"
|
#include "libc/str/str.h"
|
||||||
#include "libc/sysv/consts/w.h"
|
#include "libc/sysv/consts/w.h"
|
||||||
#include "libc/sysv/errfuns.h"
|
#include "libc/sysv/errfuns.h"
|
||||||
|
#include "libc/thread/thread.h"
|
||||||
#include "libc/thread/tls.h"
|
#include "libc/thread/tls.h"
|
||||||
|
|
||||||
#ifdef __x86_64__
|
#ifdef __x86_64__
|
||||||
|
@ -98,7 +100,7 @@ static textwindows int CheckZombies(int pid, int *wstatus,
|
||||||
}
|
}
|
||||||
|
|
||||||
static textwindows int WaitForProcess(int pid, int *wstatus, int options,
|
static textwindows int WaitForProcess(int pid, int *wstatus, int options,
|
||||||
struct rusage *opt_out_rusage) {
|
struct rusage *rusage, uint64_t *m) {
|
||||||
int rc, *wv;
|
int rc, *wv;
|
||||||
nsync_cv *cv;
|
nsync_cv *cv;
|
||||||
struct Dll *e;
|
struct Dll *e;
|
||||||
|
@ -106,7 +108,7 @@ static textwindows int WaitForProcess(int pid, int *wstatus, int options,
|
||||||
struct timespec deadline = timespec_zero;
|
struct timespec deadline = timespec_zero;
|
||||||
|
|
||||||
// check list of processes that've already exited
|
// check list of processes that've already exited
|
||||||
if ((rc = CheckZombies(pid, wstatus, opt_out_rusage))) {
|
if ((rc = CheckZombies(pid, wstatus, rusage))) {
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -139,16 +141,16 @@ CheckForInterrupt:
|
||||||
if (_check_interrupts(kSigOpRestartable) == -1) return -1;
|
if (_check_interrupts(kSigOpRestartable) == -1) return -1;
|
||||||
deadline = GetNextDeadline(deadline);
|
deadline = GetNextDeadline(deadline);
|
||||||
SpuriousWakeup:
|
SpuriousWakeup:
|
||||||
BEGIN_BLOCKING_OPERATION;
|
|
||||||
++*wv;
|
++*wv;
|
||||||
|
atomic_store_explicit(&__get_tls()->tib_sigmask, *m, memory_order_release);
|
||||||
rc = nsync_cv_wait_with_deadline(cv, &__proc.lock, deadline, 0);
|
rc = nsync_cv_wait_with_deadline(cv, &__proc.lock, deadline, 0);
|
||||||
|
*m = atomic_exchange(&__get_tls()->tib_sigmask, -1);
|
||||||
--*wv;
|
--*wv;
|
||||||
END_BLOCKING_OPERATION;
|
|
||||||
if (rc == ECANCELED) return ecanceled();
|
if (rc == ECANCELED) return ecanceled();
|
||||||
if (pr && pr->iszombie) return ReapZombie(pr, wstatus, opt_out_rusage);
|
if (pr && pr->iszombie) return ReapZombie(pr, wstatus, rusage);
|
||||||
if (rc == ETIMEDOUT) goto CheckForInterrupt;
|
if (rc == ETIMEDOUT) goto CheckForInterrupt;
|
||||||
unassert(!rc);
|
unassert(!rc);
|
||||||
if (!pr && (rc = CheckZombies(pid, wstatus, opt_out_rusage))) return rc;
|
if (!pr && (rc = CheckZombies(pid, wstatus, rusage))) return rc;
|
||||||
goto SpuriousWakeup;
|
goto SpuriousWakeup;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -163,9 +165,12 @@ textwindows int sys_wait4_nt(int pid, int *opt_out_wstatus, int options,
|
||||||
// just does an "ignore ctrl-c" internally.
|
// just does an "ignore ctrl-c" internally.
|
||||||
if (pid == 0) pid = -1;
|
if (pid == 0) pid = -1;
|
||||||
if (pid < -1) pid = -pid;
|
if (pid < -1) pid = -pid;
|
||||||
|
uint64_t m = atomic_exchange(&__get_tls()->tib_sigmask, -1);
|
||||||
__proc_lock();
|
__proc_lock();
|
||||||
rc = WaitForProcess(pid, opt_out_wstatus, options, opt_out_rusage);
|
pthread_cleanup_push((void *)__proc_unlock, 0);
|
||||||
__proc_unlock();
|
rc = WaitForProcess(pid, opt_out_wstatus, options, opt_out_rusage, &m);
|
||||||
|
pthread_cleanup_pop(true);
|
||||||
|
atomic_store_explicit(&__get_tls()->tib_sigmask, m, memory_order_release);
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -17,7 +17,6 @@
|
||||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||||
#include "ape/sections.internal.h"
|
#include "ape/sections.internal.h"
|
||||||
#include "libc/assert.h"
|
|
||||||
#include "libc/calls/syscall-sysv.internal.h"
|
#include "libc/calls/syscall-sysv.internal.h"
|
||||||
#include "libc/dce.h"
|
#include "libc/dce.h"
|
||||||
#include "libc/errno.h"
|
#include "libc/errno.h"
|
||||||
|
@ -120,8 +119,8 @@ textstartup void __enable_tls(void) {
|
||||||
// _tbss_start + _tbss_size:
|
// _tbss_start + _tbss_size:
|
||||||
// _tdata_start + _tls_size:
|
// _tdata_start + _tls_size:
|
||||||
//
|
//
|
||||||
unassert(_tbss_start == _tdata_start + I(_tbss_offset));
|
// unassert(_tbss_start == _tdata_start + I(_tbss_offset));
|
||||||
unassert(_tbss_start + I(_tbss_size) == _tdata_start + I(_tls_size));
|
// unassert(_tbss_start + I(_tbss_size) == _tdata_start + I(_tls_size));
|
||||||
|
|
||||||
#ifdef __x86_64__
|
#ifdef __x86_64__
|
||||||
|
|
||||||
|
@ -136,10 +135,7 @@ textstartup void __enable_tls(void) {
|
||||||
// malloc() being linked, which links _mapanon(). otherwise
|
// malloc() being linked, which links _mapanon(). otherwise
|
||||||
// if you exceed this, you need to __static_yoink("_mapanon").
|
// if you exceed this, you need to __static_yoink("_mapanon").
|
||||||
// please note that it's probably too early to call calloc()
|
// please note that it's probably too early to call calloc()
|
||||||
npassert(_weaken(_mapanon));
|
|
||||||
siz = ROUNDUP(siz, FRAMESIZE);
|
|
||||||
mem = _weaken(_mapanon)(siz);
|
mem = _weaken(_mapanon)(siz);
|
||||||
npassert(mem);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (IsAsan()) {
|
if (IsAsan()) {
|
||||||
|
@ -158,10 +154,7 @@ textstartup void __enable_tls(void) {
|
||||||
if (siz <= sizeof(__static_tls)) {
|
if (siz <= sizeof(__static_tls)) {
|
||||||
mem = __static_tls;
|
mem = __static_tls;
|
||||||
} else {
|
} else {
|
||||||
npassert(_weaken(_mapanon));
|
|
||||||
siz = ROUNDUP(siz, FRAMESIZE);
|
|
||||||
mem = _weaken(_mapanon)(siz);
|
mem = _weaken(_mapanon)(siz);
|
||||||
npassert(mem);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (IsAsan()) {
|
if (IsAsan()) {
|
||||||
|
@ -221,7 +214,9 @@ textstartup void __enable_tls(void) {
|
||||||
_pthread_list = &_pthread_static.list;
|
_pthread_list = &_pthread_static.list;
|
||||||
atomic_store_explicit(&_pthread_static.ptid, tid, memory_order_relaxed);
|
atomic_store_explicit(&_pthread_static.ptid, tid, memory_order_relaxed);
|
||||||
if (IsWindows()) {
|
if (IsWindows()) {
|
||||||
npassert((_pthread_static.semaphore = CreateSemaphore(0, 0, 1, 0)));
|
if (!(_pthread_static.semaphore = CreateSemaphore(0, 0, 1, 0))) {
|
||||||
|
notpossible;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// copy in initialized data section
|
// copy in initialized data section
|
||||||
|
|
|
@ -18,6 +18,7 @@
|
||||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||||
#include "libc/runtime/internal.h"
|
#include "libc/runtime/internal.h"
|
||||||
#include "libc/runtime/runtime.h"
|
#include "libc/runtime/runtime.h"
|
||||||
|
#include "libc/runtime/symbols.internal.h"
|
||||||
#include "libc/str/str.h"
|
#include "libc/str/str.h"
|
||||||
#include "libc/thread/tls.h"
|
#include "libc/thread/tls.h"
|
||||||
|
|
||||||
|
@ -36,6 +37,9 @@ __static_yoink("zipos");
|
||||||
* @see libc/runtime/_init.S for documentation
|
* @see libc/runtime/_init.S for documentation
|
||||||
*/
|
*/
|
||||||
textstartup int ftrace_init(void) {
|
textstartup int ftrace_init(void) {
|
||||||
|
if (strace_enabled(0) > 0) {
|
||||||
|
GetSymbolTable();
|
||||||
|
}
|
||||||
if (__intercept_flag(&__argc, __argv, "--ftrace")) {
|
if (__intercept_flag(&__argc, __argv, "--ftrace")) {
|
||||||
ftrace_install();
|
ftrace_install();
|
||||||
ftrace_enabled(+1);
|
ftrace_enabled(+1);
|
||||||
|
|
|
@ -87,8 +87,8 @@ static textwindows int Count(int c, struct DosArgv *st) {
|
||||||
// @see test/libc/dosarg_test.c
|
// @see test/libc/dosarg_test.c
|
||||||
// @see libc/runtime/ntspawn.c
|
// @see libc/runtime/ntspawn.c
|
||||||
// @note kudos to Simon Tatham for figuring out quoting behavior
|
// @note kudos to Simon Tatham for figuring out quoting behavior
|
||||||
textwindows int GetDosArgv(const char16_t *cmdline, char *buf,
|
textwindows int GetDosArgv(const char16_t *cmdline, char *buf, size_t size,
|
||||||
size_t size, char **argv, size_t max) {
|
char **argv, size_t max) {
|
||||||
bool inquote;
|
bool inquote;
|
||||||
int i, argc, slashes, quotes, ignore;
|
int i, argc, slashes, quotes, ignore;
|
||||||
static struct DosArgv st_;
|
static struct DosArgv st_;
|
||||||
|
@ -107,32 +107,6 @@ textwindows int GetDosArgv(const char16_t *cmdline, char *buf,
|
||||||
if (!st->wc) break;
|
if (!st->wc) break;
|
||||||
if (++argc < max) {
|
if (++argc < max) {
|
||||||
argv[argc - 1] = st->p < st->pe ? st->p : NULL;
|
argv[argc - 1] = st->p < st->pe ? st->p : NULL;
|
||||||
if (argc == 1) {
|
|
||||||
// windows lets you run "foo.com" without saying "./foo.com"
|
|
||||||
// which caused emacs to crash after searching for itself :(
|
|
||||||
char16_t cmd[256];
|
|
||||||
uint32_t i, j, attr;
|
|
||||||
i = j = 0;
|
|
||||||
cmd[j++] = st->wc;
|
|
||||||
for (; st->s[i]; ++i) {
|
|
||||||
if (i == 255 || st->s[i] == '/' || st->s[i] == '\\') {
|
|
||||||
goto GiveUpAddingDotSlash;
|
|
||||||
}
|
|
||||||
if (st->s[i] == ' ' || st->s[i] == '\t') {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
cmd[j++] = st->s[i];
|
|
||||||
}
|
|
||||||
cmd[j] = 0;
|
|
||||||
if (IsWindows() && //
|
|
||||||
(attr = __imp_GetFileAttributesW(cmd)) != -1u && //
|
|
||||||
!(attr & kNtFileAttributeDirectory)) {
|
|
||||||
AppendDosArgv('.', st);
|
|
||||||
AppendDosArgv('\\', st);
|
|
||||||
}
|
|
||||||
GiveUpAddingDotSlash:
|
|
||||||
donothing;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
inquote = false;
|
inquote = false;
|
||||||
while (st->wc) {
|
while (st->wc) {
|
||||||
|
|
|
@ -157,9 +157,9 @@ static bool __auto_map(int count, int align, int *res) {
|
||||||
*res + count <= FRAME(kAutomapStart + (kAutomapSize - 1));
|
*res + count <= FRAME(kAutomapStart + (kAutomapSize - 1));
|
||||||
}
|
}
|
||||||
|
|
||||||
static void *__finish_memory(void *addr, size_t size, int prot,
|
static void *__finish_memory(void *addr, size_t size, int prot, int flags,
|
||||||
int flags, int fd, int64_t off, int f,
|
int fd, int64_t off, int f, int x, int n,
|
||||||
int x, int n, struct DirectMap dm) {
|
struct DirectMap dm) {
|
||||||
if (!IsWindows() && (flags & MAP_FIXED)) {
|
if (!IsWindows() && (flags & MAP_FIXED)) {
|
||||||
if (__untrack_memories(addr, size)) {
|
if (__untrack_memories(addr, size)) {
|
||||||
__mmap_die("FIXED UNTRACK FAILED");
|
__mmap_die("FIXED UNTRACK FAILED");
|
||||||
|
@ -178,8 +178,8 @@ static void *__finish_memory(void *addr, size_t size, int prot,
|
||||||
return addr;
|
return addr;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void *__map_memory(void *addr, size_t size, int prot, int flags,
|
static void *__map_memory(void *addr, size_t size, int prot, int flags, int fd,
|
||||||
int fd, int64_t off, int f, int x, int n) {
|
int64_t off, int f, int x, int n) {
|
||||||
struct DirectMap dm;
|
struct DirectMap dm;
|
||||||
dm = sys_mmap(addr, size, prot, f, fd, off);
|
dm = sys_mmap(addr, size, prot, f, fd, off);
|
||||||
if (VERY_UNLIKELY(dm.addr == MAP_FAILED)) {
|
if (VERY_UNLIKELY(dm.addr == MAP_FAILED)) {
|
||||||
|
@ -200,9 +200,10 @@ static void *__map_memory(void *addr, size_t size, int prot, int flags,
|
||||||
* This is useful on Windows since it allows us to partially unmap or
|
* This is useful on Windows since it allows us to partially unmap or
|
||||||
* punch holes into existing mappings.
|
* punch holes into existing mappings.
|
||||||
*/
|
*/
|
||||||
static textwindows dontinline void *__map_memories(
|
static textwindows dontinline void *__map_memories(char *addr, size_t size,
|
||||||
char *addr, size_t size, int prot, int flags, int fd, int64_t off, int f,
|
int prot, int flags, int fd,
|
||||||
int x, int n) {
|
int64_t off, int f, int x,
|
||||||
|
int n) {
|
||||||
size_t i, m;
|
size_t i, m;
|
||||||
int64_t oi, sz;
|
int64_t oi, sz;
|
||||||
struct DirectMap dm;
|
struct DirectMap dm;
|
||||||
|
@ -238,8 +239,8 @@ static textwindows dontinline void *__map_memories(
|
||||||
return addr;
|
return addr;
|
||||||
}
|
}
|
||||||
|
|
||||||
inline void *__mmap_unlocked(void *addr, size_t size, int prot,
|
inline void *__mmap_unlocked(void *addr, size_t size, int prot, int flags,
|
||||||
int flags, int fd, int64_t off) {
|
int fd, int64_t off) {
|
||||||
char *p = addr;
|
char *p = addr;
|
||||||
struct DirectMap dm;
|
struct DirectMap dm;
|
||||||
size_t requested_size;
|
size_t requested_size;
|
||||||
|
@ -480,3 +481,5 @@ void *mmap(void *addr, size_t size, int prot, int flags, int fd, int64_t off) {
|
||||||
toto);
|
toto);
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
__strong_reference(mmap, mmap64);
|
||||||
|
|
|
@ -93,6 +93,7 @@ void __printargs(const char *);
|
||||||
int ftrace_install(void);
|
int ftrace_install(void);
|
||||||
int ftrace_enabled(int);
|
int ftrace_enabled(int);
|
||||||
int strace_enabled(int);
|
int strace_enabled(int);
|
||||||
|
bool strace_enter(void);
|
||||||
void _bt(const char *, ...);
|
void _bt(const char *, ...);
|
||||||
void __print_maps(void);
|
void __print_maps(void);
|
||||||
long _GetMaxFd(void);
|
long _GetMaxFd(void);
|
||||||
|
@ -141,6 +142,15 @@ long __get_minsigstksz(void) pureconst;
|
||||||
void __get_main_stack(void **, size_t *, int *);
|
void __get_main_stack(void **, size_t *, int *);
|
||||||
long __get_safe_size(long, long);
|
long __get_safe_size(long, long);
|
||||||
char *__get_tmpdir(void);
|
char *__get_tmpdir(void);
|
||||||
|
__funline int __trace_disabled(int x) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
#ifndef FTRACE
|
||||||
|
#define ftrace_enabled __trace_disabled
|
||||||
|
#endif
|
||||||
|
#ifndef SYSDEBUG
|
||||||
|
#define strace_enabled __trace_disabled
|
||||||
|
#endif
|
||||||
#endif /* _COSMO_SOURCE */
|
#endif /* _COSMO_SOURCE */
|
||||||
|
|
||||||
COSMOPOLITAN_C_END_
|
COSMOPOLITAN_C_END_
|
||||||
|
|
|
@ -20,7 +20,6 @@
|
||||||
#include "libc/calls/calls.h"
|
#include "libc/calls/calls.h"
|
||||||
#include "libc/calls/syscall-sysv.internal.h"
|
#include "libc/calls/syscall-sysv.internal.h"
|
||||||
#include "libc/dce.h"
|
#include "libc/dce.h"
|
||||||
#include "libc/errno.h"
|
|
||||||
#include "libc/nexgen32e/msr.internal.h"
|
#include "libc/nexgen32e/msr.internal.h"
|
||||||
#include "libc/nt/thread.h"
|
#include "libc/nt/thread.h"
|
||||||
#include "libc/sysv/consts/arch.h"
|
#include "libc/sysv/consts/arch.h"
|
||||||
|
@ -49,9 +48,7 @@ textstartup void __set_tls(struct CosmoTib *tib) {
|
||||||
sys_set_tls(tib);
|
sys_set_tls(tib);
|
||||||
} else if (IsXnu()) {
|
} else if (IsXnu()) {
|
||||||
// thread_fast_set_cthread_self has a weird ABI
|
// thread_fast_set_cthread_self has a weird ABI
|
||||||
int e = errno;
|
|
||||||
sys_set_tls((intptr_t)tib - 0x30);
|
sys_set_tls((intptr_t)tib - 0x30);
|
||||||
errno = e;
|
|
||||||
} else {
|
} else {
|
||||||
uint64_t val = (uint64_t)tib;
|
uint64_t val = (uint64_t)tib;
|
||||||
asm volatile("wrmsr"
|
asm volatile("wrmsr"
|
||||||
|
|
|
@ -12,7 +12,7 @@ COSMOPOLITAN_C_START_
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#define SYSLIB_MAGIC ('s' | 'l' << 8 | 'i' << 16 | 'b' << 24)
|
#define SYSLIB_MAGIC ('s' | 'l' << 8 | 'i' << 16 | 'b' << 24)
|
||||||
#define SYSLIB_VERSION 3
|
#define SYSLIB_VERSION 4
|
||||||
|
|
||||||
typedef uint64_t dispatch_time_t;
|
typedef uint64_t dispatch_time_t;
|
||||||
typedef uint64_t dispatch_semaphore_t;
|
typedef uint64_t dispatch_semaphore_t;
|
||||||
|
@ -49,6 +49,16 @@ struct Syslib {
|
||||||
int (*__pthread_attr_destroy)(void *);
|
int (*__pthread_attr_destroy)(void *);
|
||||||
int (*__pthread_attr_setstacksize)(void *, size_t);
|
int (*__pthread_attr_setstacksize)(void *, size_t);
|
||||||
int (*__pthread_attr_setguardsize)(void *, size_t);
|
int (*__pthread_attr_setguardsize)(void *, size_t);
|
||||||
|
/* v4 (2023-09-19) */
|
||||||
|
void (*__exit)(int);
|
||||||
|
long (*__close)(int);
|
||||||
|
long (*__munmap)(void *, size_t);
|
||||||
|
long (*__openat)(int, const void *, int, int);
|
||||||
|
long (*__write)(int, const void *, size_t);
|
||||||
|
long (*__read)(int, void *, size_t);
|
||||||
|
long (*__sigaction)(int, const void *, void *);
|
||||||
|
long (*__pselect)(int, void *, void *, void *, const void *, const void *);
|
||||||
|
long (*__mprotect)(void *, size_t, int);
|
||||||
};
|
};
|
||||||
|
|
||||||
extern struct Syslib *__syslib;
|
extern struct Syslib *__syslib;
|
||||||
|
|
|
@ -6,10 +6,11 @@ COSMOPOLITAN_C_START_
|
||||||
|
|
||||||
struct WinArgs {
|
struct WinArgs {
|
||||||
char *argv[4096];
|
char *argv[4096];
|
||||||
char *envp[4092];
|
char *envp[4060];
|
||||||
intptr_t auxv[2][2];
|
intptr_t auxv[2][2];
|
||||||
char argblock[ARG_MAX / 2];
|
char argblock[ARG_MAX / 2];
|
||||||
char envblock[ARG_MAX / 2];
|
char envblock[ARG_MAX / 2];
|
||||||
|
char argv0buf[256];
|
||||||
};
|
};
|
||||||
|
|
||||||
COSMOPOLITAN_C_END_
|
COSMOPOLITAN_C_END_
|
||||||
|
|
|
@ -19,6 +19,7 @@
|
||||||
#include "libc/assert.h"
|
#include "libc/assert.h"
|
||||||
#include "libc/calls/internal.h"
|
#include "libc/calls/internal.h"
|
||||||
#include "libc/calls/syscall_support-nt.internal.h"
|
#include "libc/calls/syscall_support-nt.internal.h"
|
||||||
|
#include "libc/intrin/bits.h"
|
||||||
#include "libc/intrin/weaken.h"
|
#include "libc/intrin/weaken.h"
|
||||||
#include "libc/limits.h"
|
#include "libc/limits.h"
|
||||||
#include "libc/log/libfatal.internal.h"
|
#include "libc/log/libfatal.internal.h"
|
||||||
|
@ -145,6 +146,12 @@ static abi wontreturn void WinInit(const char16_t *cmdline) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// avoid programs like emacs nagging the user to define this
|
||||||
|
char16_t var[8];
|
||||||
|
if (!__imp_GetEnvironmentVariableW(u"TERM", var, 8)) {
|
||||||
|
__imp_SetEnvironmentVariableW(u"TERM", u"xterm-256color");
|
||||||
|
}
|
||||||
|
|
||||||
// allocate memory for stack and argument block
|
// allocate memory for stack and argument block
|
||||||
_Static_assert(sizeof(struct WinArgs) % FRAMESIZE == 0, "");
|
_Static_assert(sizeof(struct WinArgs) % FRAMESIZE == 0, "");
|
||||||
_mmi.p = _mmi.s;
|
_mmi.p = _mmi.s;
|
||||||
|
@ -173,6 +180,21 @@ static abi wontreturn void WinInit(const char16_t *cmdline) {
|
||||||
int count = GetDosArgv(cmdline, wa->argblock, ARRAYLEN(wa->argblock),
|
int count = GetDosArgv(cmdline, wa->argblock, ARRAYLEN(wa->argblock),
|
||||||
wa->argv, ARRAYLEN(wa->argv));
|
wa->argv, ARRAYLEN(wa->argv));
|
||||||
|
|
||||||
|
// normalize executable path
|
||||||
|
if (wa->argv[0] && !WinFileExists(wa->argv[0])) {
|
||||||
|
unsigned i, n = 0;
|
||||||
|
while (wa->argv[0][n]) ++n;
|
||||||
|
if (n + 4 < sizeof(wa->argv0buf)) {
|
||||||
|
for (i = 0; i < n; ++i) {
|
||||||
|
wa->argv0buf[i] = wa->argv[0][i];
|
||||||
|
}
|
||||||
|
WRITE32LE(wa->argv0buf + i, READ32LE(".com"));
|
||||||
|
if (WinFileExists(wa->argv0buf)) {
|
||||||
|
wa->argv[0] = wa->argv0buf;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// munge argv so dos paths become cosmo paths
|
// munge argv so dos paths become cosmo paths
|
||||||
for (int i = 0; wa->argv[i]; ++i) {
|
for (int i = 0; wa->argv[i]; ++i) {
|
||||||
if (wa->argv[i][0] == '\\' && //
|
if (wa->argv[i][0] == '\\' && //
|
||||||
|
|
|
@ -28,6 +28,7 @@
|
||||||
#include "libc/intrin/strace.internal.h"
|
#include "libc/intrin/strace.internal.h"
|
||||||
#include "libc/sock/internal.h"
|
#include "libc/sock/internal.h"
|
||||||
#include "libc/sock/select.h"
|
#include "libc/sock/select.h"
|
||||||
|
#include "libc/sock/select.internal.h"
|
||||||
#include "libc/sysv/consts/nrlinux.h"
|
#include "libc/sysv/consts/nrlinux.h"
|
||||||
#include "libc/sysv/errfuns.h"
|
#include "libc/sysv/errfuns.h"
|
||||||
|
|
||||||
|
@ -68,6 +69,15 @@ int pselect(int nfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds,
|
||||||
} ss;
|
} ss;
|
||||||
BEGIN_CANCELLATION_POINT;
|
BEGIN_CANCELLATION_POINT;
|
||||||
|
|
||||||
|
#ifdef SYSDEBUG
|
||||||
|
fd_set old_readfds;
|
||||||
|
fd_set *old_readfds_ptr = 0;
|
||||||
|
fd_set old_writefds;
|
||||||
|
fd_set *old_writefds_ptr = 0;
|
||||||
|
fd_set old_exceptfds;
|
||||||
|
fd_set *old_exceptfds_ptr = 0;
|
||||||
|
#endif
|
||||||
|
|
||||||
if (nfds < 0) {
|
if (nfds < 0) {
|
||||||
rc = einval();
|
rc = einval();
|
||||||
} else if (IsAsan() &&
|
} else if (IsAsan() &&
|
||||||
|
@ -77,33 +87,55 @@ int pselect(int nfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds,
|
||||||
(timeout && !__asan_is_valid(timeout, sizeof(*timeout))) ||
|
(timeout && !__asan_is_valid(timeout, sizeof(*timeout))) ||
|
||||||
(sigmask && !__asan_is_valid(sigmask, sizeof(*sigmask))))) {
|
(sigmask && !__asan_is_valid(sigmask, sizeof(*sigmask))))) {
|
||||||
rc = efault();
|
rc = efault();
|
||||||
} else if (IsLinux()) {
|
|
||||||
if (timeout) {
|
|
||||||
ts = *timeout;
|
|
||||||
tsp = &ts;
|
|
||||||
} else {
|
|
||||||
tsp = 0;
|
|
||||||
}
|
|
||||||
ss.s = sigmask;
|
|
||||||
ss.n = 8;
|
|
||||||
rc = sys_pselect(nfds, readfds, writefds, exceptfds, tsp, &ss);
|
|
||||||
} else if (!IsWindows()) {
|
|
||||||
rc = sys_pselect(nfds, readfds, writefds, exceptfds,
|
|
||||||
(struct timespec *)timeout, sigmask);
|
|
||||||
} else {
|
} else {
|
||||||
if (timeout) {
|
#ifdef SYSDEBUG
|
||||||
tv.tv_sec = timeout->tv_sec;
|
if (readfds) {
|
||||||
tv.tv_usec = timeout->tv_nsec / 1000;
|
old_readfds = *readfds;
|
||||||
tvp = &tv;
|
old_readfds_ptr = &old_readfds;
|
||||||
} else {
|
}
|
||||||
tvp = 0;
|
if (writefds) {
|
||||||
|
old_writefds = *writefds;
|
||||||
|
old_writefds_ptr = &old_writefds;
|
||||||
|
}
|
||||||
|
if (exceptfds) {
|
||||||
|
old_exceptfds = *exceptfds;
|
||||||
|
old_exceptfds_ptr = &old_exceptfds;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
if (IsLinux()) {
|
||||||
|
if (timeout) {
|
||||||
|
ts = *timeout;
|
||||||
|
tsp = &ts;
|
||||||
|
} else {
|
||||||
|
tsp = 0;
|
||||||
|
}
|
||||||
|
ss.s = sigmask;
|
||||||
|
ss.n = 8;
|
||||||
|
rc = sys_pselect(nfds, readfds, writefds, exceptfds, tsp, &ss);
|
||||||
|
} else if (!IsWindows()) {
|
||||||
|
rc = sys_pselect(nfds, readfds, writefds, exceptfds,
|
||||||
|
(struct timespec *)timeout, sigmask);
|
||||||
|
} else {
|
||||||
|
if (timeout) {
|
||||||
|
tv.tv_sec = timeout->tv_sec;
|
||||||
|
tv.tv_usec = timeout->tv_nsec / 1000;
|
||||||
|
tvp = &tv;
|
||||||
|
} else {
|
||||||
|
tvp = 0;
|
||||||
|
}
|
||||||
|
rc = sys_select_nt(nfds, readfds, writefds, exceptfds, tvp, sigmask);
|
||||||
}
|
}
|
||||||
rc = sys_select_nt(nfds, readfds, writefds, exceptfds, tvp, sigmask);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
END_CANCELLATION_POINT;
|
END_CANCELLATION_POINT;
|
||||||
POLLTRACE("pselect(%d, %p, %p, %p, %s, %s) → %d% m", nfds, readfds, writefds,
|
STRACE("pselect(%d, %s → [%s], %s → [%s], %s → [%s], %s, %s) → %d% m", nfds,
|
||||||
exceptfds, DescribeTimespec(0, timeout), DescribeSigset(0, sigmask),
|
DescribeFdSet(rc, nfds, old_readfds_ptr),
|
||||||
rc);
|
DescribeFdSet(rc, nfds, readfds),
|
||||||
|
DescribeFdSet(rc, nfds, old_writefds_ptr),
|
||||||
|
DescribeFdSet(rc, nfds, writefds),
|
||||||
|
DescribeFdSet(rc, nfds, old_exceptfds_ptr),
|
||||||
|
DescribeFdSet(rc, nfds, exceptfds), //
|
||||||
|
DescribeTimespec(0, timeout), //
|
||||||
|
DescribeSigset(0, sigmask), rc);
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
|
@ -16,10 +16,12 @@
|
||||||
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
||||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||||
|
#include "libc/assert.h"
|
||||||
#include "libc/calls/bo.internal.h"
|
#include "libc/calls/bo.internal.h"
|
||||||
#include "libc/calls/internal.h"
|
#include "libc/calls/internal.h"
|
||||||
#include "libc/calls/state.internal.h"
|
#include "libc/calls/state.internal.h"
|
||||||
#include "libc/calls/struct/timeval.h"
|
#include "libc/calls/struct/timeval.h"
|
||||||
|
#include "libc/limits.h"
|
||||||
#include "libc/macros.internal.h"
|
#include "libc/macros.internal.h"
|
||||||
#include "libc/sock/select.h"
|
#include "libc/sock/select.h"
|
||||||
#include "libc/sock/sock.h"
|
#include "libc/sock/sock.h"
|
||||||
|
@ -34,11 +36,10 @@
|
||||||
int sys_select_nt(int nfds, fd_set *readfds, fd_set *writefds,
|
int sys_select_nt(int nfds, fd_set *readfds, fd_set *writefds,
|
||||||
fd_set *exceptfds, struct timeval *timeout,
|
fd_set *exceptfds, struct timeval *timeout,
|
||||||
const sigset_t *sigmask) {
|
const sigset_t *sigmask) {
|
||||||
uint64_t millis;
|
|
||||||
int i, pfds, events, fdcount;
|
int i, pfds, events, fdcount;
|
||||||
struct pollfd fds[64];
|
|
||||||
|
|
||||||
// convert bitsets to pollfd
|
// convert bitsets to pollfd
|
||||||
|
struct pollfd fds[64];
|
||||||
for (pfds = i = 0; i < nfds; ++i) {
|
for (pfds = i = 0; i < nfds; ++i) {
|
||||||
events = 0;
|
events = 0;
|
||||||
if (readfds && FD_ISSET(i, readfds)) events |= POLLIN;
|
if (readfds && FD_ISSET(i, readfds)) events |= POLLIN;
|
||||||
|
@ -57,26 +58,49 @@ int sys_select_nt(int nfds, fd_set *readfds, fd_set *writefds,
|
||||||
}
|
}
|
||||||
|
|
||||||
// convert the wait time to a word
|
// convert the wait time to a word
|
||||||
|
uint32_t millis;
|
||||||
if (!timeout) {
|
if (!timeout) {
|
||||||
millis = -1;
|
millis = -1;
|
||||||
} else {
|
} else {
|
||||||
millis = timeval_tomillis(*timeout);
|
int64_t ms = timeval_tomillis(*timeout);
|
||||||
|
if (ms < 0 || ms > UINT32_MAX) {
|
||||||
|
millis = -1u;
|
||||||
|
} else {
|
||||||
|
millis = ms;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// call our nt poll implementation
|
// call our nt poll implementation
|
||||||
BEGIN_BLOCKING_OPERATION;
|
BEGIN_BLOCKING_OPERATION;
|
||||||
fdcount = sys_poll_nt(fds, pfds, &millis, sigmask);
|
fdcount = sys_poll_nt(fds, pfds, &millis, sigmask);
|
||||||
|
unassert(fdcount < 64);
|
||||||
END_BLOCKING_OPERATION;
|
END_BLOCKING_OPERATION;
|
||||||
if (fdcount == -1) return -1;
|
if (fdcount < 0) return -1;
|
||||||
|
|
||||||
// convert pollfd back to bitsets
|
// convert pollfd back to bitsets
|
||||||
if (readfds) FD_ZERO(readfds);
|
if (readfds) FD_ZERO(readfds);
|
||||||
if (writefds) FD_ZERO(writefds);
|
if (writefds) FD_ZERO(writefds);
|
||||||
if (exceptfds) FD_ZERO(exceptfds);
|
if (exceptfds) FD_ZERO(exceptfds);
|
||||||
for (i = 0; i < fdcount; ++i) {
|
int bits = 0;
|
||||||
if (fds[i].revents & POLLIN) FD_SET(fds[i].fd, readfds);
|
for (i = 0; i < pfds; ++i) {
|
||||||
if (fds[i].revents & POLLOUT) FD_SET(fds[i].fd, writefds);
|
if (fds[i].revents & POLLIN) {
|
||||||
if (fds[i].revents & (POLLERR | POLLNVAL)) FD_SET(fds[i].fd, exceptfds);
|
if (readfds) {
|
||||||
|
FD_SET(fds[i].fd, readfds);
|
||||||
|
++bits;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (fds[i].revents & POLLOUT) {
|
||||||
|
if (writefds) {
|
||||||
|
FD_SET(fds[i].fd, writefds);
|
||||||
|
++bits;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (fds[i].revents & (POLLERR | POLLNVAL)) {
|
||||||
|
if (exceptfds) {
|
||||||
|
FD_SET(fds[i].fd, exceptfds);
|
||||||
|
++bits;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// store remaining time back in caller's timeval
|
// store remaining time back in caller's timeval
|
||||||
|
@ -84,7 +108,7 @@ int sys_select_nt(int nfds, fd_set *readfds, fd_set *writefds,
|
||||||
*timeout = timeval_frommillis(millis);
|
*timeout = timeval_frommillis(millis);
|
||||||
}
|
}
|
||||||
|
|
||||||
return fdcount;
|
return bits;
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif /* __x86_64__ */
|
#endif /* __x86_64__ */
|
||||||
|
|
|
@ -27,6 +27,8 @@
|
||||||
#include "libc/intrin/describeflags.internal.h"
|
#include "libc/intrin/describeflags.internal.h"
|
||||||
#include "libc/intrin/strace.internal.h"
|
#include "libc/intrin/strace.internal.h"
|
||||||
#include "libc/sock/internal.h"
|
#include "libc/sock/internal.h"
|
||||||
|
#include "libc/sock/select.h"
|
||||||
|
#include "libc/sock/select.internal.h"
|
||||||
#include "libc/sysv/errfuns.h"
|
#include "libc/sysv/errfuns.h"
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -88,7 +90,8 @@ int select(int nfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds,
|
||||||
}
|
}
|
||||||
END_CANCELLATION_POINT;
|
END_CANCELLATION_POINT;
|
||||||
|
|
||||||
POLLTRACE("select(%d, %p, %p, %p, [%s]) → %d% m", nfds, readfds, writefds,
|
STRACE("select(%d, [%s], [%s], [%s], [%s]) → %d% m", nfds,
|
||||||
exceptfds, DescribeTimeval(rc, tvp), rc);
|
DescribeFdSet(rc, nfds, readfds), DescribeFdSet(rc, nfds, writefds),
|
||||||
|
DescribeFdSet(rc, nfds, exceptfds), DescribeTimeval(rc, tvp), rc);
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
13
libc/sock/select.internal.h
Normal file
13
libc/sock/select.internal.h
Normal file
|
@ -0,0 +1,13 @@
|
||||||
|
#ifndef COSMOPOLITAN_LIBC_SOCK_SELECT_INTERNAL_H_
|
||||||
|
#define COSMOPOLITAN_LIBC_SOCK_SELECT_INTERNAL_H_
|
||||||
|
#include "libc/mem/alloca.h"
|
||||||
|
#include "libc/sock/select.h"
|
||||||
|
#if !(__ASSEMBLER__ + __LINKER__ + 0)
|
||||||
|
COSMOPOLITAN_C_START_
|
||||||
|
|
||||||
|
const char *DescribeFdSet(char[100], ssize_t, int, fd_set *);
|
||||||
|
#define DescribeFdSet(x, y, z) DescribeFdSet(alloca(100), x, y, z)
|
||||||
|
|
||||||
|
COSMOPOLITAN_C_END_
|
||||||
|
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
|
||||||
|
#endif /* COSMOPOLITAN_LIBC_SOCK_SELECT_INTERNAL_H_ */
|
|
@ -219,3 +219,5 @@ ssize_t sendfile(int outfd, int infd, int64_t *opt_in_out_inoffset,
|
||||||
DescribeInOutInt64(rc, opt_in_out_inoffset), uptobytes, rc);
|
DescribeInOutInt64(rc, opt_in_out_inoffset), uptobytes, rc);
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
__weak_reference(sendfile, sendfile64);
|
||||||
|
|
|
@ -12,7 +12,7 @@ int32_t __sys_poll(struct pollfd *, uint64_t, signed);
|
||||||
int sys_ppoll(struct pollfd *, size_t, const struct timespec *,
|
int sys_ppoll(struct pollfd *, size_t, const struct timespec *,
|
||||||
const sigset_t *, size_t);
|
const sigset_t *, size_t);
|
||||||
int sys_poll_metal(struct pollfd *, size_t, unsigned);
|
int sys_poll_metal(struct pollfd *, size_t, unsigned);
|
||||||
int sys_poll_nt(struct pollfd *, uint64_t, uint64_t *, const sigset_t *);
|
int sys_poll_nt(struct pollfd *, uint64_t, uint32_t *, const sigset_t *);
|
||||||
|
|
||||||
const char *DescribePollFds(char[300], ssize_t, struct pollfd *, size_t);
|
const char *DescribePollFds(char[300], ssize_t, struct pollfd *, size_t);
|
||||||
#define DescribePollFds(x, y, z) DescribePollFds(alloca(300), x, y, z)
|
#define DescribePollFds(x, y, z) DescribePollFds(alloca(300), x, y, z)
|
||||||
|
|
|
@ -22,6 +22,7 @@
|
||||||
#include "libc/calls/sig.internal.h"
|
#include "libc/calls/sig.internal.h"
|
||||||
#include "libc/calls/struct/timespec.h"
|
#include "libc/calls/struct/timespec.h"
|
||||||
#include "libc/errno.h"
|
#include "libc/errno.h"
|
||||||
|
#include "libc/intrin/weaken.h"
|
||||||
#include "libc/nt/enum/wait.h"
|
#include "libc/nt/enum/wait.h"
|
||||||
#include "libc/nt/enum/wsa.h"
|
#include "libc/nt/enum/wsa.h"
|
||||||
#include "libc/nt/errors.h"
|
#include "libc/nt/errors.h"
|
||||||
|
@ -113,6 +114,10 @@ BlockingOperation:
|
||||||
if (WSAGetOverlappedResult(f->handle, overlapped, &got, nonblock, flags)) {
|
if (WSAGetOverlappedResult(f->handle, overlapped, &got, nonblock, flags)) {
|
||||||
rc = got;
|
rc = got;
|
||||||
} else {
|
} else {
|
||||||
|
if (_weaken(pthread_testcancel_np) &&
|
||||||
|
(err = _weaken(pthread_testcancel_np)())) {
|
||||||
|
return ecanceled();
|
||||||
|
}
|
||||||
rc = -1;
|
rc = -1;
|
||||||
err = WSAGetLastError();
|
err = WSAGetLastError();
|
||||||
if (err == kNtErrorOperationAborted) {
|
if (err == kNtErrorOperationAborted) {
|
||||||
|
|
|
@ -677,3 +677,4 @@ void seekdir(DIR *dir, long tell) {
|
||||||
}
|
}
|
||||||
|
|
||||||
__weak_reference(readdir, readdir64);
|
__weak_reference(readdir, readdir64);
|
||||||
|
__weak_reference(readdir_r, readdir_r64);
|
||||||
|
|
|
@ -396,9 +396,6 @@ syscon fcntl F_OFD_GETLK 36 36 -1 -1 -1 -1 -1 -1 # listed in
|
||||||
syscon fcntl F_RDLCK 0 0 1 1 1 1 1 0 # polyfilled nt; bsd consensus
|
syscon fcntl F_RDLCK 0 0 1 1 1 1 1 0 # polyfilled nt; bsd consensus
|
||||||
syscon fcntl F_WRLCK 1 1 3 3 3 3 3 1 # polyfilled nt; bsd consensus
|
syscon fcntl F_WRLCK 1 1 3 3 3 3 3 1 # polyfilled nt; bsd consensus
|
||||||
syscon fcntl F_UNLCK 2 2 2 2 2 2 2 2 # polyfilled nt; unix consensus
|
syscon fcntl F_UNLCK 2 2 2 2 2 2 2 2 # polyfilled nt; unix consensus
|
||||||
syscon compat F_SETLK64 6 6 8 8 12 8 8 6 # polyfilled nt
|
|
||||||
syscon compat F_SETLKW64 7 7 9 9 13 9 9 7
|
|
||||||
syscon compat F_GETLK64 5 5 7 7 11 7 7 5 # polyfilled nt
|
|
||||||
|
|
||||||
syscon fcntl F_SETSIG 10 10 -1 -1 -1 -1 -1 -1
|
syscon fcntl F_SETSIG 10 10 -1 -1 -1 -1 -1 -1
|
||||||
syscon fcntl F_GETSIG 11 11 -1 -1 -1 -1 -1 -1
|
syscon fcntl F_GETSIG 11 11 -1 -1 -1 -1 -1 -1
|
||||||
|
|
|
@ -1,2 +0,0 @@
|
||||||
#include "libc/sysv/consts/syscon.internal.h"
|
|
||||||
.syscon compat,F_GETLK64,5,5,7,7,11,7,7,5
|
|
|
@ -1,2 +0,0 @@
|
||||||
#include "libc/sysv/consts/syscon.internal.h"
|
|
||||||
.syscon compat,F_SETLK64,6,6,8,8,12,8,8,6
|
|
|
@ -1,2 +0,0 @@
|
||||||
#include "libc/sysv/consts/syscon.internal.h"
|
|
||||||
.syscon compat,F_SETLKW64,7,7,9,9,13,9,9,7
|
|
|
@ -15,14 +15,12 @@ extern const int F_FULLFSYNC;
|
||||||
extern const int F_GETFD;
|
extern const int F_GETFD;
|
||||||
extern const int F_GETFL;
|
extern const int F_GETFL;
|
||||||
extern const int F_GETLEASE;
|
extern const int F_GETLEASE;
|
||||||
extern const int F_GETLK64;
|
|
||||||
extern const int F_GETLK;
|
extern const int F_GETLK;
|
||||||
extern const int F_GETNOSIGPIPE;
|
extern const int F_GETNOSIGPIPE;
|
||||||
extern const int F_GETOWN;
|
extern const int F_GETOWN;
|
||||||
extern const int F_GETPATH;
|
extern const int F_GETPATH;
|
||||||
extern const int F_GETPIPE_SZ;
|
extern const int F_GETPIPE_SZ;
|
||||||
extern const int F_GETSIG;
|
extern const int F_GETSIG;
|
||||||
extern const int F_LOCK;
|
|
||||||
extern const int F_MAXFD;
|
extern const int F_MAXFD;
|
||||||
extern const int F_NOCACHE;
|
extern const int F_NOCACHE;
|
||||||
extern const int F_NOTIFY;
|
extern const int F_NOTIFY;
|
||||||
|
@ -33,9 +31,7 @@ extern const int F_RDLCK;
|
||||||
extern const int F_SETFD;
|
extern const int F_SETFD;
|
||||||
extern const int F_SETFL;
|
extern const int F_SETFL;
|
||||||
extern const int F_SETLEASE;
|
extern const int F_SETLEASE;
|
||||||
extern const int F_SETLK64;
|
|
||||||
extern const int F_SETLK;
|
extern const int F_SETLK;
|
||||||
extern const int F_SETLKW64;
|
|
||||||
extern const int F_SETLKW;
|
extern const int F_SETLKW;
|
||||||
extern const int F_SETNOSIGPIPE;
|
extern const int F_SETNOSIGPIPE;
|
||||||
extern const int F_SETOWN;
|
extern const int F_SETOWN;
|
||||||
|
@ -61,14 +57,11 @@ COSMOPOLITAN_C_END_
|
||||||
* posix advisory locks
|
* posix advisory locks
|
||||||
* polyfilled poorly on windows
|
* polyfilled poorly on windows
|
||||||
*/
|
*/
|
||||||
#define F_SETLK F_SETLK
|
#define F_SETLK F_SETLK
|
||||||
#define F_SETLK64 F_SETLK64
|
#define F_SETLKW F_SETLKW
|
||||||
#define F_SETLKW F_SETLKW
|
#define F_GETLK F_GETLK
|
||||||
#define F_SETLKW64 F_SETLKW64
|
#define F_RDLCK F_RDLCK
|
||||||
#define F_GETLK F_GETLK
|
#define F_UNLCK F_UNLCK
|
||||||
#define F_GETLK64 F_GETLK64
|
#define F_WRLCK F_WRLCK
|
||||||
#define F_RDLCK F_RDLCK
|
|
||||||
#define F_UNLCK F_UNLCK
|
|
||||||
#define F_WRLCK F_WRLCK
|
|
||||||
|
|
||||||
#endif /* COSMOPOLITAN_LIBC_SYSV_CONSTS_F_H_ */
|
#endif /* COSMOPOLITAN_LIBC_SYSV_CONSTS_F_H_ */
|
||||||
|
|
|
@ -92,11 +92,7 @@ static void _pthread_cancel_sig(int sig, siginfo_t *si, void *arg) {
|
||||||
|
|
||||||
// punts cancellation to start of next cancellation point
|
// punts cancellation to start of next cancellation point
|
||||||
// we ensure sigthr is a pending signal in case unblocked
|
// we ensure sigthr is a pending signal in case unblocked
|
||||||
if (IsXnuSilicon()) {
|
raise(sig);
|
||||||
__syslib->__pthread_kill(_pthread_syshand(pt), sig);
|
|
||||||
} else {
|
|
||||||
sys_tkill(_pthread_tid(pt), sig, __get_tls());
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void _pthread_cancel_listen(void) {
|
static void _pthread_cancel_listen(void) {
|
||||||
|
@ -111,10 +107,7 @@ static void _pthread_cancel_listen(void) {
|
||||||
|
|
||||||
static void pthread_cancel_nt(struct PosixThread *pt, intptr_t hThread) {
|
static void pthread_cancel_nt(struct PosixThread *pt, intptr_t hThread) {
|
||||||
uint32_t old_suspend_count;
|
uint32_t old_suspend_count;
|
||||||
if (!(pt->pt_flags & PT_NOCANCEL) &&
|
if (!(pt->pt_flags & PT_NOCANCEL)) {
|
||||||
(pt->pt_flags & (PT_ASYNC | PT_MASKED))) {
|
|
||||||
pt->pt_flags |= PT_NOCANCEL;
|
|
||||||
pt->abort_errno = ECANCELED;
|
|
||||||
if ((pt->pt_flags & PT_ASYNC) &&
|
if ((pt->pt_flags & PT_ASYNC) &&
|
||||||
(old_suspend_count = SuspendThread(hThread)) != -1u) {
|
(old_suspend_count = SuspendThread(hThread)) != -1u) {
|
||||||
if (!old_suspend_count) {
|
if (!old_suspend_count) {
|
||||||
|
@ -125,13 +118,13 @@ static void pthread_cancel_nt(struct PosixThread *pt, intptr_t hThread) {
|
||||||
cpu.Rdi = (uintptr_t)PTHREAD_CANCELED;
|
cpu.Rdi = (uintptr_t)PTHREAD_CANCELED;
|
||||||
cpu.Rsp &= -16;
|
cpu.Rsp &= -16;
|
||||||
*(uintptr_t *)(cpu.Rsp -= sizeof(uintptr_t)) = cpu.Rip;
|
*(uintptr_t *)(cpu.Rsp -= sizeof(uintptr_t)) = cpu.Rip;
|
||||||
pt->abort_errno = ECANCELED;
|
|
||||||
unassert(SetThreadContext(hThread, &cpu));
|
unassert(SetThreadContext(hThread, &cpu));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
ResumeThread(hThread);
|
ResumeThread(hThread);
|
||||||
}
|
}
|
||||||
__sig_cancel(pt);
|
pt->abort_errno = ECANCELED;
|
||||||
|
__sig_cancel(pt, 0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -39,6 +39,7 @@
|
||||||
#include "libc/mem/mem.h"
|
#include "libc/mem/mem.h"
|
||||||
#include "libc/nexgen32e/crc32.h"
|
#include "libc/nexgen32e/crc32.h"
|
||||||
#include "libc/nt/runtime.h"
|
#include "libc/nt/runtime.h"
|
||||||
|
#include "libc/nt/synchronization.h"
|
||||||
#include "libc/runtime/runtime.h"
|
#include "libc/runtime/runtime.h"
|
||||||
#include "libc/runtime/stack.h"
|
#include "libc/runtime/stack.h"
|
||||||
#include "libc/runtime/syslib.internal.h"
|
#include "libc/runtime/syslib.internal.h"
|
||||||
|
@ -149,6 +150,11 @@ static errno_t pthread_create_impl(pthread_t *thread,
|
||||||
}
|
}
|
||||||
pt->start = start_routine;
|
pt->start = start_routine;
|
||||||
pt->arg = arg;
|
pt->arg = arg;
|
||||||
|
if (IsWindows()) {
|
||||||
|
if (!(pt->semaphore = CreateSemaphore(0, 0, 1, 0))) {
|
||||||
|
notpossible;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// create thread local storage memory
|
// create thread local storage memory
|
||||||
if (!(pt->tls = _mktls(&pt->tib))) {
|
if (!(pt->tls = _mktls(&pt->tib))) {
|
||||||
|
|
|
@ -17,6 +17,7 @@
|
||||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||||
#include "libc/assert.h"
|
#include "libc/assert.h"
|
||||||
|
#include "libc/atomic.h"
|
||||||
#include "libc/calls/calls.h"
|
#include "libc/calls/calls.h"
|
||||||
#include "libc/calls/cp.internal.h"
|
#include "libc/calls/cp.internal.h"
|
||||||
#include "libc/calls/internal.h"
|
#include "libc/calls/internal.h"
|
||||||
|
@ -26,12 +27,14 @@
|
||||||
#include "libc/calls/syscall-sysv.internal.h"
|
#include "libc/calls/syscall-sysv.internal.h"
|
||||||
#include "libc/dce.h"
|
#include "libc/dce.h"
|
||||||
#include "libc/errno.h"
|
#include "libc/errno.h"
|
||||||
|
#include "libc/runtime/runtime.h"
|
||||||
#include "libc/sock/internal.h"
|
#include "libc/sock/internal.h"
|
||||||
#include "libc/sysv/consts/nr.h"
|
#include "libc/sysv/consts/nr.h"
|
||||||
#include "libc/sysv/consts/o.h"
|
#include "libc/sysv/consts/o.h"
|
||||||
#include "libc/sysv/consts/sig.h"
|
#include "libc/sysv/consts/sig.h"
|
||||||
#include "libc/testlib/ezbench.h"
|
#include "libc/testlib/ezbench.h"
|
||||||
#include "libc/testlib/testlib.h"
|
#include "libc/testlib/testlib.h"
|
||||||
|
#include "libc/thread/thread.h"
|
||||||
|
|
||||||
void SetUpOnce(void) {
|
void SetUpOnce(void) {
|
||||||
testlib_enable_tmp_setup_teardown();
|
testlib_enable_tmp_setup_teardown();
|
||||||
|
@ -82,6 +85,57 @@ TEST(read_directory, eisdir) {
|
||||||
ASSERT_SYS(0, 0, close(3));
|
ASSERT_SYS(0, 0, close(3));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int fds[2];
|
||||||
|
jmp_buf jb;
|
||||||
|
pthread_t th;
|
||||||
|
atomic_bool isdone;
|
||||||
|
|
||||||
|
void *GenerateSignals(void *arg) {
|
||||||
|
while (!isdone) {
|
||||||
|
usleep(123);
|
||||||
|
pthread_kill(th, SIGINT);
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void *GenerateData(void *arg) {
|
||||||
|
for (;;) {
|
||||||
|
usleep(223);
|
||||||
|
int rc = write(fds[1], "hi", 2);
|
||||||
|
if (rc == -1 && errno == EPIPE) break;
|
||||||
|
ASSERT_EQ(2, rc);
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void OnSig(int sig) {
|
||||||
|
char buf[8];
|
||||||
|
ASSERT_SYS(0, 2, read(fds[0], buf, 8));
|
||||||
|
longjmp(jb, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(read, whatEmacsDoes) {
|
||||||
|
pthread_t sigth;
|
||||||
|
sighandler_t sh1 = signal(SIGINT, SIG_IGN);
|
||||||
|
sighandler_t sh2 = signal(SIGPIPE, SIG_IGN);
|
||||||
|
ASSERT_SYS(0, 0, pipe(fds));
|
||||||
|
ASSERT_EQ(0, pthread_create(&th, 0, GenerateData, 0));
|
||||||
|
ASSERT_EQ(0, pthread_create(&sigth, 0, GenerateSignals, 0));
|
||||||
|
for (int i = 0; i < 100; ++i) {
|
||||||
|
if (!setjmp(jb)) {
|
||||||
|
char buf[8];
|
||||||
|
ASSERT_GE(read(fds[0], buf, 8), 2);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
isdone = true;
|
||||||
|
ASSERT_SYS(0, 0, close(fds[0]));
|
||||||
|
ASSERT_EQ(0, pthread_join(sigth, 0));
|
||||||
|
ASSERT_EQ(0, pthread_join(th, 0));
|
||||||
|
ASSERT_SYS(0, 0, close(fds[1]));
|
||||||
|
signal(SIGPIPE, sh2);
|
||||||
|
signal(SIGINT, sh1);
|
||||||
|
}
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
BENCH(read, bench) {
|
BENCH(read, bench) {
|
||||||
|
|
|
@ -25,11 +25,6 @@
|
||||||
#include "libc/testlib/testlib.h"
|
#include "libc/testlib/testlib.h"
|
||||||
|
|
||||||
void SetUpOnce(void) {
|
void SetUpOnce(void) {
|
||||||
if (!IsWindows()) {
|
|
||||||
// TODO(jart): mock out that win32 i/o call
|
|
||||||
tinyprint(2, program_invocation_name, ": skipping on non-windows\n", NULL);
|
|
||||||
exit(0);
|
|
||||||
}
|
|
||||||
testlib_enable_tmp_setup_teardown();
|
testlib_enable_tmp_setup_teardown();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -197,16 +192,3 @@ TEST(GetDosArgv, cmdToil) {
|
||||||
free(argv);
|
free(argv);
|
||||||
free(buf);
|
free(buf);
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(GetDosArgv, canonicalizesCurrentDirectoryCommandPath) {
|
|
||||||
size_t max = 4;
|
|
||||||
size_t size = ARG_MAX / 2;
|
|
||||||
char *buf = malloc(size * sizeof(char));
|
|
||||||
char **argv = malloc(max * sizeof(char *));
|
|
||||||
ASSERT_SYS(0, 0, touch("emacs.com", 0755));
|
|
||||||
EXPECT_EQ(1, GetDosArgv(u"emacs.com", buf, size, argv, max));
|
|
||||||
EXPECT_STREQ(".\\emacs.com", argv[0]);
|
|
||||||
EXPECT_EQ(NULL, argv[1]);
|
|
||||||
free(argv);
|
|
||||||
free(buf);
|
|
||||||
}
|
|
||||||
|
|
|
@ -32,6 +32,7 @@
|
||||||
#include "libc/thread/thread2.h"
|
#include "libc/thread/thread2.h"
|
||||||
|
|
||||||
int pfds[2];
|
int pfds[2];
|
||||||
|
atomic_bool ready;
|
||||||
pthread_cond_t cv;
|
pthread_cond_t cv;
|
||||||
pthread_mutex_t mu;
|
pthread_mutex_t mu;
|
||||||
atomic_int gotcleanup;
|
atomic_int gotcleanup;
|
||||||
|
@ -72,6 +73,7 @@ TEST(pthread_cancel, self_deferred_waitsForCancellationPoint) {
|
||||||
|
|
||||||
void *Worker(void *arg) {
|
void *Worker(void *arg) {
|
||||||
char buf[8];
|
char buf[8];
|
||||||
|
ready = true;
|
||||||
pthread_cleanup_push(OnCleanup, 0);
|
pthread_cleanup_push(OnCleanup, 0);
|
||||||
read(pfds[0], buf, sizeof(buf));
|
read(pfds[0], buf, sizeof(buf));
|
||||||
pthread_cleanup_pop(0);
|
pthread_cleanup_pop(0);
|
||||||
|
@ -91,11 +93,12 @@ TEST(pthread_cancel, synchronous) {
|
||||||
ASSERT_SYS(0, 0, close(pfds[0]));
|
ASSERT_SYS(0, 0, close(pfds[0]));
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(pthread_cancel, synchronous_delayed) {
|
TEST(pthread_cancel, synchronous_deferred) {
|
||||||
void *rc;
|
void *rc;
|
||||||
pthread_t th;
|
pthread_t th;
|
||||||
ASSERT_SYS(0, 0, pipe(pfds));
|
ASSERT_SYS(0, 0, pipe(pfds));
|
||||||
ASSERT_EQ(0, pthread_create(&th, 0, Worker, 0));
|
ASSERT_EQ(0, pthread_create(&th, 0, Worker, 0));
|
||||||
|
while (!ready) pthread_yield();
|
||||||
ASSERT_SYS(0, 0, usleep(10));
|
ASSERT_SYS(0, 0, usleep(10));
|
||||||
EXPECT_EQ(0, pthread_cancel(th));
|
EXPECT_EQ(0, pthread_cancel(th));
|
||||||
EXPECT_EQ(0, pthread_join(th, &rc));
|
EXPECT_EQ(0, pthread_join(th, &rc));
|
||||||
|
|
4
third_party/musl/lockf.c
vendored
4
third_party/musl/lockf.c
vendored
|
@ -25,13 +25,13 @@
|
||||||
│ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. │
|
│ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. │
|
||||||
│ │
|
│ │
|
||||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||||
|
#include "third_party/musl/lockf.h"
|
||||||
#include "libc/calls/calls.h"
|
#include "libc/calls/calls.h"
|
||||||
#include "libc/calls/struct/flock.h"
|
#include "libc/calls/struct/flock.h"
|
||||||
#include "libc/calls/weirdtypes.h"
|
#include "libc/calls/weirdtypes.h"
|
||||||
#include "libc/errno.h"
|
#include "libc/errno.h"
|
||||||
#include "libc/sysv/consts/f.h"
|
#include "libc/sysv/consts/f.h"
|
||||||
#include "libc/sysv/errfuns.h"
|
#include "libc/sysv/errfuns.h"
|
||||||
#include "third_party/musl/lockf.h"
|
|
||||||
|
|
||||||
asm(".ident\t\"\\n\\n\
|
asm(".ident\t\"\\n\\n\
|
||||||
Musl libc (MIT License)\\n\
|
Musl libc (MIT License)\\n\
|
||||||
|
@ -68,3 +68,5 @@ int lockf(int fd, int op, off_t size)
|
||||||
}
|
}
|
||||||
return einval();
|
return einval();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
__weak_reference(lockf, lockf64);
|
||||||
|
|
|
@ -122,6 +122,9 @@ long g_backoff;
|
||||||
char *g_runitd;
|
char *g_runitd;
|
||||||
jmp_buf g_jmpbuf;
|
jmp_buf g_jmpbuf;
|
||||||
uint16_t g_sshport;
|
uint16_t g_sshport;
|
||||||
|
int connect_latency;
|
||||||
|
int execute_latency;
|
||||||
|
int handshake_latency;
|
||||||
char g_hostname[128];
|
char g_hostname[128];
|
||||||
uint16_t g_runitdport;
|
uint16_t g_runitdport;
|
||||||
volatile bool alarmed;
|
volatile bool alarmed;
|
||||||
|
@ -174,6 +177,7 @@ void Connect(void) {
|
||||||
LOGIFNEG1(sigaction(SIGALRM, &(struct sigaction){.sa_handler = OnAlarm}, 0));
|
LOGIFNEG1(sigaction(SIGALRM, &(struct sigaction){.sa_handler = OnAlarm}, 0));
|
||||||
DEBUGF("connecting to %s (%hhu.%hhu.%hhu.%hhu) to run %s", g_hostname, ip4[0],
|
DEBUGF("connecting to %s (%hhu.%hhu.%hhu.%hhu) to run %s", g_hostname, ip4[0],
|
||||||
ip4[1], ip4[2], ip4[3], g_prog);
|
ip4[1], ip4[2], ip4[3], g_prog);
|
||||||
|
struct timespec start = timespec_real();
|
||||||
TryAgain:
|
TryAgain:
|
||||||
alarmed = false;
|
alarmed = false;
|
||||||
LOGIFNEG1(setitimer(
|
LOGIFNEG1(setitimer(
|
||||||
|
@ -199,6 +203,7 @@ TryAgain:
|
||||||
}
|
}
|
||||||
setitimer(ITIMER_REAL, &(const struct itimerval){0}, 0);
|
setitimer(ITIMER_REAL, &(const struct itimerval){0}, 0);
|
||||||
freeaddrinfo(ai);
|
freeaddrinfo(ai);
|
||||||
|
connect_latency = timespec_tomicros(timespec_sub(timespec_real(), start));
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Send(int tmpfd, const void *output, size_t outputsize) {
|
bool Send(int tmpfd, const void *output, size_t outputsize) {
|
||||||
|
@ -309,6 +314,7 @@ bool Recv(char *p, int n) {
|
||||||
|
|
||||||
int ReadResponse(void) {
|
int ReadResponse(void) {
|
||||||
int exitcode;
|
int exitcode;
|
||||||
|
struct timespec start = timespec_real();
|
||||||
for (;;) {
|
for (;;) {
|
||||||
char msg[5];
|
char msg[5];
|
||||||
if (!Recv(msg, 5)) {
|
if (!Recv(msg, 5)) {
|
||||||
|
@ -351,6 +357,7 @@ int ReadResponse(void) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
execute_latency = timespec_tomicros(timespec_sub(timespec_real(), start));
|
||||||
close(g_sock);
|
close(g_sock);
|
||||||
return exitcode;
|
return exitcode;
|
||||||
}
|
}
|
||||||
|
@ -373,7 +380,9 @@ int RunOnHost(char *spec) {
|
||||||
for (;;) {
|
for (;;) {
|
||||||
Connect();
|
Connect();
|
||||||
EzFd(g_sock);
|
EzFd(g_sock);
|
||||||
|
struct timespec start = timespec_real();
|
||||||
err = EzHandshake2();
|
err = EzHandshake2();
|
||||||
|
handshake_latency = timespec_tomicros(timespec_sub(timespec_real(), start));
|
||||||
if (!err) break;
|
if (!err) break;
|
||||||
WARNF("handshake with %s:%d failed -0x%04x (%s)", //
|
WARNF("handshake with %s:%d failed -0x%04x (%s)", //
|
||||||
g_hostname, g_runitdport, err, GetTlsError(err));
|
g_hostname, g_runitdport, err, GetTlsError(err));
|
||||||
|
@ -381,7 +390,10 @@ int RunOnHost(char *spec) {
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
RelayRequest();
|
RelayRequest();
|
||||||
return ReadResponse();
|
int rc = ReadResponse();
|
||||||
|
kprintf("%s on %-16s %'11d µs %'8ld µs %'8ld µs\n", basename(g_prog),
|
||||||
|
g_hostname, execute_latency, connect_latency, handshake_latency);
|
||||||
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool IsParallelBuild(void) {
|
bool IsParallelBuild(void) {
|
||||||
|
|
|
@ -40,6 +40,7 @@
|
||||||
#include "libc/mem/mem.h"
|
#include "libc/mem/mem.h"
|
||||||
#include "libc/nexgen32e/crc32.h"
|
#include "libc/nexgen32e/crc32.h"
|
||||||
#include "libc/proc/posix_spawn.h"
|
#include "libc/proc/posix_spawn.h"
|
||||||
|
#include "libc/runtime/internal.h"
|
||||||
#include "libc/runtime/runtime.h"
|
#include "libc/runtime/runtime.h"
|
||||||
#include "libc/runtime/syslib.internal.h"
|
#include "libc/runtime/syslib.internal.h"
|
||||||
#include "libc/sock/sock.h"
|
#include "libc/sock/sock.h"
|
||||||
|
@ -488,7 +489,8 @@ void *ClientWorker(void *arg) {
|
||||||
// condition can happen, where etxtbsy is raised by our execve
|
// condition can happen, where etxtbsy is raised by our execve
|
||||||
// we're using o_cloexec so it's guaranteed to fix itself fast
|
// we're using o_cloexec so it's guaranteed to fix itself fast
|
||||||
// thus we use an optimistic approach to avoid expensive locks
|
// thus we use an optimistic approach to avoid expensive locks
|
||||||
sprintf(client->tmpexepath, "o/%s.XXXXXX.com", basename(origname));
|
sprintf(client->tmpexepath, "o/%s.XXXXXX.com",
|
||||||
|
basename(stripext(gc(strdup(origname)))));
|
||||||
int exefd = openatemp(AT_FDCWD, client->tmpexepath, 4, O_CLOEXEC, 0700);
|
int exefd = openatemp(AT_FDCWD, client->tmpexepath, 4, O_CLOEXEC, 0700);
|
||||||
if (exefd == -1) {
|
if (exefd == -1) {
|
||||||
WARNF("%s failed to open temporary file %#s due to %m", addrstr,
|
WARNF("%s failed to open temporary file %#s due to %m", addrstr,
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue