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/dce.h"
#include "libc/errno.h"
#include "libc/fmt/fmt.h"
#include "libc/intrin/safemacros.internal.h"
#include "libc/intrin/weaken.h"
#include "libc/mem/mem.h"
#include "libc/runtime/runtime.h"
#include "libc/sock/sock.h"
#include "libc/sock/struct/pollfd.h"
#include "libc/stdio/stdio.h"
#include "libc/str/str.h"
#include "libc/sysv/consts/poll.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/ │
*/
#endif
#include "libc/assert.h"
#include "libc/calls/calls.h"
#include "libc/calls/struct/sigaction.h"
#include "libc/errno.h"
@ -15,7 +16,9 @@
#include "libc/sock/struct/pollfd.h"
#include "libc/stdio/stdio.h"
#include "libc/str/str.h"
#include "libc/sysv/consts/f.h"
#include "libc/sysv/consts/limits.h"
#include "libc/sysv/consts/o.h"
#include "libc/sysv/consts/poll.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
// such programs shall rely on asynchronous signals
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) {
printf("\rgot ctrl+c asynchronously\n");
exit(0);
@ -55,7 +58,7 @@ int main(int argc, char *argv[]) {
// 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
// we can also be assured that multiple actors wont have tearing
char buf[PIPE_BUF];
char buf[4];
// 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
// which kills the process by default
write(1, buf, got);
write(1, "\n", 1);
}
}

View file

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

View file

@ -93,6 +93,12 @@ o/$(MODE)/libc/calls/vdsofunc.greg.o: private \
-ffreestanding \
-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:
# ntspawn allocates 128kb of heap memory via win32
o/$(MODE)/libc/calls/ntspawn.o \

View file

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

View file

@ -18,39 +18,46 @@
*/
#include "libc/calls/calls.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-sysv.internal.h"
#include "libc/dce.h"
#include "libc/intrin/strace.internal.h"
#include "libc/runtime/runtime.h"
#include "libc/sysv/errfuns.h"
/**
* Blocks until kernel flushes non-metadata buffers for fd to disk.
*
* @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 __nosync to secretly disable
* @raise ECANCELED if thread was cancelled in masked mode
* @raise EINTR if signal was delivered
* @cancellationpoint
* @asyncsignalsafe
*/
int fdatasync(int fd) {
int rc;
struct stat st;
if (__nosync != 0x5453455454534146) {
BEGIN_CANCELLATION_POINT;
if (!IsWindows()) {
bool fake = __nosync == 0x5453455454534146;
BEGIN_CANCELLATION_POINT;
if (__isfdkind(fd, kFdZip)) {
rc = erofs();
} else if (!IsWindows()) {
if (!fake) {
rc = sys_fdatasync(fd);
} else {
rc = sys_fdatasync_nt(fd);
rc = sys_fsync_fake(fd);
}
END_CANCELLATION_POINT;
STRACE("fdatasync(%d) → %d% m", fd, rc);
} else {
rc = fstat(fd, &st);
STRACE("fdatasync_fake(%d) → %d% m", fd, rc);
rc = sys_fdatasync_nt(fd, fake);
}
END_CANCELLATION_POINT;
STRACE("fdatasync%s(%d) → %d% m", fake ? "_fake" : "", fd, 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/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-sysv.internal.h"
#include "libc/dce.h"
#include "libc/intrin/strace.internal.h"
#include "libc/runtime/runtime.h"
#include "libc/sysv/errfuns.h"
/**
* Blocks until kernel flushes buffers for fd to disk.
*
* @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 fdatasync(), sync_file_range()
* @see __nosync to secretly disable
* @cancellationpoint
@ -38,19 +44,20 @@
*/
int fsync(int fd) {
int rc;
struct stat st;
if (__nosync != 0x5453455454534146) {
BEGIN_CANCELLATION_POINT;
if (!IsWindows()) {
bool fake = __nosync == 0x5453455454534146;
BEGIN_CANCELLATION_POINT;
if (__isfdkind(fd, kFdZip)) {
rc = erofs();
} else if (!IsWindows()) {
if (!fake) {
rc = sys_fsync(fd);
} else {
rc = sys_fdatasync_nt(fd);
rc = sys_fsync_fake(fd);
}
END_CANCELLATION_POINT;
STRACE("fsync(%d) → %d% m", fd, rc);
} else {
rc = fstat(fd, &st);
STRACE("fsync_fake(%d) → %d% m", fd, rc);
rc = sys_fdatasync_nt(fd, fake);
}
END_CANCELLATION_POINT;
STRACE("fsync%s(%d) → %d% m", fake ? "_fake" : "", fd, rc);
return rc;
}

View file

@ -24,6 +24,7 @@
#include "libc/calls/syscall_support-nt.internal.h"
#include "libc/errno.h"
#include "libc/macros.internal.h"
#include "libc/nt/console.h"
#include "libc/nt/createfile.h"
#include "libc/nt/enum/accessmask.h"
#include "libc/nt/enum/creationdisposition.h"
@ -144,14 +145,20 @@ static textwindows int sys_open_nt_console(int dirfd,
const struct NtMagicPaths *mp,
uint32_t flags, int32_t mode,
size_t fd) {
if (GetFileType(g_fds.p[STDIN_FILENO].handle) == kNtFileTypeChar &&
GetFileType(g_fds.p[STDOUT_FILENO].handle) == kNtFileTypeChar) {
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[STDIN_FILENO].handle;
g_fds.p[fd].extra = g_fds.p[STDOUT_FILENO].handle;
g_fds.p[STDOUT_FILENO].dontclose = true;
g_fds.p[STDIN_FILENO].dontclose = true;
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) {
@ -187,7 +194,7 @@ textwindows int sys_open_nt(int dirfd, const char *file, uint32_t flags,
ssize_t rc;
__fds_lock();
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);
} else {
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)) {
rc = espipe();
} 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 {
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) {
return espipe();
} else {
return sys_read_nt(g_fds.p + fd, iov, iovlen, off);
return sys_read_nt(fd, iov, iovlen, off);
}
} else {
return ebadf();

View file

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

View file

@ -16,6 +16,7 @@
TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE.
*/
#include "libc/calls/internal.h"
#include "libc/calls/metalfile.internal.h"
#include "libc/calls/struct/fd.internal.h"
#include "libc/calls/struct/iovec.h"
@ -28,11 +29,11 @@
#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;
size_t got, toto;
struct MetalFile *file;
switch (fd->kind) {
switch (g_fds.p[fd].kind) {
case kFdConsole:
/*
* 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.
*/
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;
}
/* fall through */
case kFdSerial:
return sys_readv_serial(fd, iov, iovlen);
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) {
got = MIN(iov[i].iov_len, file->size - file->pos);
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
PERFORMANCE OF THIS SOFTWARE.
*/
#include "libc/calls/internal.h"
#include "libc/calls/struct/iovec.internal.h"
#include "libc/intrin/weaken.h"
#include "libc/sock/internal.h"
@ -24,9 +25,8 @@
#ifdef __x86_64__
textwindows ssize_t sys_readv_nt(struct Fd *fd, const struct iovec *iov,
int iovlen) {
switch (fd->kind) {
textwindows ssize_t sys_readv_nt(int fd, const struct iovec *iov, int iovlen) {
switch (g_fds.p[fd].kind) {
case kFdFile:
case kFdConsole:
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
PERFORMANCE OF THIS SOFTWARE.
*/
#include "libc/calls/internal.h"
#include "libc/calls/struct/fd.internal.h"
#include "libc/calls/struct/iovec.internal.h"
#include "libc/nexgen32e/uart.internal.h"
#include "libc/runtime/pc.internal.h"
#ifdef __x86_64__
static bool IsDataAvailable(struct Fd *fd) {
return inb(fd->handle + UART_LSR) & UART_TTYDA;
static bool IsDataAvailable(int fd) {
return inb(g_fds.p[fd].handle + UART_LSR) & UART_TTYDA;
}
static int GetFirstIov(const struct iovec *iov, int iovlen) {
@ -36,13 +37,13 @@ static int GetFirstIov(const struct iovec *iov, int iovlen) {
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;
if ((i = GetFirstIov(iov, iovlen)) != -1) {
while (!IsDataAvailable(fd)) {
__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;
} else {
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) {
rc = ebadf();
} else if (IsMetal()) {
rc = sys_readv_metal(g_fds.p + fd, iov, iovlen);
rc = sys_readv_metal(fd, iov, iovlen);
} else if (IsWindows()) {
rc = sys_readv_nt(g_fds.p + fd, iov, iovlen);
rc = sys_readv_nt(fd, iov, iovlen);
} else {
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_vmsplice(int, const struct iovec *, int64_t, uint32_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_readv_metal(struct Fd *, const struct iovec *, int);
ssize_t sys_readv_nt(struct Fd *, const struct iovec *, int);
ssize_t sys_readv_serial(struct Fd *, const struct iovec *, int);
ssize_t sys_read_nt(int, const struct iovec *, size_t, int64_t);
ssize_t sys_readv_metal(int, const struct iovec *, int);
ssize_t sys_readv_nt(int, 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_writev_metal(struct Fd *, 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;
int64_t timeval_toseconds(struct timeval);
int64_t timeval_tomicros(struct timeval);
int64_t timeval_tomillis(struct timeval);
struct timeval timespec_totimeval(struct timespec) pureconst;
static inline struct timeval timeval_fromseconds(int64_t __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_fchmodat_nt(int, const char *, uint32_t, int);
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_fork_nt(uint32_t);
int sys_fsync_fake(int);
int sys_ftruncate_nt(int64_t, uint64_t);
int sys_getloadavg_nt(double *, int);
int sys_getppid_nt(void);
@ -36,6 +37,7 @@ int sys_sync_nt(void);
int sys_truncate_nt(const char *, uint64_t);
int sys_unlinkat_nt(int, const char *, 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);
COSMOPOLITAN_C_END_

View file

@ -23,10 +23,14 @@
#include "libc/calls/syscall_support-nt.internal.h"
#include "libc/calls/termios.h"
#include "libc/dce.h"
#include "libc/errno.h"
#include "libc/fmt/itoa.h"
#include "libc/intrin/strace.internal.h"
#include "libc/mem/alloca.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/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) {
bool32 ok;
int64_t h;
if (!__isfdopen(fd)) return ebadf();
ok = true;
h = g_fds.p[fd].handle;
if (queue == TCIFLUSH || queue == TCIOFLUSH) {
ok &= !!PurgeComm(h, kNtPurgeRxclear);
if (!__isfdopen(fd)) {
return ebadf();
}
if (queue == TCOFLUSH || queue == TCIOFLUSH) {
ok &= !!PurgeComm(h, kNtPurgeTxclear);
int64_t hConin;
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 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();
} else if (IsLinux()) {
rc = sys_ioctl(fd, TCFLSH, queue);

View file

@ -22,79 +22,87 @@
#include "libc/calls/struct/termios.h"
#include "libc/calls/ttydefaults.h"
#include "libc/intrin/nomultics.internal.h"
#include "libc/macros.internal.h"
#include "libc/nt/console.h"
#include "libc/nt/enum/consolemodeflags.h"
#include "libc/nt/struct/consolescreenbufferinfoex.h"
#include "libc/str/str.h"
#include "libc/sysv/consts/baud.internal.h"
#include "libc/sysv/consts/fileno.h"
#include "libc/sysv/consts/o.h"
#include "libc/sysv/consts/termios.h"
#include "libc/sysv/errfuns.h"
textwindows int tcgetattr_nt(int ignored, struct termios *tio) {
int64_t in, out;
bool32 inok, outok;
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));
textwindows int tcgetattr_nt(int fd, struct termios *tio) {
int64_t hInput, hOutput;
uint32_t inmode, outmode;
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 (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;
if (__isfdkind(fd, kFdConsole)) {
hInput = g_fds.p[fd].handle;
hOutput = g_fds.p[fd].extra;
} else if (fd == STDIN_FILENO || //
fd == STDOUT_FILENO || //
fd == STDERR_FILENO) {
hInput = g_fds.p[STDIN_FILENO].handle;
hOutput = g_fds.p[MAX(STDOUT_FILENO, fd)].handle;
} else {
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/sig.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/ttydefaults.h"
#include "libc/dce.h"
#include "libc/intrin/describeflags.internal.h"
#include "libc/intrin/nomultics.internal.h"
#include "libc/intrin/strace.internal.h"
#include "libc/macros.internal.h"
#include "libc/nt/console.h"
#include "libc/nt/enum/consolemodeflags.h"
#include "libc/nt/enum/version.h"
@ -32,6 +35,7 @@
#include "libc/nt/version.h"
#include "libc/runtime/runtime.h"
#include "libc/str/str.h"
#include "libc/sysv/consts/fileno.h"
#include "libc/sysv/consts/o.h"
#include "libc/sysv/consts/sicode.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;
int64_t hInput, hOutput;
uint32_t inmode, outmode;
if (__isfdkind(fd, kFdConsole)) {
// program manually opened /dev/tty in O_RDWR mode for cmd.exe
hInput = g_fds.p[fd].handle;
hOutput = g_fds.p[fd].extra;
} else if (fd == 0 || fd == 1) {
// otherwise just assume cmd.exe console stdio
// there's no serial port support yet
hInput = g_fds.p[0].handle;
hOutput = g_fds.p[1].handle;
fd = 0;
} else if (fd == STDIN_FILENO || //
fd == STDOUT_FILENO || //
fd == STDERR_FILENO) {
hInput = g_fds.p[STDIN_FILENO].handle;
hOutput = g_fds.p[MAX(STDOUT_FILENO, fd)].handle;
} else {
STRACE("tcsetattr(fd) must be 0, 1, or open'd /dev/tty");
return enotty();
}
if (GetConsoleMode(hInput, &inmode) && GetConsoleMode(hOutput, &outmode)) {
if (opt == TCSAFLUSH) {
FlushConsoleInputBuffer(hInput);
}
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);
if (!GetConsoleMode(hInput, &inmode) || !GetConsoleMode(hOutput, &outmode)) {
return enotty();
}
outmode &= ~kNtDisableNewlineAutoReturn;
outmode |= kNtEnableProcessedOutput;
if (!(tio->c_oflag & ONLCR)) {
outmode |= kNtDisableNewlineAutoReturn;
if (opt == TCSAFLUSH) {
tcflush(fd, TCIFLUSH);
}
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()) {
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) {

View file

@ -20,9 +20,11 @@
#include "libc/calls/internal.h"
#include "libc/calls/syscall_support-nt.internal.h"
#include "libc/dce.h"
#include "libc/fmt/itoa.h"
#include "libc/intrin/atomic.h"
#include "libc/intrin/strace.internal.h"
#include "libc/log/libfatal.internal.h"
#include "libc/nt/console.h"
#include "libc/nt/createfile.h"
#include "libc/nt/enum/accessmask.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(CreateSemaphore) *const __imp_CreateSemaphoreW;
__msabi extern typeof(CreateThread) *const __imp_CreateThread;
__msabi extern typeof(GetConsoleMode) *const __imp_GetConsoleMode;
__msabi extern typeof(GetCurrentThreadId) *const __imp_GetCurrentThreadId;
__msabi extern typeof(GetStdHandle) *const __imp_GetStdHandle;
__msabi extern typeof(ReadFile) *const __imp_ReadFile;
@ -78,78 +81,97 @@ static void Log(const char *s) {
#endif
}
__msabi static dontasan dontubsan dontinstrument textwindows uint32_t
WinStdinThread(void *lpParameter) {
char buf[4096];
__msabi static textwindows uint32_t WinStdinThread(void *lpParameter) {
char buf[4];
uint32_t i, got, wrote;
// 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");
Log("<stdin> activated thread\n");
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)) {
Log("<stdin> read failed\n");
goto Finish;
}
if (!got) {
Log("<stdin> end of file\n");
Log("<stdin> eof\n");
goto Finish;
}
for (i = 0; i < got; i += wrote) {
Log("<stdin> write");
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;
}
}
}
Finish:
__imp_CloseHandle(g_fds.stdin.writer);
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
// 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];
int64_t hStdin, hWriter, hReader, hThread, hSemaphore;
if (!SupportsWindows()) return;
// handle numbers stay the same when inherited by the subprocesses
hStdin = __imp_GetStdHandle(kNtStdInputHandle);
if (hStdin == kNtInvalidHandleValue) {
Log("<stdin> GetStdHandle 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;
}
__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,
CreateStdinPipeName(pipename, hStdin);
hReader = __imp_CreateFileW(pipename, kNtGenericRead, 0, 0, kNtOpenExisting,
kNtFileFlagOverlapped, 0);
if (hWriter == kNtInvalidHandleValue) {
Log("<stdin> CreateFile failed\n");
return;
}
hThread = __imp_CreateThread(0, 65536, WinStdinThread, 0, 0, 0);
if (!hThread) {
Log("<stdin> CreateThread failed\n");
return;
if (hReader == kNtInvalidHandleValue) {
// we are the init process; create pipe server to dole out stdin
hWriter = __imp_CreateNamedPipeW(
pipename, kNtPipeAccessOutbound | kNtFileFlagOverlapped,
kNtPipeTypeMessage | kNtPipeReadmodeMessage | kNtPipeNowait,
kNtPipeUnlimitedInstances, 4096, 4096, 0, 0);
if (hWriter == kNtInvalidHandleValue) {
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.thread = hThread;

View file

@ -23,7 +23,7 @@
textwindows int64_t __resolve_stdin_handle(int64_t 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);
}
handle = g_fds.stdin.reader;

View file

@ -1,8 +1,5 @@
#ifndef COSMOPOLITAN_LIBC_FMT_FMT_H_
#define COSMOPOLITAN_LIBC_FMT_FMT_H_
/*───────────────────────────────────────────────────────────────────────────│─╗
cosmopolitan § string formatting
*/
#if __SIZEOF_POINTER__ == 8
#define POINTER_XDIGITS 12 /* math.log(2**48-1,16) */
@ -13,15 +10,6 @@
#if !(__ASSEMBLER__ + __LINKER__ + 0)
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 *ecvt(double, int, int *, int *);
char *gcvt(double, int, char *);

View file

@ -4,11 +4,11 @@
#include "libc/runtime/runtime.h"
#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 _STDIOTRACE 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 "

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
#define _STDARG_H
#include "libc/stdio/stdio.h"
#endif /* _STDARG_H */

View file

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

View file

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

View file

@ -25,7 +25,7 @@
#include "libc/sock/syscall_fd.internal.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,
void *opt_out_srcaddr,
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 NtOverlapped overlapped = {.hEvent = WSACreateEvent()};
err = errno;
if (!WSARecvFrom(fd->handle, iovnt, __iovec2nt(iovnt, iov, iovlen), 0, &flags,
opt_out_srcaddr, opt_inout_srcaddrsize, &overlapped, NULL)) {
if (WSAGetOverlappedResult(fd->handle, &overlapped, &got, false, &flags)) {
if (!WSARecvFrom(g_fds.p[fd].handle, iovnt, __iovec2nt(iovnt, iov, iovlen), 0,
&flags, opt_out_srcaddr, opt_inout_srcaddrsize, &overlapped,
NULL)) {
if (WSAGetOverlappedResult(g_fds.p[fd].handle, &overlapped, &got, false,
&flags)) {
rc = got;
} else {
rc = -1;
}
} else {
errno = err;
sockfd = (struct SockFd *)fd->extra;
rc = __wsablock(fd, &overlapped, &flags, kSigOpRestartable,
sockfd = (struct SockFd *)g_fds.p[fd].extra;
rc = __wsablock(g_fds.p + fd, &overlapped, &flags, kSigOpRestartable,
sockfd->rcvtimeo);
}
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);
} else if (__isfdopen(fd)) {
if (__isfdkind(fd, kFdSocket)) {
rc = sys_recvfrom_nt(&g_fds.p[fd], (struct iovec[]){{buf, size}}, 1,
flags, &addr, &addrsize);
rc = sys_recvfrom_nt(fd, (struct iovec[]){{buf, size}}, 1, flags, &addr,
&addrsize);
} else if (__isfdkind(fd, kFdFile) && !opt_out_srcaddr) { /* socketpair */
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 {
rc = einval();
}

View file

@ -74,12 +74,12 @@ ssize_t recvmsg(int fd, struct msghdr *msg, int flags) {
} else if (__isfdopen(fd)) {
if (!msg->msg_control) {
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);
} else if (__isfdkind(fd, kFdFile) && !msg->msg_name) { /* socketpair */
if (!flags) {
if ((got = sys_read_nt(&g_fds.p[fd], msg->msg_iov, msg->msg_iovlen,
-1)) != -1) {
if ((got = sys_read_nt(fd, msg->msg_iov, msg->msg_iovlen, -1)) !=
-1) {
msg->msg_flags = 0;
rc = got;
} 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
if (!timeout || ckd_add(&millis, timeout->tv_sec, timeout->tv_usec / 1000)) {
if (!timeout) {
millis = -1;
} else {
millis = timeval_tomillis(*timeout);
}
// 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
if (timeout) {
timeout->tv_sec = millis / 1000;
timeout->tv_usec = millis % 1000 * 1000;
*timeout = timeval_frommillis(millis);
}
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_setsockopt_nt(struct Fd *, int, int, const void *, uint32_t);
int sys_shutdown_nt(struct Fd *, int);
ssize_t sys_recv_nt(struct Fd *, const struct iovec *, size_t, uint32_t);
ssize_t sys_recvfrom_nt(struct Fd *, const struct iovec *, size_t, uint32_t,
void *, uint32_t *);
ssize_t sys_recv_nt(int, const struct iovec *, size_t, uint32_t);
ssize_t sys_recvfrom_nt(int, const struct iovec *, size_t, uint32_t, void *,
uint32_t *);
int __wsablock(struct Fd *, struct NtOverlapped *, uint32_t *, int, uint32_t);
COSMOPOLITAN_C_END_

View file

@ -24,6 +24,7 @@
*/
#include "libc/fmt/fmt.h"
#include "libc/mem/mem.h"
#include "libc/stdio/stdio.h"
#include "libc/str/str.h"
#include "libc/str/unicode.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
PERFORMANCE OF THIS SOFTWARE.
*/
#include "libc/fmt/fmt.h"
#include "libc/stdio/stdio.h"
/**
* Formats string to buffer.

View file

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

View file

@ -108,6 +108,14 @@ int vscanf(const char *, va_list);
int fscanf(FILE *, const char *, ...) scanfesque(2);
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 fwscanf(FILE *, 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 fwide(FILE *, int);
int sscanf(const char *, const char *, ...) scanfesque(2);
int vsscanf(const char *, const char *, va_list);
/*───────────────────────────────────────────────────────────────────────────│─╗
cosmopolitan § standard i/o » allocating
*/

View file

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

View file

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

View file

@ -16,8 +16,8 @@
TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE.
*/
#include "libc/fmt/fmt.h"
#include "libc/limits.h"
#include "libc/stdio/stdio.h"
/**
* 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
PERFORMANCE OF THIS SOFTWARE.
*/
#include "libc/fmt/fmt.h"
#include "libc/intrin/safemacros.internal.h"
#include "libc/mem/mem.h"
#include "libc/stdio/stdio.h"
#include "libc/str/str.h"
#include "libc/testlib/testlib.h"

View file

@ -16,8 +16,8 @@
TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE.
*/
#include "libc/fmt/fmt.h"
#include "libc/runtime/internal.h"
#include "libc/stdio/stdio.h"
#include "libc/sysv/consts/prot.h"
#include "libc/testlib/testlib.h"

View file

@ -16,10 +16,10 @@
TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE.
*/
#include "libc/fmt/fmt.h"
#include "libc/intrin/bits.h"
#include "libc/macros.internal.h"
#include "libc/mem/mem.h"
#include "libc/stdio/stdio.h"
#include "libc/testlib/testlib.h"
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/dce.h"
#include "libc/errno.h"
#include "libc/fmt/fmt.h"
#include "libc/intrin/directmap.internal.h"
#include "libc/intrin/safemacros.internal.h"
#include "libc/limits.h"
#include "libc/runtime/runtime.h"
#include "libc/stdio/rand.h"
#include "libc/stdio/stdio.h"
#include "libc/sysv/consts/auxv.h"
#include "libc/sysv/consts/map.h"
#include "libc/sysv/consts/o.h"

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -16,7 +16,7 @@
TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE.
*/
#include "libc/fmt/fmt.h"
#include "libc/stdio/stdio.h"
#include "libc/str/str.h"
#include "libc/testlib/testlib.h"

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -16,8 +16,8 @@
TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE.
*/
#include "libc/fmt/fmt.h"
#include "libc/intrin/safemacros.internal.h"
#include "libc/stdio/stdio.h"
#include "libc/str/str.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
*/
#include "libc/calls/calls.h"
#include "libc/fmt/fmt.h"
#include "libc/limits.h"
#include "libc/mem/mem.h"
#include "libc/stdio/stdio.h"
#include "libc/str/str.h"
#include "libc/sysv/consts/o.h"
#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
*/
#include "libc/calls/calls.h"
#include "libc/fmt/fmt.h"
#include "libc/mem/mem.h"
#include "libc/stdio/stdio.h"
#include "third_party/zlib/gz/gzguts.inc"
// clang-format off

View file

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

View file

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