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:
Justine Tunney 2023-09-21 07:30:39 -07:00
parent d6c2830850
commit 0c5dd7b342
No known key found for this signature in database
GPG key ID: BE714B4575D6E328
85 changed files with 1062 additions and 671 deletions

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

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

@ -0,0 +1,31 @@
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi
Copyright 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);
}

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

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

View file

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

View file

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

View file

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

View file

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

View file

@ -0,0 +1,31 @@
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi
Copyright 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 */

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -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] == '\\' && //

View file

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

View file

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

View file

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

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

View file

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

View file

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

View file

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

View file

@ -677,3 +677,4 @@ void seekdir(DIR *dir, long tell) {
} }
__weak_reference(readdir, readdir64); __weak_reference(readdir, readdir64);
__weak_reference(readdir_r, readdir_r64);

View file

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

View file

@ -1,2 +0,0 @@
#include "libc/sysv/consts/syscon.internal.h"
.syscon compat,F_GETLK64,5,5,7,7,11,7,7,5

View file

@ -1,2 +0,0 @@
#include "libc/sysv/consts/syscon.internal.h"
.syscon compat,F_SETLK64,6,6,8,8,12,8,8,6

View file

@ -1,2 +0,0 @@
#include "libc/sysv/consts/syscon.internal.h"
.syscon compat,F_SETLKW64,7,7,9,9,13,9,9,7

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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