Make improvements

- Polyfill pselect() on Windows
- Add -O NOFILE flag to pledge.com
- Polyfill ppoll() on NetBSD, XNU, and Windows
- Support negative numbers and errno in sizetol()
- Add .RSS, .NOFILE, and .MAXCORE to Landlock Make
- Fix issue with .PLEDGE preventing touching of output files
- Add __watch() function (like ftrace) for logging memory changes
This commit is contained in:
Justine Tunney 2022-08-15 15:18:37 -07:00
parent d3b599a796
commit f0701d2a24
35 changed files with 635 additions and 340 deletions

View file

@ -19,7 +19,6 @@
#include "libc/assert.h"
#include "libc/calls/struct/itimerval.h"
#include "libc/macros.internal.h"
#include "libc/math.h"
#include "libc/str/str.h"
#include "libc/sysv/consts/itimer.h"
#include "libc/time/time.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/intrin/safemacros.internal.h"
#include "libc/calls/calls.h"
#include "libc/calls/termios.h"
#include "libc/fmt/conv.h"
#include "libc/intrin/safemacros.internal.h"
#include "libc/log/internal.h"
#include "libc/log/log.h"
#include "libc/runtime/runtime.h"
@ -36,8 +36,8 @@
*/
int getttysize(int fd, struct winsize *out) {
if (__nocolor) {
out->ws_col = strtoimax(firstnonnull(getenv("COLUMNS"), "80"), NULL, 0);
out->ws_row = strtoimax(firstnonnull(getenv("ROWS"), "40"), NULL, 0);
out->ws_col = atoi(firstnonnull(getenv("COLUMNS"), "80"));
out->ws_row = atoi(firstnonnull(getenv("ROWS"), "40"));
out->ws_xpixel = 0;
out->ws_ypixel = 0;
return 0;

View file

@ -39,6 +39,7 @@
#include "libc/nt/winsock.h"
#include "libc/sock/internal.h"
#include "libc/sock/struct/pollfd.h"
#include "libc/sock/struct/pollfd.internal.h"
#include "libc/sysv/consts/o.h"
#include "libc/sysv/consts/poll.h"
#include "libc/sysv/consts/sig.h"
@ -51,9 +52,11 @@
* on both sockets and files at the same time. We also poll for signals
* while poll is polling.
*/
textwindows int sys_poll_nt(struct pollfd *fds, uint64_t nfds, uint64_t *ms) {
textwindows int sys_poll_nt(struct pollfd *fds, uint64_t nfds, uint64_t *ms,
const sigset_t *sigmask) {
bool ok;
uint32_t avail;
sigset_t oldmask;
struct sys_pollfd_nt pipefds[8];
struct sys_pollfd_nt sockfds[64];
int pipeindices[ARRAYLEN(pipefds)];
@ -61,6 +64,7 @@ textwindows int sys_poll_nt(struct pollfd *fds, uint64_t nfds, uint64_t *ms) {
int i, sn, pn, failed, gotinvals, gotpipes, gotsocks, waitfor;
// check for interrupts early before doing work
if (sigmask && __sig_mask(SIG_SETMASK, sigmask, &oldmask)) return -1;
if (_check_interrupts(false, g_fds.p)) return eintr();
// do the planning

View file

@ -81,7 +81,7 @@ int poll(struct pollfd *fds, size_t nfds, int timeout_ms) {
}
} else {
millis = timeout_ms;
rc = sys_poll_nt(fds, nfds, &millis);
rc = sys_poll_nt(fds, nfds, &millis, 0);
}
#if defined(SYSDEBUG) && _POLLTRACE

107
libc/calls/ppoll.c Normal file
View file

@ -0,0 +1,107 @@
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi
Copyright 2022 Justine Alexandra Roberts Tunney
Permission to use, copy, modify, and/or distribute this software for
any purpose with or without fee is hereby granted, provided that the
above copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE.
*/
#include "libc/calls/calls.h"
#include "libc/calls/strace.internal.h"
#include "libc/calls/struct/sigset.internal.h"
#include "libc/calls/struct/timespec.h"
#include "libc/dce.h"
#include "libc/errno.h"
#include "libc/intrin/asan.internal.h"
#include "libc/intrin/kprintf.h"
#include "libc/macros.internal.h"
#include "libc/sock/ppoll.h"
#include "libc/sock/struct/pollfd.h"
#include "libc/sock/struct/pollfd.internal.h"
#include "libc/sysv/consts/sig.h"
#include "libc/sysv/errfuns.h"
/**
* Waits for something to happen on multiple file descriptors at once.
*
* This function is the same as saying:
*
* sigset_t old;
* sigprocmask(SIG_SETMASK, sigmask, &old);
* poll(fds, nfds, timeout);
* sigprocmask(SIG_SETMASK, old, 0);
*
* Except it'll happen atomically if the kernel supports doing that. On
* kernel such as XNU and NetBSD which don't, this wrapper falls back to
* doing the thing described above.
*
* @param timeout if null will block indefinitely
* @param sigmask may be null in which case no mask change happens
* @asyncsignalsafe
* @threadsafe
* @norestart
*/
int ppoll(struct pollfd *fds, size_t nfds, const struct timespec *timeout,
const sigset_t *sigmask) {
int e, i, rc;
uint64_t millis;
sigset_t oldmask;
if (IsAsan() && (!__asan_is_valid(fds, nfds * sizeof(struct pollfd)) ||
(timeout && !__asan_is_valid(timeout, sizeof(timeout))) ||
(sigmask && !__asan_is_valid(sigmask, sizeof(sigmask))))) {
rc = efault();
} else if (!IsWindows()) {
e = errno;
rc = sys_ppoll(fds, nfds, timeout, sigmask);
if (rc == -1 && errno == ENOSYS) {
errno = e;
if (!timeout ||
__builtin_add_overflow(timeout->tv_sec, timeout->tv_nsec / 1000000,
&millis)) {
millis = -1;
}
if (sigmask) sys_sigprocmask(SIG_SETMASK, sigmask, &oldmask);
rc = poll(fds, nfds, millis);
if (sigmask) sys_sigprocmask(SIG_SETMASK, &oldmask, 0);
}
} else {
if (!timeout || __builtin_add_overflow(
timeout->tv_sec, timeout->tv_nsec / 1000000, &millis)) {
millis = -1;
}
rc = sys_poll_nt(fds, nfds, &millis, sigmask);
}
#if defined(SYSDEBUG) && _POLLTRACE
if (UNLIKELY(__strace > 0)) {
kprintf(STRACE_PROLOGUE "ppoll(");
if ((!IsAsan() && kisdangerous(fds)) ||
(IsAsan() && !__asan_is_valid(fds, nfds * sizeof(struct pollfd)))) {
kprintf("%p", fds);
} else {
kprintf("[{");
for (i = 0; i < MIN(5, nfds); ++i) {
kprintf("%s{%d, %s, %s}", i ? ", " : "", fds[i].fd,
DescribePollFlags(fds[i].events),
DescribePollFlags(fds[i].revents));
}
kprintf("%s}]", i == 5 ? "..." : "");
}
kprintf(", %'zu, %s, %s) → %d% lm\n", nfds, DescribeTimeval(0, timeout),
DescribeSigset(0, sigmask), rc);
}
#endif
return rc;
}

View file

@ -19,6 +19,7 @@
#include "libc/fmt/conv.h"
#include "libc/fmt/fmt.h"
#include "libc/str/str.h"
#include "libc/sysv/errfuns.h"
static int GetExponent(int c) {
switch (c) {
@ -65,27 +66,41 @@ static int GetExponent(int c) {
* characters after it (e.g. kbit, Mibit, TiB) are ignored. Spaces
* before the integer are ignored, and overflows will be detected.
*
* Negative numbers are permissible, as well as a leading `+` sign. To
* tell the difference between an error return and `-1` you must clear
* `errno` before calling and test whether it changed.
*
* @param s is non-null nul-terminated input string
* @param b is multiplier which should be 1000 or 1024
* @return size greater than or equal 0 or -1 on error
* @error EINVAL if error is due to bad syntax
* @error EOVERFLOW if error is due to overflow
*/
long sizetol(const char *s, long b) {
long x;
int c, e;
int c, e, d;
do {
c = *s++;
} while (c == ' ' || c == '\t');
if (!isdigit(c)) return -1;
d = c == '-' ? -1 : 1;
if (c == '-' || c == '+') c = *s++;
if (!isdigit(c)) {
return einval();
}
x = 0;
do {
if (__builtin_mul_overflow(x, 10, &x) ||
__builtin_add_overflow(x, c - '0', &x)) {
return -1;
__builtin_add_overflow(x, (c - '0') * d, &x)) {
return eoverflow();
}
} while (isdigit((c = *s++)));
if ((e = GetExponent(c)) == -1) return -1;
if ((e = GetExponent(c)) == -1) {
return einval();
}
while (e--) {
if (__builtin_mul_overflow(x, b, &x)) return -1;
if (__builtin_mul_overflow(x, b, &x)) {
return eoverflow();
}
}
return x;
}

View file

@ -16,7 +16,6 @@
TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE.
*/
#include "libc/fmt/fmt.h"
#include "libc/nt/runtime.h"
#include "libc/str/str.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/intrin/safemacros.internal.h"
#include "libc/dce.h"
#include "libc/fmt/fmt.h"
#include "libc/intrin/kprintf.h"
#include "libc/intrin/safemacros.internal.h"
#include "libc/macros.internal.h"
#include "libc/nt/enum/formatmessageflags.h"
#include "libc/nt/enum/lang.h"

View file

@ -36,6 +36,7 @@ COSMOPOLITAN_C_START_
extern FILE *__log_file;
int __watch(void *, size_t);
void __die(void) relegated wontreturn; /* print backtrace and abort() */
void meminfo(int); /* shows malloc statistics &c. */
void memsummary(int); /* light version of same thing */

View file

@ -65,6 +65,10 @@ o/$(MODE)/libc/log/checkfail.o: private \
OVERRIDE_CFLAGS += \
-mgeneral-regs-only
o/$(MODE)/libc/log/watch.o: private \
OVERRIDE_CFLAGS += \
-ffreestanding
o/$(MODE)/libc/log/attachdebugger.o \
o/$(MODE)/libc/log/checkaligned.o \
o/$(MODE)/libc/log/checkfail.o \

65
libc/log/watch-hook.S Normal file
View file

@ -0,0 +1,65 @@
/*-*- mode:unix-assembly; indent-tabs-mode:t; tab-width:8; coding:utf-8 -*-│
vi: set et ft=asm ts=8 tw=8 fenc=utf-8 :vi
Copyright 2021 Justine Alexandra Roberts Tunney
Permission to use, copy, modify, and/or distribute this software for
any purpose with or without fee is hereby granted, provided that the
above copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE.
*/
#include "libc/macros.internal.h"
__watch_hook:
push %rbp
mov %rsp,%rbp
and $-16,%rsp
sub $0x80,%rsp
movaps %xmm0,0x00(%rsp)
movaps %xmm1,0x10(%rsp)
movaps %xmm2,0x20(%rsp)
movaps %xmm3,0x30(%rsp)
movaps %xmm4,0x40(%rsp)
movaps %xmm5,0x50(%rsp)
movaps %xmm6,0x60(%rsp)
movaps %xmm7,0x70(%rsp)
push %rax
push %rax
push %rdi
push %rsi
push %rdx
push %rcx
push %r8
push %r9
push %r10
push %r11
call __watcher
pop %r11
pop %r10
pop %r9
pop %r8
pop %rcx
pop %rdx
pop %rsi
pop %rdi
pop %rax
pop %rax
movaps 0x00(%rsp),%xmm0
movaps 0x10(%rsp),%xmm1
movaps 0x20(%rsp),%xmm2
movaps 0x30(%rsp),%xmm3
movaps 0x40(%rsp),%xmm4
movaps 0x50(%rsp),%xmm5
movaps 0x60(%rsp),%xmm6
movaps 0x70(%rsp),%xmm7
leave
ret
.endfn __watch_hook,globl

87
libc/log/watch.c Normal file
View file

@ -0,0 +1,87 @@
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi
Copyright 2022 Justine Alexandra Roberts Tunney
Permission to use, copy, modify, and/or distribute this software for
any purpose with or without fee is hereby granted, provided that the
above copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE.
*/
#include "libc/intrin/bits.h"
#include "libc/intrin/kprintf.h"
#include "libc/log/backtrace.internal.h"
#include "libc/log/log.h"
#include "libc/runtime/runtime.h"
#include "libc/runtime/symbols.internal.h"
#include "libc/sysv/errfuns.h"
static bool __watch_busy;
static void *__watch_addr;
static size_t __watch_size;
static char __watch_last[4096];
void __watch_hook(void);
static noinstrument inline void Copy(char *p, char *q, size_t n) {
size_t i;
for (i = 0; i < n; ++i) {
p[i] = q[i];
}
}
static noinstrument inline int Cmp(char *p, char *q, size_t n) {
int c;
if (n == 8) return READ64LE(p) != READ64LE(q);
if (n == 4) return READ32LE(p) != READ32LE(q);
for (; n; ++p, ++q, --n) {
if (*p != *q) {
return 1;
}
}
return 0;
}
noinstrument void __watcher(void) {
if (__watch_busy) return;
__watch_busy = true;
if (Cmp(__watch_last, __watch_addr, __watch_size)) {
kprintf("watchpoint %p changed:\n"
"%#.*hhs\n"
"%#.*hhs\n",
__watch_addr, //
__watch_size, __watch_last, //
__watch_size, __watch_addr);
Copy(__watch_last, __watch_addr, __watch_size);
ShowBacktrace(2, __builtin_frame_address(0));
}
__watch_busy = false;
}
/**
* Watches memory address for changes.
*
* It's useful for situations when ASAN and GDB both aren't working.
*/
int __watch(void *addr, size_t size) {
static bool once;
if (__watch_busy) ebusy();
if (size > sizeof(__watch_last)) return einval();
if (!once) {
if (!GetSymbolTable()) return -1;
if (__hook(__watch_hook, GetSymbolTable()) == -1) return -1;
once = true;
}
__watch_addr = addr;
__watch_size = size;
Copy(__watch_last, __watch_addr, __watch_size);
return 0;
}

View file

@ -111,10 +111,6 @@ o//libc/runtime/opensymboltable.greg.o: private \
OVERRIDE_CFLAGS += \
-Os
o/$(MODE)/libc/runtime/ftrace.greg.o: private \
OVERRIDE_CFLAGS += \
-mgeneral-regs-only
LIBC_RUNTIME_LIBS = $(foreach x,$(LIBC_RUNTIME_ARTIFACTS),$($(x)))
LIBC_RUNTIME_SRCS = $(foreach x,$(LIBC_RUNTIME_ARTIFACTS),$($(x)_SRCS))
LIBC_RUNTIME_HDRS = $(foreach x,$(LIBC_RUNTIME_ARTIFACTS),$($(x)_HDRS))

View file

@ -87,7 +87,8 @@ int sys_socketpair_nt_stream(int, int, int, int[2]) hidden;
int sys_socketpair_nt_dgram(int, int, int, int[2]) hidden;
*/
int sys_socketpair_nt(int, int, int, int[2]) hidden;
int sys_select_nt(int, fd_set *, fd_set *, fd_set *, struct timeval *) hidden;
int sys_select_nt(int, fd_set *, fd_set *, fd_set *, struct timeval *,
const sigset_t *) hidden;
size_t __iovec2nt(struct NtIovec[hasatleast 16], const struct iovec *,
size_t) hidden;

View file

@ -18,9 +18,13 @@
*/
#include "libc/calls/strace.internal.h"
#include "libc/calls/struct/timespec.h"
#include "libc/calls/struct/timeval.h"
#include "libc/dce.h"
#include "libc/intrin/asan.internal.h"
#include "libc/intrin/describeflags.internal.h"
#include "libc/sock/internal.h"
#include "libc/sock/select.h"
#include "libc/sysv/errfuns.h"
/**
* Does what poll() does except with bitset API.
@ -32,9 +36,30 @@ int pselect(int nfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds,
const struct timespec *timeout, const sigset_t *sigmask) {
int rc;
sigset_t oldmask;
rc = sys_pselect(nfds, readfds, writefds, exceptfds, timeout, sigmask);
POLLTRACE("pselect(%d, %p, %p, %p, [%s], %s) → %d% m", nfds, readfds,
writefds, exceptfds, DescribeTimeval(rc, timeout),
DescribeSigset(0, sigmask), rc);
struct timeval tv, *tvp;
if (nfds < 0) {
rc = einval();
} else if (IsAsan() &&
((readfds && !__asan_is_valid(readfds, FD_SIZE(nfds))) ||
(writefds && !__asan_is_valid(writefds, FD_SIZE(nfds))) ||
(exceptfds && !__asan_is_valid(exceptfds, FD_SIZE(nfds))) ||
(timeout && !__asan_is_valid(timeout, sizeof(*timeout))) ||
(sigmask && !__asan_is_valid(sigmask, sizeof(*sigmask))))) {
rc = efault();
} else if (!IsWindows()) {
rc = sys_pselect(nfds, readfds, writefds, exceptfds, timeout, sigmask);
} else {
if (timeout) {
tv.tv_sec = timeout->tv_sec;
tv.tv_usec = timeout->tv_nsec / 1000;
tvp = &tv;
} else {
tvp = 0;
}
rc = sys_select_nt(nfds, readfds, writefds, exceptfds, tvp, sigmask);
}
POLLTRACE("pselect(%d, %p, %p, %p, %s, %s) → %d% m", nfds, readfds, writefds,
exceptfds, DescribeTimeval(0, timeout), DescribeSigset(0, sigmask),
rc);
return rc;
}

View file

@ -17,6 +17,7 @@
PERFORMANCE OF THIS SOFTWARE.
*/
#include "libc/calls/internal.h"
#include "libc/calls/state.internal.h"
#include "libc/calls/struct/timeval.h"
#include "libc/macros.internal.h"
#include "libc/sock/select.h"
@ -27,14 +28,12 @@
#include "libc/sysv/errfuns.h"
int sys_select_nt(int nfds, fd_set *readfds, fd_set *writefds,
fd_set *exceptfds, struct timeval *timeout) {
fd_set *exceptfds, struct timeval *timeout,
const sigset_t *sigmask) {
uint64_t millis;
int i, pfds, events, fdcount;
struct pollfd fds[64];
// check for interrupts early before doing work
if (_check_interrupts(false, g_fds.p)) return eintr();
// convert bitsets to pollfd
for (pfds = i = 0; i < nfds; ++i) {
events = 0;
@ -60,7 +59,7 @@ int sys_select_nt(int nfds, fd_set *readfds, fd_set *writefds,
}
// call our nt poll implementation
fdcount = sys_poll_nt(fds, pfds, &millis);
fdcount = sys_poll_nt(fds, pfds, &millis, sigmask);
if (fdcount == -1) return -1;
// convert pollfd back to bitsets

View file

@ -19,9 +19,11 @@
#include "libc/calls/strace.internal.h"
#include "libc/calls/struct/timeval.h"
#include "libc/dce.h"
#include "libc/intrin/asan.internal.h"
#include "libc/intrin/describeflags.internal.h"
#include "libc/sock/internal.h"
#include "libc/sock/select.h"
#include "libc/sysv/errfuns.h"
/**
* Does what poll() does except with bitset API.
@ -35,10 +37,18 @@ int select(int nfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds,
int rc;
POLLTRACE("select(%d, %p, %p, %p, %s) → ...", nfds, readfds, writefds,
exceptfds, DescribeTimeval(0, timeout));
if (!IsWindows()) {
if (nfds < 0) {
rc = einval();
} else if (IsAsan() &&
((readfds && !__asan_is_valid(readfds, FD_SIZE(nfds))) ||
(writefds && !__asan_is_valid(writefds, FD_SIZE(nfds))) ||
(exceptfds && !__asan_is_valid(exceptfds, FD_SIZE(nfds))) ||
(timeout && !__asan_is_valid(timeout, sizeof(*timeout))))) {
rc = efault();
} else if (!IsWindows()) {
rc = sys_select(nfds, readfds, writefds, exceptfds, timeout);
} else {
rc = sys_select_nt(nfds, readfds, writefds, exceptfds, timeout);
rc = sys_select_nt(nfds, readfds, writefds, exceptfds, timeout, 0);
}
POLLTRACE("select(%d, %p, %p, %p, [%s]) → %d% m", nfds, readfds, writefds,
exceptfds, DescribeTimeval(rc, timeout), rc);

View file

@ -11,13 +11,14 @@
COSMOPOLITAN_C_START_
typedef struct fd_set {
uint64_t fds_bits[FD_SETSIZE / 64];
unsigned long fds_bits[FD_SETSIZE / (sizeof(long) * CHAR_BIT)];
} fd_set;
#define FD_ISSET(FD, SET) (((SET)->fds_bits[(FD) >> 6] >> ((FD)&63)) & 1)
#define FD_SET(FD, SET) ((SET)->fds_bits[(FD) >> 6] |= 1ull << ((FD)&63))
#define FD_CLR(FD, SET) ((SET)->fds_bits[(FD) >> 6] &= ~(1ull << ((FD)&63)))
#define FD_ZERO(SET) bzero((SET)->fds_bits, sizeof((SET)->fds_bits))
#define FD_SIZE(bits) (((bits) + (sizeof(long) * CHAR_BIT) - 1) / sizeof(long))
int select(int, fd_set *, fd_set *, fd_set *, struct timeval *);
int pselect(int, fd_set *, fd_set *, fd_set *, const struct timespec *,

View file

@ -1,12 +1,16 @@
#ifndef COSMOPOLITAN_LIBC_SOCK_STRUCT_POLLFD_INTERNAL_H_
#define COSMOPOLITAN_LIBC_SOCK_STRUCT_POLLFD_INTERNAL_H_
#include "libc/calls/struct/sigset.h"
#include "libc/calls/struct/timespec.h"
#include "libc/sock/struct/pollfd.h"
#if !(__ASSEMBLER__ + __LINKER__ + 0)
COSMOPOLITAN_C_START_
int32_t sys_poll(struct pollfd *, uint64_t, signed) hidden;
int sys_ppoll(struct pollfd *, size_t, const struct timespec *,
const sigset_t *);
int sys_poll_metal(struct pollfd *, size_t, unsigned);
int sys_poll_nt(struct pollfd *, uint64_t, uint64_t *) hidden;
int sys_poll_nt(struct pollfd *, uint64_t, uint64_t *, const sigset_t *) hidden;
COSMOPOLITAN_C_END_
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */

View file

@ -105,7 +105,7 @@ static void EmptySignalMask(void) {
}
static void FixIrregularFds(void) {
int i, fd, maxfds;
int e, i, fd, maxfds;
struct rlimit rlim;
struct pollfd *pfds;
for (i = 0; i < 3; ++i) {
@ -118,6 +118,9 @@ static void FixIrregularFds(void) {
}
}
}
e = errno;
if (!closefrom(3)) return;
errno = e;
if (IsWindows()) {
maxfds = 64;
} else {