Make the Windows Console work better

The stdio reader thread now appears to be working recursively along
cosmopolitan subprocesses. For example, it's now possible to launch
vim.com from the unbourne.com bestline repl, thanks to hacks plus a
bug fix to select() timeouts.
This commit is contained in:
Justine Tunney 2023-09-07 16:03:19 -07:00
parent 032b1f3449
commit 8bdaddd81d
No known key found for this signature in database
GPG key ID: BE714B4575D6E328
68 changed files with 580 additions and 346 deletions

View file

@ -21,13 +21,13 @@
#include "libc/calls/termios.h" #include "libc/calls/termios.h"
#include "libc/dce.h" #include "libc/dce.h"
#include "libc/errno.h" #include "libc/errno.h"
#include "libc/fmt/fmt.h"
#include "libc/intrin/safemacros.internal.h" #include "libc/intrin/safemacros.internal.h"
#include "libc/intrin/weaken.h" #include "libc/intrin/weaken.h"
#include "libc/mem/mem.h" #include "libc/mem/mem.h"
#include "libc/runtime/runtime.h" #include "libc/runtime/runtime.h"
#include "libc/sock/sock.h" #include "libc/sock/sock.h"
#include "libc/sock/struct/pollfd.h" #include "libc/sock/struct/pollfd.h"
#include "libc/stdio/stdio.h"
#include "libc/str/str.h" #include "libc/str/str.h"
#include "libc/sysv/consts/poll.h" #include "libc/sysv/consts/poll.h"
#include "libc/sysv/errfuns.h" #include "libc/sysv/errfuns.h"

16
examples/clear.c Normal file
View file

@ -0,0 +1,16 @@
#if 0
/*─────────────────────────────────────────────────────────────────╗
To the extent possible under law, Justine Tunney has waived
all copyright and related or neighboring rights to this file,
as it is written in the following disclaimers:
http://unlicense.org/ │
http://creativecommons.org/publicdomain/zero/1.0/ │
*/
#endif
#include "libc/calls/calls.h"
// clears the teletypewriter display with empty cells
int main(int argc, char *argv[]) {
write(1, "\e[H", 3);
}

View file

@ -7,6 +7,7 @@
http://creativecommons.org/publicdomain/zero/1.0/ │ http://creativecommons.org/publicdomain/zero/1.0/ │
*/ */
#endif #endif
#include "libc/assert.h"
#include "libc/calls/calls.h" #include "libc/calls/calls.h"
#include "libc/calls/struct/sigaction.h" #include "libc/calls/struct/sigaction.h"
#include "libc/errno.h" #include "libc/errno.h"
@ -15,7 +16,9 @@
#include "libc/sock/struct/pollfd.h" #include "libc/sock/struct/pollfd.h"
#include "libc/stdio/stdio.h" #include "libc/stdio/stdio.h"
#include "libc/str/str.h" #include "libc/str/str.h"
#include "libc/sysv/consts/f.h"
#include "libc/sysv/consts/limits.h" #include "libc/sysv/consts/limits.h"
#include "libc/sysv/consts/o.h"
#include "libc/sysv/consts/poll.h" #include "libc/sysv/consts/poll.h"
#include "libc/sysv/consts/sig.h" #include "libc/sysv/consts/sig.h"
@ -45,7 +48,7 @@ int main(int argc, char *argv[]) {
// some programs are blocked on cpu rather than i/o // some programs are blocked on cpu rather than i/o
// such programs shall rely on asynchronous signals // such programs shall rely on asynchronous signals
printf("doing cpu task...\n"); printf("doing cpu task...\n");
for (volatile int i = 0; i < INT_MAX / 20; ++i) { for (volatile int i = 0; i < INT_MAX / 5; ++i) {
if (gotsig) { if (gotsig) {
printf("\rgot ctrl+c asynchronously\n"); printf("\rgot ctrl+c asynchronously\n");
exit(0); exit(0);
@ -55,7 +58,7 @@ int main(int argc, char *argv[]) {
// posix guarantees atomic i/o if you use pipe_buf sized buffers // posix guarantees atomic i/o if you use pipe_buf sized buffers
// that way we don't need to worry about things like looping and // that way we don't need to worry about things like looping and
// we can also be assured that multiple actors wont have tearing // we can also be assured that multiple actors wont have tearing
char buf[PIPE_BUF]; char buf[4];
// read data from standard input // read data from standard input
// //
@ -107,5 +110,6 @@ int main(int argc, char *argv[]) {
// operating system will send SIGPIPE if there's any problem // operating system will send SIGPIPE if there's any problem
// which kills the process by default // which kills the process by default
write(1, buf, got); write(1, buf, got);
write(1, "\n", 1);
} }
} }

View file

@ -15,7 +15,9 @@
#include "libc/fmt/fmt.h" #include "libc/fmt/fmt.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/stdio/dprintf.h" #include "libc/stdio/dprintf.h"
#include "libc/stdio/stdio.h" #include "libc/stdio/stdio.h"
#include "libc/str/str.h" #include "libc/str/str.h"
@ -26,6 +28,8 @@
#include "libc/sysv/consts/termios.h" #include "libc/sysv/consts/termios.h"
#include "libc/x/xsigaction.h" #include "libc/x/xsigaction.h"
__static_yoink("WinMainStdin");
#define CTRL(C) ((C) ^ 0b01000000) #define CTRL(C) ((C) ^ 0b01000000)
#define WRITE(FD, SLIT) write(FD, SLIT, strlen(SLIT)) #define WRITE(FD, SLIT) write(FD, SLIT, strlen(SLIT))
#define ENABLE_SAFE_PASTE "\e[?2004h" #define ENABLE_SAFE_PASTE "\e[?2004h"

View file

@ -93,6 +93,12 @@ o/$(MODE)/libc/calls/vdsofunc.greg.o: private \
-ffreestanding \ -ffreestanding \
-fno-sanitize=address -fno-sanitize=address
# we can't use magic because:
# this code is called by WinMain
o/$(MODE)/libc/calls/winstdin1.o: private \
COPTS += \
$(NO_MAGIC)
# we can't use asan because: # we can't use asan because:
# ntspawn allocates 128kb of heap memory via win32 # ntspawn allocates 128kb of heap memory via win32
o/$(MODE)/libc/calls/ntspawn.o \ o/$(MODE)/libc/calls/ntspawn.o \

View file

@ -17,12 +17,15 @@
PERFORMANCE OF THIS SOFTWARE. PERFORMANCE OF THIS SOFTWARE.
*/ */
#include "libc/calls/internal.h" #include "libc/calls/internal.h"
#include "libc/nt/enum/filetype.h"
#include "libc/nt/files.h" #include "libc/nt/files.h"
#include "libc/sysv/errfuns.h" #include "libc/sysv/errfuns.h"
textwindows int sys_fdatasync_nt(int fd) { textwindows int sys_fdatasync_nt(int fd, bool fake) {
// TODO(jart): what should we do with worker pipes? if (!__isfdopen(fd)) return ebadf();
if (!__isfdkind(fd, kFdFile)) return ebadf(); if (!__isfdkind(fd, kFdFile)) return einval();
if (GetFileType(g_fds.p[fd].handle) != kNtFileTypeDisk) return einval();
if (_check_interrupts(0)) return -1; if (_check_interrupts(0)) return -1;
if (fake) return 0;
return FlushFileBuffers(g_fds.p[fd].handle) ? 0 : -1; return FlushFileBuffers(g_fds.p[fd].handle) ? 0 : -1;
} }

View file

@ -18,39 +18,46 @@
*/ */
#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/struct/stat.h" #include "libc/calls/internal.h"
#include "libc/calls/syscall-nt.internal.h" #include "libc/calls/syscall-nt.internal.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/intrin/strace.internal.h" #include "libc/intrin/strace.internal.h"
#include "libc/runtime/runtime.h" #include "libc/runtime/runtime.h"
#include "libc/sysv/errfuns.h"
/** /**
* Blocks until kernel flushes non-metadata buffers for fd to disk. * Blocks until kernel flushes non-metadata buffers for fd to disk.
* *
* @return 0 on success, or -1 w/ errno * @return 0 on success, or -1 w/ errno
* @raise ECANCELED if thread was cancelled in masked mode
* @raise EROFS if `fd` is on a read-only filesystem e.g. /zip
* @raise EINVAL if `fd` is a special file w/o synchronization
* @raise ENOSPC if disk space was exhausted
* @raise EBADF if `fd` isn't an open file
* @raise EINTR if signal was delivered
* @raise EIO if an i/o error happened
* @see sync(), fsync(), sync_file_range() * @see sync(), fsync(), sync_file_range()
* @see __nosync to secretly disable * @see __nosync to secretly disable
* @raise ECANCELED if thread was cancelled in masked mode
* @raise EINTR if signal was delivered
* @cancellationpoint * @cancellationpoint
* @asyncsignalsafe * @asyncsignalsafe
*/ */
int fdatasync(int fd) { int fdatasync(int fd) {
int rc; int rc;
struct stat st; bool fake = __nosync == 0x5453455454534146;
if (__nosync != 0x5453455454534146) { BEGIN_CANCELLATION_POINT;
BEGIN_CANCELLATION_POINT; if (__isfdkind(fd, kFdZip)) {
if (!IsWindows()) { rc = erofs();
} else if (!IsWindows()) {
if (!fake) {
rc = sys_fdatasync(fd); rc = sys_fdatasync(fd);
} else { } else {
rc = sys_fdatasync_nt(fd); rc = sys_fsync_fake(fd);
} }
END_CANCELLATION_POINT;
STRACE("fdatasync(%d) → %d% m", fd, rc);
} else { } else {
rc = fstat(fd, &st); rc = sys_fdatasync_nt(fd, fake);
STRACE("fdatasync_fake(%d) → %d% m", fd, rc);
} }
END_CANCELLATION_POINT;
STRACE("fdatasync%s(%d) → %d% m", fake ? "_fake" : "", fd, rc);
return rc; return rc;
} }

36
libc/calls/fsync-fake.c Normal file
View file

@ -0,0 +1,36 @@
/*-*- 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/calls.h"
#include "libc/calls/struct/stat.h"
#include "libc/calls/struct/stat.internal.h"
#include "libc/sysv/consts/s.h"
#include "libc/sysv/errfuns.h"
int sys_fsync_fake(int fd) {
int rc;
struct stat st;
if (!(rc = sys_fstat(fd, &st))) {
if (S_ISSOCK(st.st_mode) || //
S_ISFIFO(st.st_mode) || //
S_ISLNK(st.st_mode)) {
rc = einval();
}
}
return rc;
}

View file

@ -18,19 +18,25 @@
*/ */
#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/struct/stat.h" #include "libc/calls/internal.h"
#include "libc/calls/syscall-nt.internal.h" #include "libc/calls/syscall-nt.internal.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/intrin/strace.internal.h" #include "libc/intrin/strace.internal.h"
#include "libc/runtime/runtime.h" #include "libc/runtime/runtime.h"
#include "libc/sysv/errfuns.h"
/** /**
* Blocks until kernel flushes buffers for fd to disk. * Blocks until kernel flushes buffers for fd to disk.
* *
* @return 0 on success, or -1 w/ errno * @return 0 on success, or -1 w/ errno
* @raise ECANCELED if thread was cancelled in masked mode * @raise ECANCELED if thread was cancelled in masked mode
* @raise EROFS if `fd` is on a read-only filesystem e.g. /zip
* @raise EINVAL if `fd` is a special file w/o synchronization
* @raise ENOSPC if disk space was exhausted
* @raise EBADF if `fd` isn't an open file
* @raise EINTR if signal was delivered * @raise EINTR if signal was delivered
* @raise EIO if an i/o error happened
* @see fdatasync(), sync_file_range() * @see fdatasync(), sync_file_range()
* @see __nosync to secretly disable * @see __nosync to secretly disable
* @cancellationpoint * @cancellationpoint
@ -38,19 +44,20 @@
*/ */
int fsync(int fd) { int fsync(int fd) {
int rc; int rc;
struct stat st; bool fake = __nosync == 0x5453455454534146;
if (__nosync != 0x5453455454534146) { BEGIN_CANCELLATION_POINT;
BEGIN_CANCELLATION_POINT; if (__isfdkind(fd, kFdZip)) {
if (!IsWindows()) { rc = erofs();
} else if (!IsWindows()) {
if (!fake) {
rc = sys_fsync(fd); rc = sys_fsync(fd);
} else { } else {
rc = sys_fdatasync_nt(fd); rc = sys_fsync_fake(fd);
} }
END_CANCELLATION_POINT;
STRACE("fsync(%d) → %d% m", fd, rc);
} else { } else {
rc = fstat(fd, &st); rc = sys_fdatasync_nt(fd, fake);
STRACE("fsync_fake(%d) → %d% m", fd, rc);
} }
END_CANCELLATION_POINT;
STRACE("fsync%s(%d) → %d% m", fake ? "_fake" : "", fd, rc);
return rc; return rc;
} }

View file

@ -24,6 +24,7 @@
#include "libc/calls/syscall_support-nt.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/macros.internal.h"
#include "libc/nt/console.h"
#include "libc/nt/createfile.h" #include "libc/nt/createfile.h"
#include "libc/nt/enum/accessmask.h" #include "libc/nt/enum/accessmask.h"
#include "libc/nt/enum/creationdisposition.h" #include "libc/nt/enum/creationdisposition.h"
@ -144,14 +145,20 @@ 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) {
if (GetFileType(g_fds.p[STDIN_FILENO].handle) == kNtFileTypeChar && uint32_t cm;
GetFileType(g_fds.p[STDOUT_FILENO].handle) == kNtFileTypeChar) { 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 // this is an ugly hack that works for observed usage patterns
g_fds.p[fd].handle = g_fds.p[STDIN_FILENO].handle; g_fds.p[fd].handle = g_fds.p[input].handle;
g_fds.p[fd].extra = g_fds.p[STDOUT_FILENO].handle; g_fds.p[fd].extra = g_fds.p[output].handle;
g_fds.p[STDOUT_FILENO].dontclose = true;
g_fds.p[STDIN_FILENO].dontclose = true;
g_fds.p[fd].dontclose = true; 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( } else if ((g_fds.p[fd].handle = sys_open_nt_impl(
dirfd, mp->conin, (flags & ~O_ACCMODE) | O_RDONLY, mode, dirfd, mp->conin, (flags & ~O_ACCMODE) | O_RDONLY, mode,
kNtFileFlagOverlapped)) != -1) { kNtFileFlagOverlapped)) != -1) {
@ -187,7 +194,7 @@ textwindows int sys_open_nt(int dirfd, const char *file, uint32_t flags,
ssize_t rc; ssize_t rc;
__fds_lock(); __fds_lock();
if ((rc = fd = __reservefd_unlocked(-1)) != -1) { if ((rc = fd = __reservefd_unlocked(-1)) != -1) {
if ((flags & O_ACCMODE) == O_RDWR && !strcmp(file, kNtMagicPaths.devtty)) { if (!strcmp(file, kNtMagicPaths.devtty)) {
rc = sys_open_nt_console(dirfd, &kNtMagicPaths, flags, mode, fd); rc = sys_open_nt_console(dirfd, &kNtMagicPaths, flags, mode, fd);
} else { } else {
rc = sys_open_nt_file(dirfd, file, flags, mode, fd); rc = sys_open_nt_file(dirfd, file, flags, mode, fd);

View file

@ -74,7 +74,7 @@ ssize_t pread(int fd, void *buf, size_t size, int64_t offset) {
} else if (__isfdkind(fd, kFdSocket)) { } else if (__isfdkind(fd, kFdSocket)) {
rc = espipe(); rc = espipe();
} else if (__isfdkind(fd, kFdFile)) { } else if (__isfdkind(fd, kFdFile)) {
rc = sys_read_nt(&g_fds.p[fd], (struct iovec[]){{buf, size}}, 1, offset); rc = sys_read_nt(fd, (struct iovec[]){{buf, size}}, 1, offset);
} else { } else {
rc = ebadf(); rc = ebadf();
} }

View file

@ -62,7 +62,7 @@ static ssize_t Preadv(int fd, struct iovec *iov, int iovlen, int64_t off) {
if (g_fds.p[fd].kind == kFdSocket) { if (g_fds.p[fd].kind == kFdSocket) {
return espipe(); return espipe();
} else { } else {
return sys_read_nt(g_fds.p + fd, iov, iovlen, off); return sys_read_nt(fd, iov, iovlen, off);
} }
} else { } else {
return ebadf(); return ebadf();

View file

@ -41,6 +41,7 @@
#include "libc/nt/struct/overlapped.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/str/str.h" #include "libc/str/str.h"
#include "libc/sysv/consts/o.h" #include "libc/sysv/consts/o.h"
#include "libc/sysv/consts/sicode.h" #include "libc/sysv/consts/sicode.h"
@ -48,19 +49,24 @@
#include "libc/sysv/consts/termios.h" #include "libc/sysv/consts/termios.h"
#include "libc/sysv/errfuns.h" #include "libc/sysv/errfuns.h"
__static_yoink("WinMainStdin");
#ifdef __x86_64__ #ifdef __x86_64__
__msabi extern typeof(CloseHandle) *const __imp_CloseHandle;
static textwindows void sys_read_nt_abort(int64_t handle, static textwindows void sys_read_nt_abort(int64_t handle,
struct NtOverlapped *overlapped) { struct NtOverlapped *overlapped) {
unassert(CancelIoEx(handle, overlapped) || unassert(CancelIoEx(handle, overlapped) ||
GetLastError() == kNtErrorNotFound); GetLastError() == kNtErrorNotFound);
} }
static textwindows ssize_t sys_read_nt_impl(struct Fd *fd, void *data, textwindows ssize_t sys_read_nt_impl(int fd, void *data, size_t size,
size_t size, int64_t offset) { int64_t offset) {
// perform the read i/o operation // perform the read i/o operation
bool32 ok; bool32 ok;
struct Fd *f;
uint32_t got; uint32_t got;
int filetype; int filetype;
int64_t handle; int64_t handle;
@ -69,27 +75,28 @@ static textwindows ssize_t sys_read_nt_impl(struct Fd *fd, void *data,
uint32_t targetsize; uint32_t targetsize;
bool is_console_input; bool is_console_input;
int abort_errno = EAGAIN; int abort_errno = EAGAIN;
f = g_fds.p + fd;
StartOver: StartOver:
size = MIN(size, 0x7ffff000); size = MIN(size, 0x7ffff000);
handle = __resolve_stdin_handle(fd->handle); handle = __resolve_stdin_handle(f->handle);
filetype = GetFileType(handle); filetype = GetFileType(handle);
is_console_input = g_fds.stdin.handle ? fd->handle == g_fds.stdin.handle is_console_input = g_fds.stdin.handle ? f->handle == g_fds.stdin.handle
: fd->handle == g_fds.p[0].handle; : f->handle == g_fds.p[0].handle;
// the caller might be reading a single byte at a time. but we need to // the caller might be reading a single byte at a time. but we need to
// be able to munge three bytes into just 1 e.g. "\342\220\200" → "\0" // be able to munge three bytes into just 1 e.g. "\342\220\200" → "\0"
if (size && fd->buflen) { if (size && f->buflen) {
ReturnDataFromBuffer: ReturnDataFromBuffer:
got = MIN(size, fd->buflen); got = MIN(size, f->buflen);
remain = fd->buflen - got; remain = f->buflen - got;
if (got) memcpy(data, fd->buf, got); if (got) memcpy(data, f->buf, got);
if (remain) memmove(fd->buf, fd->buf + got, remain); if (remain) memmove(f->buf, f->buf + got, remain);
fd->buflen = remain; f->buflen = remain;
return got; return got;
} }
if (is_console_input && size && size < 3 && (__ttymagic & kFdTtyMunging)) { if (is_console_input && size && size < 3 && (__ttymagic & kFdTtyMunging)) {
targetdata = fd->buf; targetdata = f->buf;
targetsize = sizeof(fd->buf); targetsize = sizeof(f->buf);
} else { } else {
targetdata = data; targetdata = data;
targetsize = size; targetsize = size;
@ -106,12 +113,11 @@ StartOver:
// since for overlapped i/o, we always use GetOverlappedResult // since for overlapped i/o, we always use GetOverlappedResult
ok = ReadFile(handle, targetdata, targetsize, 0, &overlap); ok = ReadFile(handle, targetdata, targetsize, 0, &overlap);
if (!ok && GetLastError() == kNtErrorIoPending) { if (!ok && GetLastError() == kNtErrorIoPending) {
TryAgain:
// the i/o operation is in flight; blocking is unavoidable // the i/o operation is in flight; blocking is unavoidable
// if we're in a non-blocking mode, then immediately abort // if we're in a non-blocking mode, then immediately abort
// if an interrupt is pending then we abort before waiting // if an interrupt is pending then we abort before waiting
// otherwise wait for i/o periodically checking interrupts // otherwise wait for i/o periodically checking interrupts
if (fd->flags & O_NONBLOCK) { if (f->flags & O_NONBLOCK) {
sys_read_nt_abort(handle, &overlap); sys_read_nt_abort(handle, &overlap);
} else if (_check_interrupts(kSigOpRestartable)) { } else if (_check_interrupts(kSigOpRestartable)) {
Interrupted: Interrupted:
@ -120,6 +126,9 @@ StartOver:
} else { } else {
for (;;) { for (;;) {
uint32_t i; uint32_t i;
if (g_fds.stdin.inisem) {
ReleaseSemaphore(g_fds.stdin.inisem, 1, 0);
}
i = WaitForSingleObject(overlap.hEvent, __SIG_POLLING_INTERVAL_MS); i = WaitForSingleObject(overlap.hEvent, __SIG_POLLING_INTERVAL_MS);
if (i == kNtWaitTimeout) { if (i == kNtWaitTimeout) {
if (_check_interrupts(kSigOpRestartable)) { if (_check_interrupts(kSigOpRestartable)) {
@ -138,10 +147,11 @@ StartOver:
// for windows to acknowledge that it's done using that memory // for windows to acknowledge that it's done using that memory
ok = GetOverlappedResult(handle, &overlap, &got, true); ok = GetOverlappedResult(handle, &overlap, &got, true);
if (!ok && GetLastError() == kNtErrorIoIncomplete) { if (!ok && GetLastError() == kNtErrorIoIncomplete) {
goto TryAgain; kprintf("you complete me\n");
ok = true;
} }
} }
CloseHandle(overlap.hEvent); __imp_CloseHandle(overlap.hEvent);
} else { } else {
ok = false; ok = false;
} }
@ -153,7 +163,7 @@ StartOver:
int64_t position; int64_t position;
// save file pointer which windows clobbers, even for overlapped i/o // save file pointer which windows clobbers, even for overlapped i/o
if (!SetFilePointerEx(handle, 0, &position, SEEK_CUR)) { if (!SetFilePointerEx(handle, 0, &position, SEEK_CUR)) {
return __winerr(); // fd probably isn't seekable? return __winerr(); // f probably isn't seekable?
} }
struct NtOverlapped overlap = {0}; struct NtOverlapped overlap = {0};
overlap.Pointer = (void *)(uintptr_t)offset; overlap.Pointer = (void *)(uintptr_t)offset;
@ -179,11 +189,11 @@ StartOver:
} }
} }
if (__ttymagic & kFdTtyEchoing) { if (__ttymagic & kFdTtyEchoing) {
_weaken(__echo_terminal_input)(fd, targetdata, got); _weaken(__echo_terminal_input)(f, targetdata, got);
} }
} }
if (targetdata != data) { if (targetdata != data) {
fd->buflen = got; f->buflen = got;
goto ReturnDataFromBuffer; goto ReturnDataFromBuffer;
} }
return got; return got;
@ -204,8 +214,8 @@ StartOver:
} }
} }
textwindows ssize_t sys_read_nt(struct Fd *fd, const struct iovec *iov, textwindows ssize_t sys_read_nt(int fd, const struct iovec *iov, size_t iovlen,
size_t iovlen, int64_t opt_offset) { int64_t opt_offset) {
ssize_t rc; ssize_t rc;
size_t i, total; size_t i, total;
if (opt_offset < -1) return einval(); if (opt_offset < -1) return einval();

View file

@ -80,9 +80,9 @@ ssize_t read(int fd, void *buf, size_t size) {
} else if (fd >= g_fds.n) { } else if (fd >= g_fds.n) {
rc = ebadf(); rc = ebadf();
} else if (IsMetal()) { } else if (IsMetal()) {
rc = sys_readv_metal(g_fds.p + fd, &(struct iovec){buf, size}, 1); rc = sys_readv_metal(fd, &(struct iovec){buf, size}, 1);
} else if (IsWindows()) { } else if (IsWindows()) {
rc = sys_readv_nt(g_fds.p + fd, &(struct iovec){buf, size}, 1); rc = sys_readv_nt(fd, &(struct iovec){buf, size}, 1);
} else { } else {
rc = enosys(); rc = enosys();
} }

View file

@ -16,6 +16,7 @@
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/internal.h"
#include "libc/calls/metalfile.internal.h" #include "libc/calls/metalfile.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"
@ -28,11 +29,11 @@
#ifdef __x86_64__ #ifdef __x86_64__
ssize_t sys_readv_metal(struct Fd *fd, const struct iovec *iov, int iovlen) { ssize_t sys_readv_metal(int fd, const struct iovec *iov, int iovlen) {
int i; int i;
size_t got, toto; size_t got, toto;
struct MetalFile *file; struct MetalFile *file;
switch (fd->kind) { switch (g_fds.p[fd].kind) {
case kFdConsole: case kFdConsole:
/* /*
* The VGA teletypewriter code may wish to send out "status report" * The VGA teletypewriter code may wish to send out "status report"
@ -40,14 +41,14 @@ ssize_t sys_readv_metal(struct Fd *fd, const struct iovec *iov, int iovlen) {
* Read & return these if they are available. * Read & return these if they are available.
*/ */
if (_weaken(sys_readv_vga)) { if (_weaken(sys_readv_vga)) {
ssize_t res = _weaken(sys_readv_vga)(fd, iov, iovlen); ssize_t res = _weaken(sys_readv_vga)(g_fds.p + fd, iov, iovlen);
if (res > 0) return res; if (res > 0) return res;
} }
/* fall through */ /* fall through */
case kFdSerial: case kFdSerial:
return sys_readv_serial(fd, iov, iovlen); return sys_readv_serial(fd, iov, iovlen);
case kFdFile: case kFdFile:
file = (struct MetalFile *)fd->handle; file = (struct MetalFile *)g_fds.p[fd].handle;
for (toto = i = 0; i < iovlen && file->pos < file->size; ++i) { for (toto = i = 0; i < iovlen && file->pos < file->size; ++i) {
got = MIN(iov[i].iov_len, file->size - file->pos); got = MIN(iov[i].iov_len, file->size - file->pos);
if (got) memcpy(iov[i].iov_base, file->base, got); if (got) memcpy(iov[i].iov_base, file->base, got);

View file

@ -16,6 +16,7 @@
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/internal.h"
#include "libc/calls/struct/iovec.internal.h" #include "libc/calls/struct/iovec.internal.h"
#include "libc/intrin/weaken.h" #include "libc/intrin/weaken.h"
#include "libc/sock/internal.h" #include "libc/sock/internal.h"
@ -24,9 +25,8 @@
#ifdef __x86_64__ #ifdef __x86_64__
textwindows ssize_t sys_readv_nt(struct Fd *fd, const struct iovec *iov, textwindows ssize_t sys_readv_nt(int fd, const struct iovec *iov, int iovlen) {
int iovlen) { switch (g_fds.p[fd].kind) {
switch (fd->kind) {
case kFdFile: case kFdFile:
case kFdConsole: case kFdConsole:
return sys_read_nt(fd, iov, iovlen, -1); return sys_read_nt(fd, iov, iovlen, -1);

View file

@ -16,14 +16,15 @@
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/internal.h"
#include "libc/calls/struct/fd.internal.h" #include "libc/calls/struct/fd.internal.h"
#include "libc/calls/struct/iovec.internal.h" #include "libc/calls/struct/iovec.internal.h"
#include "libc/nexgen32e/uart.internal.h" #include "libc/nexgen32e/uart.internal.h"
#include "libc/runtime/pc.internal.h" #include "libc/runtime/pc.internal.h"
#ifdef __x86_64__ #ifdef __x86_64__
static bool IsDataAvailable(struct Fd *fd) { static bool IsDataAvailable(int fd) {
return inb(fd->handle + UART_LSR) & UART_TTYDA; return inb(g_fds.p[fd].handle + UART_LSR) & UART_TTYDA;
} }
static int GetFirstIov(const struct iovec *iov, int iovlen) { static int GetFirstIov(const struct iovec *iov, int iovlen) {
@ -36,13 +37,13 @@ static int GetFirstIov(const struct iovec *iov, int iovlen) {
return -1; return -1;
} }
ssize_t sys_readv_serial(struct Fd *fd, const struct iovec *iov, int iovlen) { ssize_t sys_readv_serial(int fd, const struct iovec *iov, int iovlen) {
size_t i; size_t i;
if ((i = GetFirstIov(iov, iovlen)) != -1) { if ((i = GetFirstIov(iov, iovlen)) != -1) {
while (!IsDataAvailable(fd)) { while (!IsDataAvailable(fd)) {
__builtin_ia32_pause(); __builtin_ia32_pause();
} }
((char *)iov[i].iov_base)[0] = inb(fd->handle); ((char *)iov[i].iov_base)[0] = inb(g_fds.p[fd].handle);
return 1; return 1;
} else { } else {
return 0; return 0;

View file

@ -68,9 +68,9 @@ ssize_t readv(int fd, const struct iovec *iov, int iovlen) {
} else if (fd >= g_fds.n) { } else if (fd >= g_fds.n) {
rc = ebadf(); rc = ebadf();
} else if (IsMetal()) { } else if (IsMetal()) {
rc = sys_readv_metal(g_fds.p + fd, iov, iovlen); rc = sys_readv_metal(fd, iov, iovlen);
} else if (IsWindows()) { } else if (IsWindows()) {
rc = sys_readv_nt(g_fds.p + fd, iov, iovlen); rc = sys_readv_nt(fd, iov, iovlen);
} else { } else {
rc = enosys(); rc = enosys();
} }

View file

@ -12,10 +12,10 @@ int64_t sys_pwritev(int, const struct iovec *, int, int64_t, int64_t);
int64_t sys_readv(int32_t, const struct iovec *, int32_t); int64_t sys_readv(int32_t, const struct iovec *, int32_t);
int64_t sys_vmsplice(int, const struct iovec *, int64_t, uint32_t); int64_t sys_vmsplice(int, const struct iovec *, int64_t, uint32_t);
int64_t sys_writev(int32_t, const struct iovec *, int32_t); int64_t sys_writev(int32_t, const struct iovec *, int32_t);
ssize_t sys_read_nt(struct Fd *, const struct iovec *, size_t, int64_t); ssize_t sys_read_nt(int, const struct iovec *, size_t, int64_t);
ssize_t sys_readv_metal(struct Fd *, const struct iovec *, int); ssize_t sys_readv_metal(int, const struct iovec *, int);
ssize_t sys_readv_nt(struct Fd *, const struct iovec *, int); ssize_t sys_readv_nt(int, const struct iovec *, int);
ssize_t sys_readv_serial(struct Fd *, const struct iovec *, int); ssize_t sys_readv_serial(int, const struct iovec *, int);
ssize_t sys_write_nt(int, const struct iovec *, size_t, ssize_t); ssize_t sys_write_nt(int, const struct iovec *, size_t, ssize_t);
ssize_t sys_writev_metal(struct Fd *, const struct iovec *, int); ssize_t sys_writev_metal(struct Fd *, const struct iovec *, int);
ssize_t sys_writev_nt(int, const struct iovec *, int); ssize_t sys_writev_nt(int, const struct iovec *, int);

View file

@ -31,6 +31,7 @@ struct timeval timeval_sub(struct timeval, struct timeval) pureconst;
struct timeval timeval_subz(struct timeval, struct timeval) pureconst; struct timeval timeval_subz(struct timeval, struct timeval) pureconst;
int64_t timeval_toseconds(struct timeval); int64_t timeval_toseconds(struct timeval);
int64_t timeval_tomicros(struct timeval); int64_t timeval_tomicros(struct timeval);
int64_t timeval_tomillis(struct timeval);
struct timeval timespec_totimeval(struct timespec) pureconst; struct timeval timespec_totimeval(struct timespec) pureconst;
static inline struct timeval timeval_fromseconds(int64_t __x) { static inline struct timeval timeval_fromseconds(int64_t __x) {
return (struct timeval){__x}; return (struct timeval){__x};

View file

@ -14,9 +14,10 @@ int sys_fadvise_nt(int, uint64_t, uint64_t, int);
int sys_fchdir_nt(int); int sys_fchdir_nt(int);
int sys_fchmodat_nt(int, const char *, uint32_t, int); int sys_fchmodat_nt(int, const char *, uint32_t, int);
int sys_fcntl_nt(int, int, uintptr_t); int sys_fcntl_nt(int, int, uintptr_t);
int sys_fdatasync_nt(int); int sys_fdatasync_nt(int, bool);
int sys_flock_nt(int, int); int sys_flock_nt(int, int);
int sys_fork_nt(uint32_t); int sys_fork_nt(uint32_t);
int sys_fsync_fake(int);
int sys_ftruncate_nt(int64_t, uint64_t); int sys_ftruncate_nt(int64_t, uint64_t);
int sys_getloadavg_nt(double *, int); int sys_getloadavg_nt(double *, int);
int sys_getppid_nt(void); int sys_getppid_nt(void);
@ -36,6 +37,7 @@ int sys_sync_nt(void);
int sys_truncate_nt(const char *, uint64_t); int sys_truncate_nt(const char *, uint64_t);
int sys_unlinkat_nt(int, const char *, int); int sys_unlinkat_nt(int, const char *, int);
int64_t sys_lseek_nt(int, int64_t, int); int64_t sys_lseek_nt(int, int64_t, int);
ssize_t sys_read_nt_impl(int, void *, size_t, int64_t);
ssize_t sys_readlinkat_nt(int, const char *, char *, size_t); ssize_t sys_readlinkat_nt(int, const char *, char *, size_t);
COSMOPOLITAN_C_END_ COSMOPOLITAN_C_END_

View file

@ -23,10 +23,14 @@
#include "libc/calls/syscall_support-nt.internal.h" #include "libc/calls/syscall_support-nt.internal.h"
#include "libc/calls/termios.h" #include "libc/calls/termios.h"
#include "libc/dce.h" #include "libc/dce.h"
#include "libc/errno.h"
#include "libc/fmt/itoa.h" #include "libc/fmt/itoa.h"
#include "libc/intrin/strace.internal.h" #include "libc/intrin/strace.internal.h"
#include "libc/mem/alloca.h" #include "libc/mem/alloca.h"
#include "libc/nt/comms.h" #include "libc/nt/comms.h"
#include "libc/nt/console.h"
#include "libc/sysv/consts/fileno.h"
#include "libc/sysv/consts/o.h"
#include "libc/sysv/consts/termios.h" #include "libc/sysv/consts/termios.h"
#include "libc/sysv/errfuns.h" #include "libc/sysv/errfuns.h"
@ -45,18 +49,48 @@ static const char *DescribeFlush(char buf[12], int action) {
} }
static dontinline textwindows int sys_tcflush_nt(int fd, int queue) { static dontinline textwindows int sys_tcflush_nt(int fd, int queue) {
bool32 ok; if (!__isfdopen(fd)) {
int64_t h; return ebadf();
if (!__isfdopen(fd)) return ebadf();
ok = true;
h = g_fds.p[fd].handle;
if (queue == TCIFLUSH || queue == TCIOFLUSH) {
ok &= !!PurgeComm(h, kNtPurgeRxclear);
} }
if (queue == TCOFLUSH || queue == TCIOFLUSH) { int64_t hConin;
ok &= !!PurgeComm(h, kNtPurgeTxclear); if (__isfdkind(fd, kFdConsole)) {
hConin = g_fds.p[fd].handle;
} else if (fd == 0 || fd == 1 || fd == 2) {
hConin = g_fds.p[(fd = 0)].handle;
} else {
return enotty();
} }
return ok ? 0 : __winerr(); uint32_t inmode;
if (!GetConsoleMode(hConin, &inmode)) {
return enotty();
}
if (queue == TCOFLUSH) {
return 0; // windows console output is never buffered
}
FlushConsoleInputBuffer(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;
} }
/** /**
@ -77,7 +111,9 @@ static dontinline textwindows int sys_tcflush_nt(int fd, int queue) {
*/ */
int tcflush(int fd, int queue) { int tcflush(int fd, int queue) {
int rc; int rc;
if (fd < g_fds.n && g_fds.p[fd].kind == kFdZip) { if (queue != TCIFLUSH && queue != TCOFLUSH && queue != TCIOFLUSH) {
rc = einval();
} else if (fd < g_fds.n && g_fds.p[fd].kind == kFdZip) {
rc = enotty(); rc = enotty();
} else if (IsLinux()) { } else if (IsLinux()) {
rc = sys_ioctl(fd, TCFLSH, queue); rc = sys_ioctl(fd, TCFLSH, queue);

View file

@ -22,79 +22,87 @@
#include "libc/calls/struct/termios.h" #include "libc/calls/struct/termios.h"
#include "libc/calls/ttydefaults.h" #include "libc/calls/ttydefaults.h"
#include "libc/intrin/nomultics.internal.h" #include "libc/intrin/nomultics.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/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"
#include "libc/sysv/consts/fileno.h"
#include "libc/sysv/consts/o.h" #include "libc/sysv/consts/o.h"
#include "libc/sysv/consts/termios.h" #include "libc/sysv/consts/termios.h"
#include "libc/sysv/errfuns.h" #include "libc/sysv/errfuns.h"
textwindows int tcgetattr_nt(int ignored, struct termios *tio) { textwindows int tcgetattr_nt(int fd, struct termios *tio) {
int64_t in, out; int64_t hInput, hOutput;
bool32 inok, outok; uint32_t inmode, outmode;
uint32_t inmode = 0, outmode = 0;
inok = GetConsoleMode((in = __getfdhandleactual(0)), &inmode);
outok = GetConsoleMode((out = __getfdhandleactual(1)), &outmode);
if (inok | outok) {
bzero(tio, sizeof(*tio));
tio->c_cc[VMIN] = 1; if (__isfdkind(fd, kFdConsole)) {
tio->c_cc[VINTR] = __vintr; hInput = g_fds.p[fd].handle;
tio->c_cc[VQUIT] = __vquit; hOutput = g_fds.p[fd].extra;
tio->c_cc[VERASE] = CTRL('?'); } else if (fd == STDIN_FILENO || //
tio->c_cc[VWERASE] = CTRL('W'); fd == STDOUT_FILENO || //
tio->c_cc[VKILL] = CTRL('U'); fd == STDERR_FILENO) {
tio->c_cc[VEOF] = CTRL('D'); hInput = g_fds.p[STDIN_FILENO].handle;
tio->c_cc[VMIN] = CTRL('A'); hOutput = g_fds.p[MAX(STDOUT_FILENO, fd)].handle;
tio->c_cc[VSTART] = _POSIX_VDISABLE;
tio->c_cc[VSTOP] = _POSIX_VDISABLE;
tio->c_cc[VSUSP] = _POSIX_VDISABLE;
tio->c_cc[VREPRINT] = CTRL('R');
tio->c_cc[VDISCARD] = CTRL('O');
tio->c_cc[VLNEXT] = CTRL('V');
tio->c_iflag = IUTF8;
tio->c_lflag = ECHOE;
tio->c_cflag = CS8 | CREAD;
tio->_c_ispeed = B38400;
tio->_c_ospeed = B38400;
if (inok) {
if (inmode & kNtEnableLineInput) {
tio->c_lflag |= ICANON;
}
// kNtEnableEchoInput only works with kNtEnableLineInput enabled.
if ((inmode & kNtEnableEchoInput) || (__ttymagic & kFdTtyEchoing)) {
tio->c_lflag |= ECHO;
}
// The Windows console itself always echos control codes as ASCII.
if ((inmode & kNtEnableEchoInput) || !(__ttymagic & kFdTtyEchoRaw)) {
tio->c_lflag |= ECHOCTL;
}
if (!(__ttymagic & kFdTtyNoCr2Nl)) {
tio->c_iflag |= ICRNL;
}
if (!(__ttymagic & kFdTtyNoIsigs)) {
tio->c_lflag |= ISIG;
}
if ((inmode & kNtEnableProcessedInput) || (__ttymagic & kFdTtyMunging)) {
tio->c_lflag |= IEXTEN;
}
}
if (outok) {
if (outmode & kNtEnableProcessedOutput) {
tio->c_oflag |= OPOST;
}
if (!(outmode & kNtDisableNewlineAutoReturn)) {
tio->c_oflag |= OPOST | ONLCR;
}
}
return 0;
} else { } else {
return enotty(); return enotty();
} }
if (!GetConsoleMode(hInput, &inmode) || !GetConsoleMode(hOutput, &outmode)) {
return enotty();
}
bzero(tio, sizeof(*tio));
tio->c_cc[VMIN] = 1;
tio->c_cc[VINTR] = __vintr;
tio->c_cc[VQUIT] = __vquit;
tio->c_cc[VERASE] = CTRL('?');
tio->c_cc[VWERASE] = CTRL('W');
tio->c_cc[VKILL] = CTRL('U');
tio->c_cc[VEOF] = CTRL('D');
tio->c_cc[VMIN] = CTRL('A');
tio->c_cc[VSTART] = _POSIX_VDISABLE;
tio->c_cc[VSTOP] = _POSIX_VDISABLE;
tio->c_cc[VSUSP] = _POSIX_VDISABLE;
tio->c_cc[VREPRINT] = CTRL('R');
tio->c_cc[VDISCARD] = CTRL('O');
tio->c_cc[VLNEXT] = CTRL('V');
tio->c_iflag = IUTF8;
tio->c_lflag = ECHOE;
tio->c_cflag = CS8 | CREAD;
tio->_c_ispeed = B38400;
tio->_c_ospeed = B38400;
if (inmode & kNtEnableLineInput) {
tio->c_lflag |= ICANON;
}
// kNtEnableEchoInput only works with kNtEnableLineInput enabled.
if ((inmode & kNtEnableEchoInput) || (__ttymagic & kFdTtyEchoing)) {
tio->c_lflag |= ECHO;
}
// The Windows console itself always echos control codes as ASCII.
if ((inmode & kNtEnableEchoInput) || !(__ttymagic & kFdTtyEchoRaw)) {
tio->c_lflag |= ECHOCTL;
}
if (!(__ttymagic & kFdTtyNoCr2Nl)) {
tio->c_iflag |= ICRNL;
}
if (!(__ttymagic & kFdTtyNoIsigs)) {
tio->c_lflag |= ISIG;
}
if ((inmode & kNtEnableProcessedInput) || (__ttymagic & kFdTtyMunging)) {
tio->c_lflag |= IEXTEN;
}
if (outmode & kNtEnableProcessedOutput) {
tio->c_oflag |= OPOST;
}
if (!(outmode & kNtDisableNewlineAutoReturn)) {
tio->c_oflag |= OPOST | ONLCR;
}
return 0;
} }

View file

@ -19,12 +19,15 @@
#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/struct/metatermios.internal.h" #include "libc/calls/struct/metatermios.internal.h"
#include "libc/calls/syscall-nt.internal.h"
#include "libc/calls/termios.h"
#include "libc/calls/termios.internal.h" #include "libc/calls/termios.internal.h"
#include "libc/calls/ttydefaults.h" #include "libc/calls/ttydefaults.h"
#include "libc/dce.h" #include "libc/dce.h"
#include "libc/intrin/describeflags.internal.h" #include "libc/intrin/describeflags.internal.h"
#include "libc/intrin/nomultics.internal.h" #include "libc/intrin/nomultics.internal.h"
#include "libc/intrin/strace.internal.h" #include "libc/intrin/strace.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/enum/version.h" #include "libc/nt/enum/version.h"
@ -32,6 +35,7 @@
#include "libc/nt/version.h" #include "libc/nt/version.h"
#include "libc/runtime/runtime.h" #include "libc/runtime/runtime.h"
#include "libc/str/str.h" #include "libc/str/str.h"
#include "libc/sysv/consts/fileno.h"
#include "libc/sysv/consts/o.h" #include "libc/sysv/consts/o.h"
#include "libc/sysv/consts/sicode.h" #include "libc/sysv/consts/sicode.h"
#include "libc/sysv/consts/sig.h" #include "libc/sysv/consts/sig.h"
@ -166,94 +170,92 @@ textwindows int tcsetattr_nt(int fd, int opt, const struct termios *tio) {
bool32 ok; bool32 ok;
int64_t hInput, hOutput; int64_t hInput, hOutput;
uint32_t inmode, outmode; uint32_t inmode, outmode;
if (__isfdkind(fd, kFdConsole)) { if (__isfdkind(fd, kFdConsole)) {
// program manually opened /dev/tty in O_RDWR mode for cmd.exe
hInput = g_fds.p[fd].handle; hInput = g_fds.p[fd].handle;
hOutput = g_fds.p[fd].extra; hOutput = g_fds.p[fd].extra;
} else if (fd == 0 || fd == 1) { } else if (fd == STDIN_FILENO || //
// otherwise just assume cmd.exe console stdio fd == STDOUT_FILENO || //
// there's no serial port support yet fd == STDERR_FILENO) {
hInput = g_fds.p[0].handle; hInput = g_fds.p[STDIN_FILENO].handle;
hOutput = g_fds.p[1].handle; hOutput = g_fds.p[MAX(STDOUT_FILENO, fd)].handle;
fd = 0;
} else { } else {
STRACE("tcsetattr(fd) must be 0, 1, or open'd /dev/tty");
return enotty(); return enotty();
} }
if (GetConsoleMode(hInput, &inmode) && GetConsoleMode(hOutput, &outmode)) {
if (opt == TCSAFLUSH) { if (!GetConsoleMode(hInput, &inmode) || !GetConsoleMode(hOutput, &outmode)) {
FlushConsoleInputBuffer(hInput); return enotty();
} }
inmode &= ~(kNtEnableLineInput | kNtEnableEchoInput |
kNtEnableProcessedInput | kNtEnableVirtualTerminalInput);
inmode |= kNtEnableWindowInput;
__ttymagic = 0;
if (tio->c_lflag & ICANON) {
inmode |= kNtEnableLineInput | kNtEnableProcessedInput;
} else {
__ttymagic |= kFdTtyMunging;
if (tio->c_cc[VMIN] != 1) {
STRACE("tcsetattr c_cc[VMIN] must be 1 on Windows");
return einval();
}
if (IsAtLeastWindows10()) {
// - keys like f1, up, etc. get turned into \e ansi codes
// - totally destroys default console gui (e.g. up arrow)
inmode |= kNtEnableVirtualTerminalInput;
}
}
if (!(tio->c_iflag & ICRNL)) {
__ttymagic |= kFdTtyNoCr2Nl;
}
if (!(tio->c_lflag & ECHOCTL)) {
__ttymagic |= kFdTtyEchoRaw;
}
if (tio->c_lflag & ECHO) {
// "kNtEnableEchoInput can be used only if the
// kNtEnableLineInput mode is also enabled." -MSDN
if (tio->c_lflag & ICANON) {
inmode |= kNtEnableEchoInput;
} else {
// If ECHO is enabled in raw mode, then read(0) needs to
// magically write(1) to simulate echoing. This normally
// visualizes control codes, e.g. \r → ^M unless ECHOCTL
// hasn't been specified.
__ttymagic |= kFdTtyEchoing;
}
}
if (!(tio->c_lflag & ISIG)) {
__ttymagic |= kFdTtyNoIsigs;
}
__vintr = tio->c_cc[VINTR];
__vquit = tio->c_cc[VQUIT];
if ((tio->c_lflag & ISIG) && //
tio->c_cc[VINTR] == CTRL('C')) {
// allows ctrl-c to be delivered asynchronously via win32
inmode |= kNtEnableProcessedInput;
}
ok = SetConsoleMode(hInput, inmode);
(void)ok;
NTTRACE("SetConsoleMode(%p, %s) → %hhhd", hInput,
DescribeNtConsoleInFlags(inmode), ok);
outmode &= ~kNtDisableNewlineAutoReturn; if (opt == TCSAFLUSH) {
outmode |= kNtEnableProcessedOutput; tcflush(fd, TCIFLUSH);
if (!(tio->c_oflag & ONLCR)) { }
outmode |= kNtDisableNewlineAutoReturn; inmode &= ~(kNtEnableLineInput | kNtEnableEchoInput |
kNtEnableProcessedInput | kNtEnableVirtualTerminalInput);
inmode |= kNtEnableWindowInput;
__ttymagic = 0;
if (tio->c_lflag & ICANON) {
inmode |= kNtEnableLineInput | kNtEnableProcessedInput;
} else {
__ttymagic |= kFdTtyMunging;
if (tio->c_cc[VMIN] != 1) {
STRACE("tcsetattr c_cc[VMIN] must be 1 on Windows");
return einval();
} }
if (IsAtLeastWindows10()) { if (IsAtLeastWindows10()) {
outmode |= kNtEnableVirtualTerminalProcessing; // - keys like f1, up, etc. get turned into \e ansi codes
// - totally destroys default console gui (e.g. up arrow)
inmode |= kNtEnableVirtualTerminalInput;
} }
ok = SetConsoleMode(hOutput, outmode);
(void)ok;
NTTRACE("SetConsoleMode(%p, %s) → %hhhd", hOutput,
DescribeNtConsoleOutFlags(outmode), ok);
return 0;
} else {
return enotty();
} }
if (!(tio->c_iflag & ICRNL)) {
__ttymagic |= kFdTtyNoCr2Nl;
}
if (!(tio->c_lflag & ECHOCTL)) {
__ttymagic |= kFdTtyEchoRaw;
}
if (tio->c_lflag & ECHO) {
// "kNtEnableEchoInput can be used only if the
// kNtEnableLineInput mode is also enabled." -MSDN
if (tio->c_lflag & ICANON) {
inmode |= kNtEnableEchoInput;
} else {
// If ECHO is enabled in raw mode, then read(0) needs to
// magically write(1) to simulate echoing. This normally
// visualizes control codes, e.g. \r → ^M unless ECHOCTL
// hasn't been specified.
__ttymagic |= kFdTtyEchoing;
}
}
if (!(tio->c_lflag & ISIG)) {
__ttymagic |= kFdTtyNoIsigs;
}
__vintr = tio->c_cc[VINTR];
__vquit = tio->c_cc[VQUIT];
if ((tio->c_lflag & ISIG) && //
tio->c_cc[VINTR] == CTRL('C')) {
// allows ctrl-c to be delivered asynchronously via win32
inmode |= kNtEnableProcessedInput;
}
ok = SetConsoleMode(hInput, inmode);
(void)ok;
NTTRACE("SetConsoleMode(%p, %s) → %hhhd", hInput,
DescribeNtConsoleInFlags(inmode), ok);
outmode &= ~kNtDisableNewlineAutoReturn;
outmode |= kNtEnableProcessedOutput;
if (!(tio->c_oflag & ONLCR)) {
outmode |= kNtDisableNewlineAutoReturn;
}
if (IsAtLeastWindows10()) {
outmode |= kNtEnableVirtualTerminalProcessing;
}
ok = SetConsoleMode(hOutput, outmode);
(void)ok;
NTTRACE("SetConsoleMode(%p, %s) → %hhhd", hOutput,
DescribeNtConsoleOutFlags(outmode), ok);
return 0;
} }
__attribute__((__constructor__)) static void tcsetattr_nt_init(void) { __attribute__((__constructor__)) static void tcsetattr_nt_init(void) {

View file

@ -20,9 +20,11 @@
#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/dce.h" #include "libc/dce.h"
#include "libc/fmt/itoa.h"
#include "libc/intrin/atomic.h" #include "libc/intrin/atomic.h"
#include "libc/intrin/strace.internal.h" #include "libc/intrin/strace.internal.h"
#include "libc/log/libfatal.internal.h" #include "libc/log/libfatal.internal.h"
#include "libc/nt/console.h"
#include "libc/nt/createfile.h" #include "libc/nt/createfile.h"
#include "libc/nt/enum/accessmask.h" #include "libc/nt/enum/accessmask.h"
#include "libc/nt/enum/creationdisposition.h" #include "libc/nt/enum/creationdisposition.h"
@ -60,6 +62,7 @@ __msabi extern typeof(CreateFile) *const __imp_CreateFileW;
__msabi extern typeof(CreateNamedPipe) *const __imp_CreateNamedPipeW; __msabi extern typeof(CreateNamedPipe) *const __imp_CreateNamedPipeW;
__msabi extern typeof(CreateSemaphore) *const __imp_CreateSemaphoreW; __msabi extern typeof(CreateSemaphore) *const __imp_CreateSemaphoreW;
__msabi extern typeof(CreateThread) *const __imp_CreateThread; __msabi extern typeof(CreateThread) *const __imp_CreateThread;
__msabi extern typeof(GetConsoleMode) *const __imp_GetConsoleMode;
__msabi extern typeof(GetCurrentThreadId) *const __imp_GetCurrentThreadId; __msabi extern typeof(GetCurrentThreadId) *const __imp_GetCurrentThreadId;
__msabi extern typeof(GetStdHandle) *const __imp_GetStdHandle; __msabi extern typeof(GetStdHandle) *const __imp_GetStdHandle;
__msabi extern typeof(ReadFile) *const __imp_ReadFile; __msabi extern typeof(ReadFile) *const __imp_ReadFile;
@ -78,78 +81,97 @@ static void Log(const char *s) {
#endif #endif
} }
__msabi static dontasan dontubsan dontinstrument textwindows uint32_t __msabi static textwindows uint32_t WinStdinThread(void *lpParameter) {
WinStdinThread(void *lpParameter) { char buf[4];
char buf[4096];
uint32_t i, got, wrote; uint32_t i, got, wrote;
Log("<stdin> activated thread\n");
// wait forever for semaphore to exceed 0
//
// this semaphore is unlocked the first time read or poll happens. we
// need it so the prog has time to call functions like SetConsoleMode
// before we begin performing i/o.
__imp_WaitForSingleObject(g_fds.stdin.inisem, -1u);
__imp_CloseHandle(g_fds.stdin.inisem);
// relay stdin to process
Log("<stdin> activated\n");
for (;;) { for (;;) {
Log("<stdin> wait\n");
__imp_WaitForSingleObject(g_fds.stdin.inisem, -1u);
Log("<stdin> read\n");
if (!__imp_ReadFile(g_fds.stdin.handle, buf, sizeof(buf), &got, 0)) { if (!__imp_ReadFile(g_fds.stdin.handle, buf, sizeof(buf), &got, 0)) {
Log("<stdin> read failed\n"); Log("<stdin> read failed\n");
goto Finish; goto Finish;
} }
if (!got) { if (!got) {
Log("<stdin> end of file\n"); Log("<stdin> eof\n");
goto Finish; goto Finish;
} }
for (i = 0; i < got; i += wrote) { for (i = 0; i < got; i += wrote) {
Log("<stdin> write");
if (!__imp_WriteFile(g_fds.stdin.writer, buf + i, got - i, &wrote, 0)) { if (!__imp_WriteFile(g_fds.stdin.writer, buf + i, got - i, &wrote, 0)) {
Log("<stdin> failed to write to pipe\n"); Log("<stdin> write failed\n");
goto Finish; goto Finish;
} }
} }
} }
Finish: Finish:
__imp_CloseHandle(g_fds.stdin.writer); __imp_CloseHandle(g_fds.stdin.writer);
return 0; return 0;
} }
textwindows static char16_t *FixCpy(char16_t p[17], uint64_t x, uint8_t k) {
while (k > 0) *p++ = "0123456789abcdef"[(x >> (k -= 4)) & 15];
*p = '\0';
return p;
}
textwindows static char16_t *CreateStdinPipeName(char16_t *a, int64_t h) {
char16_t *p = a;
const char *q = "\\\\?\\pipe\\cosmo\\stdin\\";
while (*q) *p++ = *q++;
p = FixCpy(p, h, 64);
*p = 0;
return a;
}
// this makes it possible for our read() implementation to periodically // this makes it possible for our read() implementation to periodically
// poll for signals while performing a blocking overlapped io operation // poll for signals while performing a blocking overlapped io operation
dontasan dontubsan dontinstrument textwindows void WinMainStdin(void) { textwindows void WinMainStdin(void) {
char16_t pipename[64]; char16_t pipename[64];
int64_t hStdin, hWriter, hReader, hThread, hSemaphore; int64_t hStdin, hWriter, hReader, hThread, hSemaphore;
if (!SupportsWindows()) return; if (!SupportsWindows()) return;
// handle numbers stay the same when inherited by the subprocesses
hStdin = __imp_GetStdHandle(kNtStdInputHandle); hStdin = __imp_GetStdHandle(kNtStdInputHandle);
if (hStdin == kNtInvalidHandleValue) { if (hStdin == kNtInvalidHandleValue) {
Log("<stdin> GetStdHandle failed\n"); Log("<stdin> GetStdHandle failed\n");
return; return;
} }
// create non-inherited semaphore with initial value of 0 CreateStdinPipeName(pipename, hStdin);
hSemaphore = __imp_CreateSemaphoreW(0, 0, 1, 0); hReader = __imp_CreateFileW(pipename, kNtGenericRead, 0, 0, kNtOpenExisting,
if (!hSemaphore) {
Log("<stdin> CreateSemaphore failed\n");
return;
}
__create_pipe_name(pipename);
hReader = __imp_CreateNamedPipeW(
pipename, kNtPipeAccessInbound | kNtFileFlagOverlapped,
kNtPipeTypeByte | kNtPipeReadmodeByte, 1, 4096, 4096, 0, 0);
if (hReader == kNtInvalidHandleValue) {
Log("<stdin> CreateNamedPipe failed\n");
return;
}
hWriter = __imp_CreateFileW(pipename, kNtGenericWrite, 0, 0, kNtOpenExisting,
kNtFileFlagOverlapped, 0); kNtFileFlagOverlapped, 0);
if (hWriter == kNtInvalidHandleValue) { if (hReader == kNtInvalidHandleValue) {
Log("<stdin> CreateFile failed\n"); // we are the init process; create pipe server to dole out stdin
return; hWriter = __imp_CreateNamedPipeW(
} pipename, kNtPipeAccessOutbound | kNtFileFlagOverlapped,
hThread = __imp_CreateThread(0, 65536, WinStdinThread, 0, 0, 0); kNtPipeTypeMessage | kNtPipeReadmodeMessage | kNtPipeNowait,
if (!hThread) { kNtPipeUnlimitedInstances, 4096, 4096, 0, 0);
Log("<stdin> CreateThread failed\n"); if (hWriter == kNtInvalidHandleValue) {
return; Log("<stdin> CreateNamedPipe failed\n");
return;
}
hReader = __imp_CreateFileW(pipename, kNtGenericRead, 0, 0, kNtOpenExisting,
kNtFileFlagOverlapped, 0);
if (hReader == kNtInvalidHandleValue) {
Log("<stdin> CreateFile failed\n");
return;
}
// create non-inherited semaphore with initial value of 0
hSemaphore = __imp_CreateSemaphoreW(0, 0, 1, 0);
if (!hSemaphore) {
Log("<stdin> CreateSemaphore failed\n");
return;
}
hThread = __imp_CreateThread(0, 65536, WinStdinThread, 0, 0, 0);
if (!hThread) {
Log("<stdin> CreateThread failed\n");
return;
}
} else {
// we are the child of a cosmo process with its own stdin thread
hWriter = 0;
hThread = 0;
hSemaphore = 0;
} }
g_fds.stdin.handle = hStdin; g_fds.stdin.handle = hStdin;
g_fds.stdin.thread = hThread; g_fds.stdin.thread = hThread;

View file

@ -23,7 +23,7 @@
textwindows int64_t __resolve_stdin_handle(int64_t handle) { textwindows int64_t __resolve_stdin_handle(int64_t handle) {
if (handle == g_fds.stdin.handle) { if (handle == g_fds.stdin.handle) {
if (!atomic_exchange(&g_fds.stdin.once, 1)) { if (g_fds.stdin.inisem) {
ReleaseSemaphore(g_fds.stdin.inisem, 1, 0); ReleaseSemaphore(g_fds.stdin.inisem, 1, 0);
} }
handle = g_fds.stdin.reader; handle = g_fds.stdin.reader;

View file

@ -1,8 +1,5 @@
#ifndef COSMOPOLITAN_LIBC_FMT_FMT_H_ #ifndef COSMOPOLITAN_LIBC_FMT_FMT_H_
#define COSMOPOLITAN_LIBC_FMT_FMT_H_ #define COSMOPOLITAN_LIBC_FMT_FMT_H_
/*───────────────────────────────────────────────────────────────────────────│─╗
cosmopolitan § string formatting
*/
#if __SIZEOF_POINTER__ == 8 #if __SIZEOF_POINTER__ == 8
#define POINTER_XDIGITS 12 /* math.log(2**48-1,16) */ #define POINTER_XDIGITS 12 /* math.log(2**48-1,16) */
@ -13,15 +10,6 @@
#if !(__ASSEMBLER__ + __LINKER__ + 0) #if !(__ASSEMBLER__ + __LINKER__ + 0)
COSMOPOLITAN_C_START_ COSMOPOLITAN_C_START_
int snprintf(char *, size_t, const char *, ...)
printfesque(3) dontthrow nocallback;
int vsnprintf(char *, size_t, const char *, va_list)
dontthrow nocallback;
int sprintf(char *, const char *, ...) dontthrow nocallback;
int vsprintf(char *, const char *, va_list)
dontthrow nocallback;
int sscanf(const char *, const char *, ...) scanfesque(2);
int vsscanf(const char *, const char *, va_list);
char *fcvt(double, int, int *, int *); char *fcvt(double, int, int *, int *);
char *ecvt(double, int, int *, int *); char *ecvt(double, int, int *, int *);
char *gcvt(double, int, char *); char *gcvt(double, int, char *);

View file

@ -4,11 +4,11 @@
#include "libc/runtime/runtime.h" #include "libc/runtime/runtime.h"
#define _KERNTRACE 0 /* not configurable w/ flag yet */ #define _KERNTRACE 0 /* not configurable w/ flag yet */
#define _POLLTRACE 0 /* not configurable w/ flag yet */ #define _POLLTRACE 1 /* not configurable w/ flag yet */
#define _DATATRACE 1 /* not configurable w/ flag yet */ #define _DATATRACE 1 /* not configurable w/ flag yet */
#define _STDIOTRACE 0 /* not configurable w/ flag yet */ #define _STDIOTRACE 0 /* not configurable w/ flag yet */
#define _LOCKTRACE 0 /* not configurable w/ flag yet */ #define _LOCKTRACE 0 /* not configurable w/ flag yet */
#define _NTTRACE 0 /* not configurable w/ flag yet */ #define _NTTRACE 1 /* not configurable w/ flag yet */
#define STRACE_PROLOGUE "%rSYS %6P %'18T " #define STRACE_PROLOGUE "%rSYS %6P %'18T "

View file

@ -0,0 +1,19 @@
#ifndef _LINUX_PARAM_H
#define _LINUX_PARAM_H
#include "libc/runtime/clktck.h"
#ifndef HZ
#define HZ CLK_TCK
#endif
#ifndef EXEC_PAGESIZE
#define EXEC_PAGESIZE 65536
#endif
#ifndef NOGROUP
#define NOGROUP (-1)
#endif
#define MAXHOSTNAMELEN 64
#endif

View file

@ -1,3 +1,4 @@
#ifndef _STDARG_H #ifndef _STDARG_H
#define _STDARG_H #define _STDARG_H
#include "libc/stdio/stdio.h"
#endif /* _STDARG_H */ #endif /* _STDARG_H */

View file

@ -32,8 +32,6 @@
#include "libc/sysv/consts/sio.h" #include "libc/sysv/consts/sio.h"
#include "libc/sysv/consts/sock.h" #include "libc/sysv/consts/sock.h"
/* TODO(jart): DELETE */
static uint32_t *GetUnixIps(void) { static uint32_t *GetUnixIps(void) {
int fd, n; int fd, n;
uint64_t z; uint64_t z;

View file

@ -28,8 +28,8 @@
#include "libc/sock/syscall_fd.internal.h" #include "libc/sock/syscall_fd.internal.h"
#include "libc/sysv/errfuns.h" #include "libc/sysv/errfuns.h"
textwindows ssize_t sys_recv_nt(struct Fd *fd, const struct iovec *iov, textwindows ssize_t sys_recv_nt(int fd, const struct iovec *iov, size_t iovlen,
size_t iovlen, uint32_t flags) { uint32_t flags) {
int err; int err;
ssize_t rc; ssize_t rc;
uint32_t got; uint32_t got;
@ -37,17 +37,18 @@ textwindows ssize_t sys_recv_nt(struct Fd *fd, const struct iovec *iov,
struct NtIovec iovnt[16]; struct NtIovec iovnt[16];
struct NtOverlapped overlapped = {.hEvent = WSACreateEvent()}; struct NtOverlapped overlapped = {.hEvent = WSACreateEvent()};
err = errno; err = errno;
if (!WSARecv(fd->handle, iovnt, __iovec2nt(iovnt, iov, iovlen), 0, &flags, if (!WSARecv(g_fds.p[fd].handle, iovnt, __iovec2nt(iovnt, iov, iovlen), 0,
&overlapped, 0)) { &flags, &overlapped, 0)) {
if (WSAGetOverlappedResult(fd->handle, &overlapped, &got, false, &flags)) { if (WSAGetOverlappedResult(g_fds.p[fd].handle, &overlapped, &got, false,
&flags)) {
rc = got; rc = got;
} else { } else {
rc = -1; rc = -1;
} }
} else { } else {
errno = err; errno = err;
sockfd = (struct SockFd *)fd->extra; sockfd = (struct SockFd *)g_fds.p[fd].extra;
rc = __wsablock(fd, &overlapped, &flags, kSigOpRestartable, rc = __wsablock(g_fds.p + fd, &overlapped, &flags, kSigOpRestartable,
sockfd->rcvtimeo); sockfd->rcvtimeo);
} }
unassert(WSACloseEvent(overlapped.hEvent)); unassert(WSACloseEvent(overlapped.hEvent));

View file

@ -53,12 +53,12 @@ ssize_t recv(int fd, void *buf, size_t size, int flags) {
rc = sys_recvfrom(fd, buf, size, flags, 0, 0); rc = sys_recvfrom(fd, buf, size, flags, 0, 0);
} else if (__isfdopen(fd)) { } else if (__isfdopen(fd)) {
if (__isfdkind(fd, kFdSocket)) { if (__isfdkind(fd, kFdSocket)) {
rc = sys_recv_nt(&g_fds.p[fd], (struct iovec[]){{buf, size}}, 1, flags); rc = sys_recv_nt(fd, (struct iovec[]){{buf, size}}, 1, flags);
} else if (__isfdkind(fd, kFdFile)) { } else if (__isfdkind(fd, kFdFile)) {
if (flags) { if (flags) {
rc = einval(); rc = einval();
} else { } else {
rc = sys_read_nt(&g_fds.p[fd], (struct iovec[]){{buf, size}}, 1, -1); rc = sys_read_nt(fd, (struct iovec[]){{buf, size}}, 1, -1);
} }
} else { } else {
rc = enotsock(); rc = enotsock();

View file

@ -25,7 +25,7 @@
#include "libc/sock/syscall_fd.internal.h" #include "libc/sock/syscall_fd.internal.h"
#include "libc/sysv/errfuns.h" #include "libc/sysv/errfuns.h"
textwindows ssize_t sys_recvfrom_nt(struct Fd *fd, const struct iovec *iov, textwindows ssize_t sys_recvfrom_nt(int fd, const struct iovec *iov,
size_t iovlen, uint32_t flags, size_t iovlen, uint32_t flags,
void *opt_out_srcaddr, void *opt_out_srcaddr,
uint32_t *opt_inout_srcaddrsize) { uint32_t *opt_inout_srcaddrsize) {
@ -36,17 +36,19 @@ textwindows ssize_t sys_recvfrom_nt(struct Fd *fd, const struct iovec *iov,
struct NtIovec iovnt[16]; struct NtIovec iovnt[16];
struct NtOverlapped overlapped = {.hEvent = WSACreateEvent()}; struct NtOverlapped overlapped = {.hEvent = WSACreateEvent()};
err = errno; err = errno;
if (!WSARecvFrom(fd->handle, iovnt, __iovec2nt(iovnt, iov, iovlen), 0, &flags, if (!WSARecvFrom(g_fds.p[fd].handle, iovnt, __iovec2nt(iovnt, iov, iovlen), 0,
opt_out_srcaddr, opt_inout_srcaddrsize, &overlapped, NULL)) { &flags, opt_out_srcaddr, opt_inout_srcaddrsize, &overlapped,
if (WSAGetOverlappedResult(fd->handle, &overlapped, &got, false, &flags)) { NULL)) {
if (WSAGetOverlappedResult(g_fds.p[fd].handle, &overlapped, &got, false,
&flags)) {
rc = got; rc = got;
} else { } else {
rc = -1; rc = -1;
} }
} else { } else {
errno = err; errno = err;
sockfd = (struct SockFd *)fd->extra; sockfd = (struct SockFd *)g_fds.p[fd].extra;
rc = __wsablock(fd, &overlapped, &flags, kSigOpRestartable, rc = __wsablock(g_fds.p + fd, &overlapped, &flags, kSigOpRestartable,
sockfd->rcvtimeo); sockfd->rcvtimeo);
} }
WSACloseEvent(overlapped.hEvent); WSACloseEvent(overlapped.hEvent);

View file

@ -68,11 +68,11 @@ ssize_t recvfrom(int fd, void *buf, size_t size, int flags,
rc = sys_recvfrom(fd, buf, size, flags, &addr, &addrsize); rc = sys_recvfrom(fd, buf, size, flags, &addr, &addrsize);
} else if (__isfdopen(fd)) { } else if (__isfdopen(fd)) {
if (__isfdkind(fd, kFdSocket)) { if (__isfdkind(fd, kFdSocket)) {
rc = sys_recvfrom_nt(&g_fds.p[fd], (struct iovec[]){{buf, size}}, 1, rc = sys_recvfrom_nt(fd, (struct iovec[]){{buf, size}}, 1, flags, &addr,
flags, &addr, &addrsize); &addrsize);
} else if (__isfdkind(fd, kFdFile) && !opt_out_srcaddr) { /* socketpair */ } else if (__isfdkind(fd, kFdFile) && !opt_out_srcaddr) { /* socketpair */
if (!flags) { if (!flags) {
rc = sys_read_nt(&g_fds.p[fd], (struct iovec[]){{buf, size}}, 1, -1); rc = sys_read_nt(fd, (struct iovec[]){{buf, size}}, 1, -1);
} else { } else {
rc = einval(); rc = einval();
} }

View file

@ -74,12 +74,12 @@ ssize_t recvmsg(int fd, struct msghdr *msg, int flags) {
} else if (__isfdopen(fd)) { } else if (__isfdopen(fd)) {
if (!msg->msg_control) { if (!msg->msg_control) {
if (__isfdkind(fd, kFdSocket)) { if (__isfdkind(fd, kFdSocket)) {
rc = sys_recvfrom_nt(&g_fds.p[fd], msg->msg_iov, msg->msg_iovlen, flags, rc = sys_recvfrom_nt(fd, msg->msg_iov, msg->msg_iovlen, flags,
msg->msg_name, &msg->msg_namelen); msg->msg_name, &msg->msg_namelen);
} else if (__isfdkind(fd, kFdFile) && !msg->msg_name) { /* socketpair */ } else if (__isfdkind(fd, kFdFile) && !msg->msg_name) { /* socketpair */
if (!flags) { if (!flags) {
if ((got = sys_read_nt(&g_fds.p[fd], msg->msg_iov, msg->msg_iovlen, if ((got = sys_read_nt(fd, msg->msg_iov, msg->msg_iovlen, -1)) !=
-1)) != -1) { -1) {
msg->msg_flags = 0; msg->msg_flags = 0;
rc = got; rc = got;
} else { } else {

View file

@ -56,8 +56,10 @@ 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
if (!timeout || ckd_add(&millis, timeout->tv_sec, timeout->tv_usec / 1000)) { if (!timeout) {
millis = -1; millis = -1;
} else {
millis = timeval_tomillis(*timeout);
} }
// call our nt poll implementation // call our nt poll implementation
@ -76,8 +78,7 @@ int sys_select_nt(int nfds, fd_set *readfds, fd_set *writefds,
// store remaining time back in caller's timeval // store remaining time back in caller's timeval
if (timeout) { if (timeout) {
timeout->tv_sec = millis / 1000; *timeout = timeval_frommillis(millis);
timeout->tv_usec = millis % 1000 * 1000;
} }
return fdcount; return fdcount;

View file

@ -17,9 +17,9 @@ int sys_getsockopt_nt(struct Fd *, int, int, void *, uint32_t *);
int sys_listen_nt(struct Fd *, int); int sys_listen_nt(struct Fd *, int);
int sys_setsockopt_nt(struct Fd *, int, int, const void *, uint32_t); int sys_setsockopt_nt(struct Fd *, int, int, const void *, uint32_t);
int sys_shutdown_nt(struct Fd *, int); int sys_shutdown_nt(struct Fd *, int);
ssize_t sys_recv_nt(struct Fd *, const struct iovec *, size_t, uint32_t); ssize_t sys_recv_nt(int, const struct iovec *, size_t, uint32_t);
ssize_t sys_recvfrom_nt(struct Fd *, const struct iovec *, size_t, uint32_t, ssize_t sys_recvfrom_nt(int, const struct iovec *, size_t, uint32_t, void *,
void *, uint32_t *); uint32_t *);
int __wsablock(struct Fd *, struct NtOverlapped *, uint32_t *, int, uint32_t); int __wsablock(struct Fd *, struct NtOverlapped *, uint32_t *, int, uint32_t);
COSMOPOLITAN_C_END_ COSMOPOLITAN_C_END_

View file

@ -24,6 +24,7 @@
*/ */
#include "libc/fmt/fmt.h" #include "libc/fmt/fmt.h"
#include "libc/mem/mem.h" #include "libc/mem/mem.h"
#include "libc/stdio/stdio.h"
#include "libc/str/str.h" #include "libc/str/str.h"
#include "libc/str/unicode.h" #include "libc/str/unicode.h"
#include "third_party/gdtoa/gdtoa.h" #include "third_party/gdtoa/gdtoa.h"

View file

@ -16,7 +16,7 @@
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/fmt/fmt.h" #include "libc/stdio/stdio.h"
/** /**
* Formats string to buffer. * Formats string to buffer.

View file

@ -18,6 +18,7 @@
*/ */
#include "libc/dce.h" #include "libc/dce.h"
#include "libc/fmt/fmt.h" #include "libc/fmt/fmt.h"
#include "libc/stdio/stdio.h"
/** /**
* String decoder. * String decoder.

View file

@ -108,6 +108,14 @@ int vscanf(const char *, va_list);
int fscanf(FILE *, const char *, ...) scanfesque(2); int fscanf(FILE *, const char *, ...) scanfesque(2);
int vfscanf(FILE *, const char *, va_list); int vfscanf(FILE *, const char *, va_list);
int snprintf(char *, size_t, const char *, ...)
printfesque(3) dontthrow nocallback;
int vsnprintf(char *, size_t, const char *, va_list)
dontthrow nocallback;
int sprintf(char *, const char *, ...) dontthrow nocallback;
int vsprintf(char *, const char *, va_list)
dontthrow nocallback;
int fwprintf(FILE *, const wchar_t *, ...); int fwprintf(FILE *, const wchar_t *, ...);
int fwscanf(FILE *, const wchar_t *, ...); int fwscanf(FILE *, const wchar_t *, ...);
int swprintf(wchar_t *, size_t, const wchar_t *, ...); int swprintf(wchar_t *, size_t, const wchar_t *, ...);
@ -122,6 +130,9 @@ int wprintf(const wchar_t *, ...);
int wscanf(const wchar_t *, ...); int wscanf(const wchar_t *, ...);
int fwide(FILE *, int); int fwide(FILE *, int);
int sscanf(const char *, const char *, ...) scanfesque(2);
int vsscanf(const char *, const char *, va_list);
/*───────────────────────────────────────────────────────────────────────────│─╗ /*───────────────────────────────────────────────────────────────────────────│─╗
cosmopolitan § standard i/o » allocating cosmopolitan § standard i/o » allocating
*/ */

View file

@ -18,10 +18,10 @@
*/ */
#include "libc/assert.h" #include "libc/assert.h"
#include "libc/dce.h" #include "libc/dce.h"
#include "libc/fmt/fmt.h"
#include "libc/macros.internal.h" #include "libc/macros.internal.h"
#include "libc/mem/mem.h" #include "libc/mem/mem.h"
#include "libc/stdio/append.h" #include "libc/stdio/append.h"
#include "libc/stdio/stdio.h"
#define W sizeof(size_t) #define W sizeof(size_t)

View file

@ -17,8 +17,8 @@
PERFORMANCE OF THIS SOFTWARE. PERFORMANCE OF THIS SOFTWARE.
*/ */
#include "libc/assert.h" #include "libc/assert.h"
#include "libc/fmt/fmt.h"
#include "libc/mem/mem.h" #include "libc/mem/mem.h"
#include "libc/stdio/stdio.h"
/** /**
* Formats string w/ dynamic memory allocation. * Formats string w/ dynamic memory allocation.

View file

@ -16,8 +16,8 @@
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/fmt/fmt.h"
#include "libc/limits.h" #include "libc/limits.h"
#include "libc/stdio/stdio.h"
/** /**
* Formats string to buffer hopefully large enough w/ vararg state. * Formats string to buffer hopefully large enough w/ vararg state.

View file

@ -16,9 +16,9 @@
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/fmt/fmt.h"
#include "libc/intrin/safemacros.internal.h" #include "libc/intrin/safemacros.internal.h"
#include "libc/mem/mem.h" #include "libc/mem/mem.h"
#include "libc/stdio/stdio.h"
#include "libc/str/str.h" #include "libc/str/str.h"
#include "libc/testlib/testlib.h" #include "libc/testlib/testlib.h"

View file

@ -16,8 +16,8 @@
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/fmt/fmt.h"
#include "libc/runtime/internal.h" #include "libc/runtime/internal.h"
#include "libc/stdio/stdio.h"
#include "libc/sysv/consts/prot.h" #include "libc/sysv/consts/prot.h"
#include "libc/testlib/testlib.h" #include "libc/testlib/testlib.h"

View file

@ -16,10 +16,10 @@
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/fmt/fmt.h"
#include "libc/intrin/bits.h" #include "libc/intrin/bits.h"
#include "libc/macros.internal.h" #include "libc/macros.internal.h"
#include "libc/mem/mem.h" #include "libc/mem/mem.h"
#include "libc/stdio/stdio.h"
#include "libc/testlib/testlib.h" #include "libc/testlib/testlib.h"
static size_t sbufi_; static size_t sbufi_;

View file

@ -0,0 +1,37 @@
/*-*- 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/calls.h"
#include "libc/mem/gc.internal.h"
#include "libc/sysv/consts/o.h"
#include "libc/testlib/testlib.h"
char testlib_enable_tmp_setup_teardown;
TEST(fchdir, test) {
const char *a, *b;
ASSERT_SYS(0, 0, mkdir("dog", 0755));
ASSERT_SYS(0, 0, chdir("dog"));
ASSERT_NE(NULL, (a = gc(getcwd(0, 0))));
ASSERT_SYS(0, 3, open(".", O_RDONLY));
ASSERT_SYS(0, 0, chdir("/"));
ASSERT_SYS(0, 0, fchdir(3));
ASSERT_NE(NULL, (b = gc(getcwd(0, 0))));
ASSERT_STREQ(a, b);
ASSERT_SYS(0, 0, close(3));
}

View file

@ -21,12 +21,12 @@
#include "libc/calls/struct/rlimit.h" #include "libc/calls/struct/rlimit.h"
#include "libc/dce.h" #include "libc/dce.h"
#include "libc/errno.h" #include "libc/errno.h"
#include "libc/fmt/fmt.h"
#include "libc/intrin/directmap.internal.h" #include "libc/intrin/directmap.internal.h"
#include "libc/intrin/safemacros.internal.h" #include "libc/intrin/safemacros.internal.h"
#include "libc/limits.h" #include "libc/limits.h"
#include "libc/runtime/runtime.h" #include "libc/runtime/runtime.h"
#include "libc/stdio/rand.h" #include "libc/stdio/rand.h"
#include "libc/stdio/stdio.h"
#include "libc/sysv/consts/auxv.h" #include "libc/sysv/consts/auxv.h"
#include "libc/sysv/consts/map.h" #include "libc/sysv/consts/map.h"
#include "libc/sysv/consts/o.h" #include "libc/sysv/consts/o.h"

View file

@ -19,11 +19,11 @@
#include "libc/calls/calls.h" #include "libc/calls/calls.h"
#include "libc/calls/struct/stat.h" #include "libc/calls/struct/stat.h"
#include "libc/errno.h" #include "libc/errno.h"
#include "libc/fmt/fmt.h"
#include "libc/fmt/itoa.h" #include "libc/fmt/itoa.h"
#include "libc/limits.h" #include "libc/limits.h"
#include "libc/runtime/runtime.h" #include "libc/runtime/runtime.h"
#include "libc/stdio/rand.h" #include "libc/stdio/rand.h"
#include "libc/stdio/stdio.h"
#include "libc/sysv/consts/at.h" #include "libc/sysv/consts/at.h"
#include "libc/sysv/consts/s.h" #include "libc/sysv/consts/s.h"
#include "libc/testlib/testlib.h" #include "libc/testlib/testlib.h"

View file

@ -20,7 +20,6 @@
#include "libc/calls/calls.h" #include "libc/calls/calls.h"
#include "libc/dce.h" #include "libc/dce.h"
#include "libc/errno.h" #include "libc/errno.h"
#include "libc/fmt/fmt.h"
#include "libc/intrin/bits.h" #include "libc/intrin/bits.h"
#include "libc/limits.h" #include "libc/limits.h"
#include "libc/log/libfatal.internal.h" #include "libc/log/libfatal.internal.h"
@ -29,6 +28,7 @@
#include "libc/runtime/runtime.h" #include "libc/runtime/runtime.h"
#include "libc/runtime/symbols.internal.h" #include "libc/runtime/symbols.internal.h"
#include "libc/stdio/rand.h" #include "libc/stdio/rand.h"
#include "libc/stdio/stdio.h"
#include "libc/str/str.h" #include "libc/str/str.h"
#include "libc/sysv/consts/map.h" #include "libc/sysv/consts/map.h"
#include "libc/sysv/consts/prot.h" #include "libc/sysv/consts/prot.h"

View file

@ -91,7 +91,7 @@ TEST(ShowCrashReports, testMemoryLeakCrash) {
return; return;
} }
ASSERT_NE(-1, pipe2(fds, O_CLOEXEC)); ASSERT_NE(-1, pipe2(fds, O_CLOEXEC));
ASSERT_NE(-1, (pid = vfork())); ASSERT_NE(-1, (pid = fork()));
if (!pid) { if (!pid) {
dup2(fds[1], 1); dup2(fds[1], 1);
dup2(fds[1], 2); dup2(fds[1], 2);
@ -191,7 +191,7 @@ TEST(ShowCrashReports, testDivideByZero) {
int ws, pid, fds[2]; int ws, pid, fds[2];
char *output, buf[512]; char *output, buf[512];
ASSERT_NE(-1, pipe2(fds, O_CLOEXEC)); ASSERT_NE(-1, pipe2(fds, O_CLOEXEC));
ASSERT_NE(-1, (pid = vfork())); ASSERT_NE(-1, (pid = fork()));
if (!pid) { if (!pid) {
dup2(fds[1], 1); dup2(fds[1], 1);
dup2(fds[1], 2); dup2(fds[1], 2);
@ -315,7 +315,7 @@ TEST(ShowCrashReports, testBssOverrunCrash) {
int ws, pid, fds[2]; int ws, pid, fds[2];
char *output, buf[512]; char *output, buf[512];
ASSERT_NE(-1, pipe2(fds, O_CLOEXEC)); ASSERT_NE(-1, pipe2(fds, O_CLOEXEC));
ASSERT_NE(-1, (pid = vfork())); ASSERT_NE(-1, (pid = fork()));
if (!pid) { if (!pid) {
dup2(fds[1], 1); dup2(fds[1], 1);
dup2(fds[1], 2); dup2(fds[1], 2);
@ -393,7 +393,7 @@ TEST(ShowCrashReports, testNpeCrash) {
int ws, pid, fds[2]; int ws, pid, fds[2];
char *output, buf[512]; char *output, buf[512];
ASSERT_NE(-1, pipe2(fds, O_CLOEXEC)); ASSERT_NE(-1, pipe2(fds, O_CLOEXEC));
ASSERT_NE(-1, (pid = vfork())); ASSERT_NE(-1, (pid = fork()));
if (!pid) { if (!pid) {
dup2(fds[1], 1); dup2(fds[1], 1);
dup2(fds[1], 2); dup2(fds[1], 2);
@ -452,7 +452,7 @@ TEST(ShowCrashReports, testDataOverrunCrash) {
int ws, pid, fds[2]; int ws, pid, fds[2];
char *output, buf[512]; char *output, buf[512];
ASSERT_NE(-1, pipe2(fds, O_CLOEXEC)); ASSERT_NE(-1, pipe2(fds, O_CLOEXEC));
ASSERT_NE(-1, (pid = vfork())); ASSERT_NE(-1, (pid = fork()));
if (!pid) { if (!pid) {
dup2(fds[1], 1); dup2(fds[1], 1);
dup2(fds[1], 2); dup2(fds[1], 2);
@ -506,7 +506,7 @@ TEST(ShowCrashReports, testNpeCrashAfterFinalize) {
int ws, pid, fds[2]; int ws, pid, fds[2];
char *output, buf[512]; char *output, buf[512];
ASSERT_NE(-1, pipe2(fds, O_CLOEXEC)); ASSERT_NE(-1, pipe2(fds, O_CLOEXEC));
ASSERT_NE(-1, (pid = vfork())); ASSERT_NE(-1, (pid = fork()));
if (!pid) { if (!pid) {
dup2(fds[1], 1); dup2(fds[1], 1);
dup2(fds[1], 2); dup2(fds[1], 2);

View file

@ -22,7 +22,6 @@
#include "libc/dce.h" #include "libc/dce.h"
#include "libc/errno.h" #include "libc/errno.h"
#include "libc/fmt/conv.h" #include "libc/fmt/conv.h"
#include "libc/fmt/fmt.h"
#include "libc/fmt/itoa.h" #include "libc/fmt/itoa.h"
#include "libc/intrin/kprintf.h" #include "libc/intrin/kprintf.h"
#include "libc/limits.h" #include "libc/limits.h"
@ -34,6 +33,7 @@
#include "libc/stdio/append.h" #include "libc/stdio/append.h"
#include "libc/stdio/ftw.h" #include "libc/stdio/ftw.h"
#include "libc/stdio/rand.h" #include "libc/stdio/rand.h"
#include "libc/stdio/stdio.h"
#include "libc/str/str.h" #include "libc/str/str.h"
#include "libc/sysv/consts/dt.h" #include "libc/sysv/consts/dt.h"
#include "libc/sysv/consts/o.h" #include "libc/sysv/consts/o.h"

View file

@ -25,7 +25,6 @@
THE SOFTWARE. THE SOFTWARE.
*/ */
#include "libc/errno.h" #include "libc/errno.h"
#include "libc/fmt/fmt.h"
#include "libc/fmt/itoa.h" #include "libc/fmt/itoa.h"
#include "libc/intrin/pushpop.internal.h" #include "libc/intrin/pushpop.internal.h"
#include "libc/intrin/safemacros.internal.h" #include "libc/intrin/safemacros.internal.h"
@ -33,6 +32,7 @@
#include "libc/math.h" #include "libc/math.h"
#include "libc/mem/gc.h" #include "libc/mem/gc.h"
#include "libc/mem/mem.h" #include "libc/mem/mem.h"
#include "libc/stdio/stdio.h"
#include "libc/str/str.h" #include "libc/str/str.h"
#include "libc/testlib/ezbench.h" #include "libc/testlib/ezbench.h"
#include "libc/testlib/testlib.h" #include "libc/testlib/testlib.h"

View file

@ -16,7 +16,7 @@
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/fmt/fmt.h" #include "libc/stdio/stdio.h"
#include "libc/str/str.h" #include "libc/str/str.h"
#include "libc/testlib/testlib.h" #include "libc/testlib/testlib.h"

View file

@ -21,11 +21,11 @@
#include "libc/mem/gc.h" #include "libc/mem/gc.h"
#include "libc/mem/mem.h" #include "libc/mem/mem.h"
#include "libc/runtime/runtime.h" #include "libc/runtime/runtime.h"
#include "libc/temp.h"
#include "libc/str/str.h" #include "libc/str/str.h"
#include "libc/sysv/consts/clock.h" #include "libc/sysv/consts/clock.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/temp.h"
#include "libc/testlib/subprocess.h" #include "libc/testlib/subprocess.h"
#include "libc/testlib/testlib.h" #include "libc/testlib/testlib.h"
#include "libc/thread/semaphore.h" #include "libc/thread/semaphore.h"
@ -107,7 +107,7 @@ TEST(sem_close, withUnnamedSemaphore_isUndefinedBehavior) {
SPAWN(fork); SPAWN(fork);
IgnoreStderr(); IgnoreStderr();
sem_close(&sem); sem_close(&sem);
EXITS(128 + SIGABRT); // see __assert_fail TERMS(SIGABRT); // see __assert_fail
ASSERT_SYS(0, 0, sem_destroy(&sem)); ASSERT_SYS(0, 0, sem_destroy(&sem));
} }
@ -118,7 +118,7 @@ TEST(sem_destroy, withNamedSemaphore_isUndefinedBehavior) {
SPAWN(fork); SPAWN(fork);
IgnoreStderr(); IgnoreStderr();
sem_destroy(sem); sem_destroy(sem);
EXITS(128 + SIGABRT); // see __assert_fail TERMS(SIGABRT); // see __assert_fail
ASSERT_SYS(0, 0, sem_unlink("/boop")); ASSERT_SYS(0, 0, sem_unlink("/boop"));
ASSERT_SYS(0, 0, sem_close(sem)); ASSERT_SYS(0, 0, sem_close(sem));
} }

View file

@ -17,7 +17,7 @@
PERFORMANCE OF THIS SOFTWARE. PERFORMANCE OF THIS SOFTWARE.
*/ */
#include "libc/complex.h" #include "libc/complex.h"
#include "libc/fmt/fmt.h" #include "libc/stdio/stdio.h"
#include "libc/testlib/testlib.h" #include "libc/testlib/testlib.h"
TEST(complex, test) { TEST(complex, test) {

View file

@ -17,11 +17,11 @@
PERFORMANCE OF THIS SOFTWARE. PERFORMANCE OF THIS SOFTWARE.
*/ */
#include "libc/fmt/conv.h" #include "libc/fmt/conv.h"
#include "libc/fmt/fmt.h"
#include "libc/macros.internal.h" #include "libc/macros.internal.h"
#include "libc/mem/gc.h" #include "libc/mem/gc.h"
#include "libc/mem/mem.h" #include "libc/mem/mem.h"
#include "libc/runtime/fenv.h" #include "libc/runtime/fenv.h"
#include "libc/stdio/stdio.h"
#include "libc/testlib/ezbench.h" #include "libc/testlib/ezbench.h"
#include "libc/testlib/testlib.h" #include "libc/testlib/testlib.h"
#include "libc/x/xasprintf.h" #include "libc/x/xasprintf.h"

View file

@ -15,11 +15,12 @@
- Apache 2.0 : https://www.apache.org/licenses/LICENSE-2.0 │ - Apache 2.0 : https://www.apache.org/licenses/LICENSE-2.0 │
*/ */
#include "third_party/argon2/encoding.h"
#include "libc/fmt/fmt.h" #include "libc/fmt/fmt.h"
#include "libc/limits.h" #include "libc/limits.h"
#include "libc/stdio/stdio.h"
#include "libc/str/str.h" #include "libc/str/str.h"
#include "third_party/argon2/core.h" #include "third_party/argon2/core.h"
#include "third_party/argon2/encoding.h"
asm(".ident\t\"\\n\\n\ asm(".ident\t\"\\n\\n\
argon2 (CC0 or Apache2)\\n\ argon2 (CC0 or Apache2)\\n\

View file

@ -37,10 +37,10 @@
#include "libc/calls/struct/stat.h" #include "libc/calls/struct/stat.h"
#include "libc/calls/struct/stat.macros.h" #include "libc/calls/struct/stat.macros.h"
#include "libc/errno.h" #include "libc/errno.h"
#include "libc/fmt/fmt.h"
#include "libc/mem/mem.h" #include "libc/mem/mem.h"
#include "libc/paths.h" #include "libc/paths.h"
#include "libc/runtime/runtime.h" #include "libc/runtime/runtime.h"
#include "libc/stdio/stdio.h"
#include "libc/str/str.h" #include "libc/str/str.h"
#include "libc/sysv/consts/o.h" #include "libc/sysv/consts/o.h"
#include "third_party/finger/finger.h" #include "third_party/finger/finger.h"

View file

@ -3,8 +3,8 @@
#include "libc/assert.h" #include "libc/assert.h"
#include "libc/dce.h" #include "libc/dce.h"
#include "libc/fmt/conv.h" #include "libc/fmt/conv.h"
#include "libc/fmt/fmt.h"
#include "libc/limits.h" #include "libc/limits.h"
#include "libc/stdio/stdio.h"
#include "libc/str/unicode.h" #include "libc/str/unicode.h"
#define LUA_USE_POSIX #define LUA_USE_POSIX

View file

@ -26,7 +26,7 @@
*/ */
#include "libc/errno.h" #include "libc/errno.h"
#include "libc/fmt/fmt.h" #include "libc/stdio/stdio.h"
#include "libc/str/locale.h" #include "libc/str/locale.h"
#include "libc/str/str.h" #include "libc/str/str.h"
#include "libc/thread/tls.h" #include "libc/thread/tls.h"

View file

@ -16,8 +16,8 @@
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/fmt/fmt.h"
#include "libc/intrin/safemacros.internal.h" #include "libc/intrin/safemacros.internal.h"
#include "libc/stdio/stdio.h"
#include "libc/str/str.h" #include "libc/str/str.h"
#include "third_party/regex/regex.h" #include "third_party/regex/regex.h"

View file

@ -6,9 +6,9 @@
* For conditions of distribution and use, see copyright notice in zlib.h * For conditions of distribution and use, see copyright notice in zlib.h
*/ */
#include "libc/calls/calls.h" #include "libc/calls/calls.h"
#include "libc/fmt/fmt.h"
#include "libc/limits.h" #include "libc/limits.h"
#include "libc/mem/mem.h" #include "libc/mem/mem.h"
#include "libc/stdio/stdio.h"
#include "libc/str/str.h" #include "libc/str/str.h"
#include "libc/sysv/consts/o.h" #include "libc/sysv/consts/o.h"
#include "third_party/zlib/gz/gzguts.inc" #include "third_party/zlib/gz/gzguts.inc"

View file

@ -6,8 +6,8 @@
* For conditions of distribution and use, see copyright notice in zlib.h * For conditions of distribution and use, see copyright notice in zlib.h
*/ */
#include "libc/calls/calls.h" #include "libc/calls/calls.h"
#include "libc/fmt/fmt.h"
#include "libc/mem/mem.h" #include "libc/mem/mem.h"
#include "libc/stdio/stdio.h"
#include "third_party/zlib/gz/gzguts.inc" #include "third_party/zlib/gz/gzguts.inc"
// clang-format off // clang-format off

View file

@ -19,10 +19,10 @@
#include "tool/build/lib/buffer.h" #include "tool/build/lib/buffer.h"
#include "libc/calls/calls.h" #include "libc/calls/calls.h"
#include "libc/errno.h" #include "libc/errno.h"
#include "libc/fmt/fmt.h"
#include "libc/macros.internal.h" #include "libc/macros.internal.h"
#include "libc/mem/arraylist2.internal.h" #include "libc/mem/arraylist2.internal.h"
#include "libc/mem/mem.h" #include "libc/mem/mem.h"
#include "libc/stdio/stdio.h"
#include "libc/str/str.h" #include "libc/str/str.h"
/* TODO(jart): replace with new append*() library */ /* TODO(jart): replace with new append*() library */

View file

@ -17,9 +17,9 @@
PERFORMANCE OF THIS SOFTWARE. PERFORMANCE OF THIS SOFTWARE.
*/ */
#include "tool/decode/lib/flagger.h" #include "tool/decode/lib/flagger.h"
#include "libc/fmt/fmt.h"
#include "libc/mem/arraylist2.internal.h" #include "libc/mem/arraylist2.internal.h"
#include "libc/mem/mem.h" #include "libc/mem/mem.h"
#include "libc/stdio/stdio.h"
#include "libc/str/str.h" #include "libc/str/str.h"
/** /**