mirror of
https://github.com/jart/cosmopolitan.git
synced 2025-01-31 03:27:39 +00:00
Implement support for POSIX thread cancellations
This change makes some miracle modifications to the System Five system call support, which lets us have safe, correct, and atomic handling of thread cancellations. It all turned out to be cheaper than anticipated because it wasn't necessary to modify the system call veneers. We were able to encode the cancellability of each system call into the magnums found in libc/sysv/syscalls.sh. Since cancellations are so waq, we are also supporting a lovely Musl Libc mask feature for raising ECANCELED.
This commit is contained in:
parent
37d40e087f
commit
2278327eba
145 changed files with 715 additions and 265 deletions
2
Makefile
2
Makefile
|
@ -61,7 +61,7 @@
|
|||
|
||||
SHELL = build/bootstrap/cocmd.com
|
||||
HOSTS ?= freebsd openbsd netbsd rhel7 rhel5 xnu win10 win10:31336
|
||||
MAKEFLAGS += -j --no-builtin-rules
|
||||
MAKEFLAGS += --no-builtin-rules
|
||||
|
||||
.SUFFIXES:
|
||||
.DELETE_ON_ERROR:
|
||||
|
|
|
@ -204,6 +204,7 @@ textwindows int __sig_raise(int sig, int si_code) {
|
|||
if (1 <= sig && sig <= 64) {
|
||||
if (!__sig_is_masked(sig)) {
|
||||
++__sig_count;
|
||||
// TODO(jart): ucontext_t support
|
||||
__sig_handle(false, sig, si_code, 0);
|
||||
return 0;
|
||||
} else {
|
||||
|
|
|
@ -34,7 +34,7 @@ textwindows int sys_clock_nanosleep_nt(int clock, int flags,
|
|||
for (;;) {
|
||||
if (sys_clock_gettime_nt(clock, &now)) return -1;
|
||||
if (_timespec_gte(now, abs)) return 0;
|
||||
if (_check_interrupts(false, g_fds.p)) return eintr();
|
||||
if (_check_interrupts(false, g_fds.p)) return -1;
|
||||
SleepEx(MIN(__SIG_POLLING_INTERVAL_MS,
|
||||
_timespec_tomillis(_timespec_sub(abs, now))),
|
||||
false);
|
||||
|
@ -47,7 +47,7 @@ textwindows int sys_clock_nanosleep_nt(int clock, int flags,
|
|||
if (_timespec_gte(now, abs)) return 0;
|
||||
if (_check_interrupts(false, g_fds.p)) {
|
||||
if (rem) *rem = _timespec_sub(abs, now);
|
||||
return eintr();
|
||||
return -1;
|
||||
}
|
||||
SleepEx(MIN(__SIG_POLLING_INTERVAL_MS,
|
||||
_timespec_tomillis(_timespec_sub(abs, now))),
|
||||
|
|
|
@ -80,6 +80,7 @@
|
|||
* @raise EINVAL if `flags` has an unrecognized value
|
||||
* @raise EINVAL if `req->tv_nsec ∉ [0,1000000000)`
|
||||
* @raise ENOSYS on bare metal
|
||||
* @cancellationpoint
|
||||
* @returnserrno
|
||||
* @norestart
|
||||
*/
|
||||
|
|
|
@ -26,7 +26,7 @@
|
|||
#include "libc/sysv/consts/o.h"
|
||||
#include "libc/sysv/errfuns.h"
|
||||
|
||||
int sys_fcntl(int fd, int cmd, uintptr_t arg) {
|
||||
int sys_fcntl(int fd, int cmd, uintptr_t arg, int impl(int, int, ...)) {
|
||||
int e, rc;
|
||||
bool islock;
|
||||
if ((islock = cmd == F_GETLK || //
|
||||
|
@ -40,12 +40,12 @@ int sys_fcntl(int fd, int cmd, uintptr_t arg) {
|
|||
cosmo2flock(arg);
|
||||
}
|
||||
e = errno;
|
||||
rc = __sys_fcntl(fd, cmd, arg);
|
||||
rc = impl(fd, cmd, arg);
|
||||
if (islock) {
|
||||
flock2cosmo(arg);
|
||||
} else if (rc == -1 && cmd == F_DUPFD_CLOEXEC && errno == EINVAL) {
|
||||
errno = e;
|
||||
rc = __fixupnewfd(__sys_fcntl(fd, F_DUPFD, arg), O_CLOEXEC);
|
||||
rc = __fixupnewfd(impl(fd, F_DUPFD, arg), O_CLOEXEC);
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
|
|
|
@ -94,6 +94,7 @@
|
|||
* @raise EDEADLK if `cmd` was `F_SETLKW` and waiting would deadlock
|
||||
* @raise EMFILE if `cmd` is `F_DUPFD` or `F_DUPFD_CLOEXEC` and
|
||||
* `RLIMIT_NOFILE` would be exceeded
|
||||
* @cancellationpoint when `cmd` is `F_SETLKW`
|
||||
* @asyncsignalsafe
|
||||
* @restartable
|
||||
*/
|
||||
|
@ -111,7 +112,11 @@ int fcntl(int fd, int cmd, ...) {
|
|||
if (fd < g_fds.n && g_fds.p[fd].kind == kFdZip) {
|
||||
rc = _weaken(__zipos_fcntl)(fd, cmd, arg);
|
||||
} else if (!IsWindows()) {
|
||||
rc = sys_fcntl(fd, cmd, arg);
|
||||
if (cmd == F_SETLKW) {
|
||||
rc = sys_fcntl(fd, cmd, arg, __sys_fcntl_cp);
|
||||
} else {
|
||||
rc = sys_fcntl(fd, cmd, arg, __sys_fcntl);
|
||||
}
|
||||
} else {
|
||||
rc = sys_fcntl_nt(fd, cmd, arg);
|
||||
}
|
||||
|
|
|
@ -30,6 +30,7 @@
|
|||
* @return 0 on success, or -1 w/ errno
|
||||
* @see sync(), fsync(), sync_file_range()
|
||||
* @see __nosync to secretly disable
|
||||
* @cancellationpoint
|
||||
* @asyncsignalsafe
|
||||
*/
|
||||
int fdatasync(int fd) {
|
||||
|
|
|
@ -17,10 +17,10 @@
|
|||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/calls/calls.h"
|
||||
#include "libc/intrin/strace.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"
|
||||
|
||||
/**
|
||||
* Acquires lock on file.
|
||||
|
@ -30,6 +30,7 @@
|
|||
* @param op can have LOCK_{SH,EX,NB,UN} for shared, exclusive,
|
||||
* non-blocking, and unlocking
|
||||
* @return 0 on success, or -1 w/ errno
|
||||
* @cancellationpoint
|
||||
* @restartable
|
||||
*/
|
||||
int flock(int fd, int op) {
|
||||
|
|
|
@ -18,16 +18,17 @@
|
|||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/calls/calls.h"
|
||||
#include "libc/calls/internal.h"
|
||||
#include "libc/intrin/strace.internal.h"
|
||||
#include "libc/calls/struct/statfs-meta.internal.h"
|
||||
#include "libc/calls/struct/statfs.internal.h"
|
||||
#include "libc/dce.h"
|
||||
#include "libc/intrin/strace.internal.h"
|
||||
#include "libc/runtime/stack.h"
|
||||
#include "libc/sysv/errfuns.h"
|
||||
|
||||
/**
|
||||
* Returns information about filesystem.
|
||||
* @return 0 on success, or -1 w/ errno
|
||||
* @cancellationpoint
|
||||
*/
|
||||
int fstatfs(int fd, struct statfs *sf) {
|
||||
int rc;
|
||||
|
|
|
@ -30,6 +30,7 @@
|
|||
* @return 0 on success, or -1 w/ errno
|
||||
* @see fdatasync(), sync_file_range()
|
||||
* @see __nosync to secretly disable
|
||||
* @cancellationpoint
|
||||
* @asyncsignalsafe
|
||||
*/
|
||||
int fsync(int fd) {
|
||||
|
|
|
@ -56,7 +56,7 @@
|
|||
* @raise EINVAL if `fd` is a non-file, e.g. pipe, socket
|
||||
* @raise EINVAL if `fd` wasn't opened in a writeable mode
|
||||
* @raise ENOSYS on bare metal
|
||||
* @see truncate()
|
||||
* @cancellationpoint
|
||||
* @asyncsignalsafe
|
||||
* @threadsafe
|
||||
*/
|
||||
|
|
|
@ -43,7 +43,7 @@ forceinline size_t _clampio(size_t size) {
|
|||
}
|
||||
|
||||
int sys_close_nt(struct Fd *, int) hidden;
|
||||
bool _check_interrupts(bool, struct Fd *) hidden;
|
||||
int _check_interrupts(bool, struct Fd *) hidden;
|
||||
int sys_openat_metal(int, const char *, int, unsigned);
|
||||
|
||||
COSMOPOLITAN_C_END_
|
||||
|
|
|
@ -18,24 +18,33 @@
|
|||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/assert.h"
|
||||
#include "libc/calls/calls.h"
|
||||
#include "libc/calls/internal.h"
|
||||
#include "libc/calls/sig.internal.h"
|
||||
#include "libc/calls/state.internal.h"
|
||||
#include "libc/calls/struct/fd.internal.h"
|
||||
#include "libc/calls/struct/sigaction.h"
|
||||
#include "libc/calls/syscall_support-nt.internal.h"
|
||||
#include "libc/dce.h"
|
||||
#include "libc/errno.h"
|
||||
#include "libc/intrin/lockcmpxchgp.h"
|
||||
#include "libc/intrin/strace.internal.h"
|
||||
#include "libc/intrin/weaken.h"
|
||||
#include "libc/sysv/errfuns.h"
|
||||
#include "libc/thread/thread.h"
|
||||
#include "libc/thread/tls.h"
|
||||
|
||||
textwindows bool _check_interrupts(bool restartable, struct Fd *fd) {
|
||||
bool res;
|
||||
textwindows int _check_interrupts(bool restartable, struct Fd *fd) {
|
||||
int rc;
|
||||
if (_weaken(pthread_testcancel_np) &&
|
||||
(rc = _weaken(pthread_testcancel_np)())) {
|
||||
errno = rc;
|
||||
return -1;
|
||||
}
|
||||
if (_weaken(_check_sigalrm)) _weaken(_check_sigalrm)();
|
||||
if (!__tls_enabled || !(__get_tls()->tib_flags & TIB_FLAG_TIME_CRITICAL)) {
|
||||
if (_weaken(_check_sigchld)) _weaken(_check_sigchld)();
|
||||
if (fd && _weaken(_check_sigwinch)) _weaken(_check_sigwinch)(fd);
|
||||
}
|
||||
res = _weaken(__sig_check) && _weaken(__sig_check)(restartable);
|
||||
return res;
|
||||
if (_weaken(__sig_check) && _weaken(__sig_check)(restartable)) return eintr();
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -32,6 +32,7 @@
|
|||
* @raise EFAULT if `req` is NULL or `req` / `rem` is a bad pointer
|
||||
* @raise ENOSYS on bare metal
|
||||
* @see clock_nanosleep()
|
||||
* @cancellationpoint
|
||||
* @norestart
|
||||
*/
|
||||
int nanosleep(const struct timespec *req, struct timespec *rem) {
|
||||
|
|
|
@ -21,6 +21,8 @@
|
|||
#include "libc/nt/struct/context.h"
|
||||
#include "libc/str/str.h"
|
||||
|
||||
// TODO(jart): uc_sigmask support
|
||||
|
||||
privileged void _ntcontext2linux(ucontext_t *ctx, const struct NtContext *cr) {
|
||||
if (!cr) return;
|
||||
ctx->uc_mcontext.eflags = cr->EFlags;
|
||||
|
|
|
@ -29,6 +29,7 @@
|
|||
* @param file specifies filesystem path to open
|
||||
* @return file descriptor, or -1 w/ errno
|
||||
* @see openat() for further documentation
|
||||
* @cancellationpoint
|
||||
* @asyncsignalsafe
|
||||
* @restartable
|
||||
* @threadsafe
|
||||
|
|
|
@ -141,6 +141,7 @@
|
|||
* @raise ELOOP if `flags` had `O_NOFOLLOW` and `file` is a symbolic link
|
||||
* @raise ELOOP if a loop was detected resolving components of `file`
|
||||
* @raise EISDIR if writing is requested and `file` names a directory
|
||||
* @cancellationpoint
|
||||
* @asyncsignalsafe
|
||||
* @restartable
|
||||
* @threadsafe
|
||||
|
|
|
@ -18,8 +18,9 @@
|
|||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/calls/internal.h"
|
||||
#include "libc/calls/sig.internal.h"
|
||||
#include "libc/intrin/strace.internal.h"
|
||||
#include "libc/calls/syscall_support-nt.internal.h"
|
||||
#include "libc/errno.h"
|
||||
#include "libc/intrin/strace.internal.h"
|
||||
#include "libc/nt/errors.h"
|
||||
#include "libc/nt/synchronization.h"
|
||||
#include "libc/sysv/errfuns.h"
|
||||
|
@ -31,7 +32,7 @@ textwindows int sys_pause_nt(void) {
|
|||
for (;;) {
|
||||
|
||||
if (_check_interrupts(false, g_fds.p)) {
|
||||
return eintr();
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (SleepEx(__SIG_POLLING_INTERVAL_MS, true) == kNtWaitIoCompletion) {
|
||||
|
|
|
@ -17,9 +17,9 @@
|
|||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/calls/calls.h"
|
||||
#include "libc/intrin/strace.internal.h"
|
||||
#include "libc/calls/syscall_support-nt.internal.h"
|
||||
#include "libc/dce.h"
|
||||
#include "libc/intrin/strace.internal.h"
|
||||
#include "libc/sock/internal.h"
|
||||
|
||||
/**
|
||||
|
@ -37,6 +37,7 @@
|
|||
* However this has a tinier footprint and better logging.
|
||||
*
|
||||
* @return -1 w/ errno set to EINTR
|
||||
* @cancellationpoint
|
||||
* @see sigsuspend()
|
||||
* @norestart
|
||||
*/
|
||||
|
|
|
@ -21,7 +21,6 @@
|
|||
#include "libc/calls/sig.internal.h"
|
||||
#include "libc/calls/state.internal.h"
|
||||
#include "libc/calls/struct/sigaction.h"
|
||||
#include "libc/errno.h"
|
||||
#include "libc/intrin/bits.h"
|
||||
#include "libc/intrin/strace.internal.h"
|
||||
#include "libc/macros.internal.h"
|
||||
|
@ -64,8 +63,7 @@ textwindows int sys_poll_nt(struct pollfd *fds, uint64_t nfds, uint64_t *ms,
|
|||
if (sigmask) {
|
||||
__sig_mask(SIG_SETMASK, sigmask, &oldmask);
|
||||
}
|
||||
if (_check_interrupts(false, g_fds.p)) {
|
||||
rc = eintr();
|
||||
if ((rc = _check_interrupts(false, g_fds.p))) {
|
||||
goto ReturnPath;
|
||||
}
|
||||
|
||||
|
@ -190,8 +188,7 @@ textwindows int sys_poll_nt(struct pollfd *fds, uint64_t nfds, uint64_t *ms,
|
|||
}
|
||||
// otherwise loop limitlessly for timeout to elapse while
|
||||
// checking for signal delivery interrupts, along the way
|
||||
if (_check_interrupts(false, g_fds.p)) {
|
||||
rc = eintr();
|
||||
if ((rc = _check_interrupts(false, g_fds.p))) {
|
||||
goto ReturnPath;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -55,6 +55,7 @@
|
|||
* @return fds[𝑖].revents is always zero initializaed and then will
|
||||
* be populated with POLL{IN,OUT,PRI,HUP,ERR,NVAL} if something
|
||||
* was determined about the file descriptor
|
||||
* @cancellationpoint
|
||||
* @asyncsignalsafe
|
||||
* @threadsafe
|
||||
* @norestart
|
||||
|
|
|
@ -50,6 +50,7 @@
|
|||
*
|
||||
* @param timeout if null will block indefinitely
|
||||
* @param sigmask may be null in which case no mask change happens
|
||||
* @cancellationpoint
|
||||
* @asyncsignalsafe
|
||||
* @threadsafe
|
||||
* @norestart
|
||||
|
|
|
@ -48,6 +48,7 @@
|
|||
* @raise EIO if a complicated i/o error happened
|
||||
* @raise EINTR if signal was delivered instead
|
||||
* @see pwrite(), write()
|
||||
* @cancellationpoint
|
||||
* @asyncsignalsafe
|
||||
* @threadsafe
|
||||
* @vforksafe
|
||||
|
|
|
@ -108,6 +108,7 @@ static ssize_t Preadv(int fd, struct iovec *iov, int iovlen, int64_t off) {
|
|||
* Reads with maximum generality.
|
||||
*
|
||||
* @return number of bytes actually read, or -1 w/ errno
|
||||
* @cancellationpoint
|
||||
* @asyncsignalsafe
|
||||
* @vforksafe
|
||||
*/
|
||||
|
|
|
@ -42,6 +42,7 @@
|
|||
* @return [1..size] bytes on success, or -1 w/ errno; noting zero is
|
||||
* impossible unless size was passed as zero to do an error check
|
||||
* @see pread(), write()
|
||||
* @cancellationpoint
|
||||
* @asyncsignalsafe
|
||||
* @threadsafe
|
||||
* @vforksafe
|
||||
|
|
|
@ -114,6 +114,7 @@ static ssize_t Pwritev(int fd, const struct iovec *iov, int iovlen,
|
|||
* call using pwrite().
|
||||
*
|
||||
* @return number of bytes actually sent, or -1 w/ errno
|
||||
* @cancellationpoint
|
||||
* @asyncsignalsafe
|
||||
* @vforksafe
|
||||
*/
|
||||
|
|
|
@ -53,7 +53,7 @@ static textwindows ssize_t sys_read_nt_impl(struct Fd *fd, void *data,
|
|||
}
|
||||
if (_check_interrupts(true, g_fds.p)) {
|
||||
POLLTRACE("sys_read_nt interrupted");
|
||||
return eintr();
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
POLLTRACE("sys_read_nt ready to read");
|
||||
|
@ -94,7 +94,7 @@ textwindows ssize_t sys_read_nt(struct Fd *fd, const struct iovec *iov,
|
|||
uint32_t size;
|
||||
size_t i, total;
|
||||
if (opt_offset < -1) return einval();
|
||||
if (_check_interrupts(true, fd)) return eintr();
|
||||
if (_check_interrupts(true, fd)) return -1;
|
||||
while (iovlen && !iov[0].iov_len) iov++, iovlen--;
|
||||
if (iovlen) {
|
||||
for (total = i = 0; i < iovlen; ++i) {
|
||||
|
|
|
@ -56,6 +56,7 @@
|
|||
* or `SO_RCVTIMEO` is in play and the time interval elapsed
|
||||
* @raise ENOBUFS is specified by POSIX
|
||||
* @raise ENXIO is specified by POSIX
|
||||
* @cancellationpoint
|
||||
* @asyncsignalsafe
|
||||
* @restartable
|
||||
* @vforksafe
|
||||
|
|
|
@ -43,6 +43,7 @@
|
|||
* performance boost in the case of a single small iovec.
|
||||
*
|
||||
* @return number of bytes actually read, or -1 w/ errno
|
||||
* @cancellationpoint
|
||||
* @restartable
|
||||
*/
|
||||
ssize_t readv(int fd, const struct iovec *iov, int iovlen) {
|
||||
|
|
|
@ -17,15 +17,10 @@
|
|||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/calls/struct/sigset.h"
|
||||
#include "libc/str/str.h"
|
||||
|
||||
/**
|
||||
* Blocks all signals without strace logging.
|
||||
*
|
||||
* @param neu is new signal mask for process
|
||||
* @return old signal mask
|
||||
*/
|
||||
sigset_t _sigblockall(void) {
|
||||
sigset_t ss;
|
||||
sigfillset(&ss);
|
||||
memset(&ss, -1, sizeof(ss));
|
||||
return _sigsetmask(ss);
|
||||
}
|
||||
|
|
|
@ -75,6 +75,11 @@ privileged void __sigenter_netbsd(int sig, struct siginfo_netbsd *si,
|
|||
uc.uc_mcontext.rsp = ctx->uc_mcontext.rsp;
|
||||
*uc.uc_mcontext.fpregs = ctx->uc_mcontext.__fpregs;
|
||||
((sigaction_f)(_base + rva))(sig, &si2, &uc);
|
||||
ctx->uc_stack.ss_sp = uc.uc_stack.ss_sp;
|
||||
ctx->uc_stack.ss_size = uc.uc_stack.ss_size;
|
||||
ctx->uc_stack.ss_flags = uc.uc_stack.ss_flags;
|
||||
__repmovsb(&ctx->uc_sigmask, &uc.uc_sigmask,
|
||||
MIN(sizeof(uc.uc_sigmask), sizeof(ctx->uc_sigmask)));
|
||||
ctx->uc_mcontext.rdi = uc.uc_mcontext.rdi;
|
||||
ctx->uc_mcontext.rsi = uc.uc_mcontext.rsi;
|
||||
ctx->uc_mcontext.rdx = uc.uc_mcontext.rdx;
|
||||
|
|
|
@ -76,6 +76,7 @@ privileged void __sigenter_openbsd(int sig, struct siginfo_openbsd *openbsdinfo,
|
|||
*g.uc.uc_mcontext.fpregs = *ctx->sc_fpstate;
|
||||
}
|
||||
((sigaction_f)(_base + rva))(sig, &g.si, &g.uc);
|
||||
ctx->sc_mask = g.uc.uc_sigmask.__bits[0];
|
||||
ctx->sc_rdi = g.uc.uc_mcontext.rdi;
|
||||
ctx->sc_rsi = g.uc.uc_mcontext.rsi;
|
||||
ctx->sc_rdx = g.uc.uc_mcontext.rdx;
|
||||
|
|
|
@ -501,6 +501,7 @@ privileged void __sigenter_xnu(void *fn, int infostyle, int sig,
|
|||
xnuctx->uc_stack.ss_sp = g.uc.uc_stack.ss_sp;
|
||||
xnuctx->uc_stack.ss_flags = g.uc.uc_stack.ss_flags;
|
||||
xnuctx->uc_stack.ss_size = g.uc.uc_stack.ss_size;
|
||||
xnuctx->uc_sigmask = g.uc.uc_sigmask.__bits[0];
|
||||
if (xnuctx->uc_mcontext) {
|
||||
if (xnuctx->uc_mcsize >=
|
||||
sizeof(struct __darwin_x86_exception_state64)) {
|
||||
|
|
|
@ -26,6 +26,7 @@
|
|||
#include "libc/intrin/asan.internal.h"
|
||||
#include "libc/intrin/describeflags.internal.h"
|
||||
#include "libc/intrin/strace.internal.h"
|
||||
#include "libc/intrin/weaken.h"
|
||||
#include "libc/str/str.h"
|
||||
#include "libc/sysv/consts/sig.h"
|
||||
#include "libc/sysv/errfuns.h"
|
||||
|
@ -59,7 +60,9 @@ int sigprocmask(int how, const sigset_t *opt_set, sigset_t *opt_out_oldset) {
|
|||
rc = efault();
|
||||
} else if (IsMetal() || IsWindows()) {
|
||||
rc = __sig_mask(how, opt_set, &old);
|
||||
_check_interrupts(false, 0);
|
||||
if (_weaken(__sig_check)) {
|
||||
_weaken(__sig_check)(true);
|
||||
}
|
||||
} else {
|
||||
rc = sys_sigprocmask(how, opt_set, opt_out_oldset ? &old : 0);
|
||||
}
|
||||
|
|
|
@ -23,12 +23,6 @@
|
|||
#include "libc/dce.h"
|
||||
#include "libc/sysv/consts/sig.h"
|
||||
|
||||
/**
|
||||
* Sets signal mask without strace logging.
|
||||
*
|
||||
* @param neu is new signal mask for process
|
||||
* @return old signal mask
|
||||
*/
|
||||
sigset_t _sigsetmask(sigset_t neu) {
|
||||
sigset_t res;
|
||||
if (IsMetal() || IsWindows()) {
|
||||
|
|
|
@ -40,6 +40,7 @@
|
|||
* @param ignore is a bitset of signals to block temporarily, which if
|
||||
* NULL is equivalent to passing an empty signal set
|
||||
* @return -1 w/ EINTR (or possibly EFAULT)
|
||||
* @cancellationpoint
|
||||
* @asyncsignalsafe
|
||||
* @norestart
|
||||
*/
|
||||
|
@ -72,8 +73,7 @@ int sigsuspend(const sigset_t *ignore) {
|
|||
ms = 0;
|
||||
totoms = 0;
|
||||
do {
|
||||
if (_check_interrupts(false, g_fds.p)) {
|
||||
rc = eintr();
|
||||
if ((rc = _check_interrupts(false, g_fds.p))) {
|
||||
break;
|
||||
}
|
||||
if (SleepEx(__SIG_POLLING_INTERVAL_MS, true) == kNtWaitIoCompletion) {
|
||||
|
|
|
@ -40,6 +40,7 @@
|
|||
* @raise EAGAIN if deadline expired
|
||||
* @raise ENOSYS on Windows, XNU, OpenBSD, Metal
|
||||
* @raise EFAULT if invalid memory was supplied
|
||||
* @cancellationpoint
|
||||
*/
|
||||
int sigtimedwait(const sigset_t *set, siginfo_t *info,
|
||||
const struct timespec *timeout) {
|
||||
|
|
|
@ -27,6 +27,7 @@
|
|||
* @raise EINTR if an asynchronous signal was delivered instead
|
||||
* @raise ENOSYS on OpenBSD, XNU, and Windows
|
||||
* @see sigtimedwait()
|
||||
* @cancellationpoint
|
||||
*/
|
||||
int sigwaitinfo(const sigset_t *mask, siginfo_t *si) {
|
||||
return sigtimedwait(mask, si, 0);
|
||||
|
|
|
@ -29,6 +29,7 @@
|
|||
* this function shall return the number of unslept seconds rounded
|
||||
* using the ceiling function
|
||||
* @see clock_nanosleep()
|
||||
* @cancellationpoint
|
||||
* @asyncsignalsafe
|
||||
* @norestart
|
||||
*/
|
||||
|
|
|
@ -18,17 +18,18 @@
|
|||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/calls/calls.h"
|
||||
#include "libc/calls/state.internal.h"
|
||||
#include "libc/intrin/strace.internal.h"
|
||||
#include "libc/calls/struct/statfs-meta.internal.h"
|
||||
#include "libc/calls/struct/statfs.internal.h"
|
||||
#include "libc/calls/syscall_support-nt.internal.h"
|
||||
#include "libc/dce.h"
|
||||
#include "libc/intrin/strace.internal.h"
|
||||
#include "libc/runtime/stack.h"
|
||||
#include "libc/sysv/consts/at.h"
|
||||
|
||||
/**
|
||||
* Returns information about filesystem.
|
||||
* @return 0 on success, or -1 w/ errno
|
||||
* @cancellationpoint
|
||||
*/
|
||||
int statfs(const char *path, struct statfs *sf) {
|
||||
int rc;
|
||||
|
|
|
@ -18,6 +18,7 @@ char *sys_getcwd_xnu(char *, u64) hidden;
|
|||
i32 __sys_dup3(i32, i32, i32) hidden;
|
||||
i32 __sys_execve(const char *, char *const[], char *const[]) hidden;
|
||||
i32 __sys_fcntl(i32, i32, ...) hidden;
|
||||
i32 __sys_fcntl_cp(i32, i32, ...) hidden;
|
||||
i32 __sys_fstat(i32, void *) hidden;
|
||||
i32 __sys_fstatat(i32, const char *, void *, i32) hidden;
|
||||
i32 __sys_gettid(i64 *) hidden;
|
||||
|
@ -43,7 +44,7 @@ i32 sys_fchmod(i32, u32) hidden;
|
|||
i32 sys_fchmodat(i32, const char *, u32, u32) hidden;
|
||||
i32 sys_fchown(i64, u32, u32) hidden;
|
||||
i32 sys_fchownat(i32, const char *, u32, u32, u32) hidden;
|
||||
i32 sys_fcntl(i32, i32, u64) hidden;
|
||||
i32 sys_fcntl(i32, i32, u64, i32 (*)(i32, i32, ...)) hidden;
|
||||
i32 sys_fdatasync(i32) hidden;
|
||||
i32 sys_flock(i32, i32) hidden;
|
||||
i32 sys_fork(void) hidden;
|
||||
|
@ -59,6 +60,7 @@ i32 sys_getresuid(u32 *, u32 *, u32 *) hidden;
|
|||
i32 sys_getsid(i32) hidden;
|
||||
i32 sys_gettid(void) hidden;
|
||||
i32 sys_ioctl(i32, u64, ...) hidden;
|
||||
i32 sys_ioctl_cp(i32, u64, ...) hidden;
|
||||
i32 sys_issetugid(void) hidden;
|
||||
i32 sys_kill(i32, i32, i32) hidden;
|
||||
i32 sys_linkat(i32, const char *, i32, const char *, i32) hidden;
|
||||
|
|
|
@ -40,6 +40,7 @@ static textwindows int sys_tcdrain_nt(int fd) {
|
|||
* @raise EIO if process group of writer is orphoned, calling thread is
|
||||
* not blocking `SIGTTOU`, and process isn't ignoring `SIGTTOU`
|
||||
* @raise ENOSYS on bare metal
|
||||
* @cancellationpoint
|
||||
* @asyncsignalsafe
|
||||
*/
|
||||
int tcdrain(int fd) {
|
||||
|
@ -47,7 +48,7 @@ int tcdrain(int fd) {
|
|||
if (IsMetal()) {
|
||||
rc = enosys();
|
||||
} else if (!IsWindows()) {
|
||||
rc = sys_ioctl(fd, TCSBRK, (void *)(intptr_t)1);
|
||||
rc = sys_ioctl_cp(fd, TCSBRK, (void *)(intptr_t)1);
|
||||
} else {
|
||||
rc = sys_tcdrain_nt(fd);
|
||||
}
|
||||
|
|
|
@ -58,6 +58,7 @@
|
|||
* @raise ETXTBSY if `path` is an executable being executed
|
||||
* @raise EROFS if `path` is on a read-only filesystem
|
||||
* @raise ENOSYS on bare metal
|
||||
* @cancellationpoint
|
||||
* @see ftruncate()
|
||||
* @threadsafe
|
||||
*/
|
||||
|
|
|
@ -27,6 +27,7 @@
|
|||
* @return 0 on success, or -1 w/ errno
|
||||
* @raise EINTR if a signal was delivered while sleeping
|
||||
* @see clock_nanosleep()
|
||||
* @cancellationpoint
|
||||
* @norestart
|
||||
*/
|
||||
int usleep(uint32_t micros) {
|
||||
|
|
|
@ -24,6 +24,7 @@
|
|||
* @param opt_out_wstatus optionally returns status code, and *wstatus
|
||||
* may be inspected using WEEXITSTATUS(), etc.
|
||||
* @return process id of terminated child or -1 w/ errno
|
||||
* @cancellationpoint
|
||||
* @asyncsignalsafe
|
||||
* @restartable
|
||||
* @vforksafe
|
||||
|
|
|
@ -27,6 +27,7 @@
|
|||
* @param options can have WNOHANG, WUNTRACED, WCONTINUED, etc.
|
||||
* @param opt_out_rusage optionally returns accounting data
|
||||
* @return process id of terminated child or -1 w/ errno
|
||||
* @cancellationpoint
|
||||
* @asyncsignalsafe
|
||||
* @restartable
|
||||
*/
|
||||
|
|
|
@ -48,15 +48,15 @@
|
|||
static textwindows int sys_wait4_nt_impl(int pid, int *opt_out_wstatus,
|
||||
int options,
|
||||
struct rusage *opt_out_rusage) {
|
||||
int pids[64];
|
||||
int64_t handle;
|
||||
int rc, pids[64];
|
||||
int64_t handles[64];
|
||||
uint32_t dwExitCode;
|
||||
bool shouldinterrupt;
|
||||
uint32_t i, j, base, count, timeout;
|
||||
struct NtProcessMemoryCountersEx memcount;
|
||||
struct NtFileTime createfiletime, exitfiletime, kernelfiletime, userfiletime;
|
||||
if (_check_interrupts(true, g_fds.p)) return eintr();
|
||||
if (_check_interrupts(true, g_fds.p)) return -1;
|
||||
__fds_lock();
|
||||
if (pid != -1 && pid != 0) {
|
||||
if (pid < 0) {
|
||||
|
@ -94,7 +94,7 @@ static textwindows int sys_wait4_nt_impl(int pid, int *opt_out_wstatus,
|
|||
}
|
||||
__fds_unlock();
|
||||
for (;;) {
|
||||
if (_check_interrupts(true, 0)) return eintr();
|
||||
if (_check_interrupts(true, 0)) return -1;
|
||||
dwExitCode = kNtStillActive;
|
||||
if (options & WNOHANG) {
|
||||
i = WaitForMultipleObjects(count, handles, false, 0);
|
||||
|
|
|
@ -17,11 +17,11 @@
|
|||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/calls/calls.h"
|
||||
#include "libc/intrin/strace.internal.h"
|
||||
#include "libc/calls/struct/rusage.internal.h"
|
||||
#include "libc/calls/wait4.h"
|
||||
#include "libc/dce.h"
|
||||
#include "libc/intrin/asan.internal.h"
|
||||
#include "libc/intrin/strace.internal.h"
|
||||
#include "libc/sysv/errfuns.h"
|
||||
|
||||
/**
|
||||
|
@ -34,6 +34,7 @@
|
|||
* @param options can have WNOHANG, WUNTRACED, WCONTINUED, etc.
|
||||
* @param opt_out_rusage optionally returns accounting data
|
||||
* @return process id of terminated child or -1 w/ errno
|
||||
* @cancellationpoint
|
||||
* @asyncsignalsafe
|
||||
* @restartable
|
||||
*/
|
||||
|
|
|
@ -27,6 +27,7 @@
|
|||
* may be inspected using WEXITSTATUS(), etc.
|
||||
* @param options can have WNOHANG, WUNTRACED, WCONTINUED, etc.
|
||||
* @return process id of terminated child or -1 w/ errno
|
||||
* @cancellationpoint
|
||||
* @asyncsignalsafe
|
||||
* @restartable
|
||||
*/
|
||||
|
|
|
@ -57,6 +57,7 @@
|
|||
* as a general possibility; whereas other system don't specify it
|
||||
* @raise ENXIO is specified only by POSIX and XNU when a request is
|
||||
* made of a nonexistent device or outside device capabilities
|
||||
* @cancellationpoint
|
||||
* @asyncsignalsafe
|
||||
* @restartable
|
||||
* @vforksafe
|
||||
|
|
|
@ -47,6 +47,7 @@
|
|||
* call using write().
|
||||
*
|
||||
* @return number of bytes actually handed off, or -1 w/ errno
|
||||
* @cancellationpoint
|
||||
* @restartable
|
||||
*/
|
||||
ssize_t writev(int fd, const struct iovec *iov, int iovlen) {
|
||||
|
|
|
@ -62,6 +62,7 @@ kSignalNames:
|
|||
.e SIGIO,"SIGIO"
|
||||
.e SIGSYS,"SIGSYS"
|
||||
.e SIGINFO,"SIGINFO"
|
||||
.e SIGCANCEL,"SIGCANCEL"
|
||||
.e SIGRTMAX,"SIGRTMAX"
|
||||
.e SIGRTMIN,"SIGRTMIN"
|
||||
.e SIGEMT,"SIGEMT"
|
||||
|
|
|
@ -33,12 +33,7 @@ int sigaddset(sigset_t *set, int sig) {
|
|||
_Static_assert(sizeof(set->__bits[0]) * CHAR_BIT == 64, "");
|
||||
if (1 <= sig && sig <= NSIG) {
|
||||
if (1 <= sig && sig <= _NSIG) {
|
||||
if (
|
||||
#define M(x) sig != x &&
|
||||
#include "libc/intrin/sigisprecious.inc"
|
||||
1) {
|
||||
set->__bits[(sig - 1) >> 6] |= 1ull << ((sig - 1) & 63);
|
||||
}
|
||||
set->__bits[(sig - 1) >> 6] |= 1ull << ((sig - 1) & 63);
|
||||
}
|
||||
return 0;
|
||||
} else {
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
M(SIGKILL)
|
||||
M(SIGABRT)
|
||||
M(SIGSTOP)
|
||||
M(SIGCANCEL)
|
||||
|
|
|
@ -34,6 +34,7 @@
|
|||
* @param addr needs to be 4096-byte page aligned
|
||||
* @param flags needs MS_ASYNC or MS_SYNC and can have MS_INVALIDATE
|
||||
* @return 0 on success or -1 w/ errno
|
||||
* @cancellationpoint
|
||||
*/
|
||||
int msync(void *addr, size_t size, int flags) {
|
||||
int rc;
|
||||
|
|
|
@ -32,10 +32,10 @@
|
|||
textwindows int sys_accept_nt(struct Fd *fd, void *addr, uint32_t *addrsize,
|
||||
int flags) {
|
||||
int64_t h;
|
||||
int client, oflags;
|
||||
int rc, client, oflags;
|
||||
struct SockFd *sockfd, *sockfd2;
|
||||
sockfd = (struct SockFd *)fd->extra;
|
||||
if (_check_interrupts(true, g_fds.p)) return eintr();
|
||||
if (_check_interrupts(true, g_fds.p)) return -1;
|
||||
for (;;) {
|
||||
if (!WSAPoll(&(struct sys_pollfd_nt){fd->handle, POLLIN}, 1,
|
||||
__SIG_POLLING_INTERVAL_MS)) {
|
||||
|
|
|
@ -26,6 +26,7 @@
|
|||
* @param out_addr will receive the remote address
|
||||
* @param inout_addrsize provides and receives addr's byte length
|
||||
* @return client fd which needs close(), or -1 w/ errno
|
||||
* @cancellationpoint
|
||||
* @asyncsignalsafe
|
||||
* @restartable (unless SO_RCVTIMEO)
|
||||
*/
|
||||
|
|
|
@ -36,6 +36,7 @@
|
|||
* @param flags can have SOCK_{CLOEXEC,NONBLOCK}, which may apply to
|
||||
* both the newly created socket and the server one
|
||||
* @return client fd which needs close(), or -1 w/ errno
|
||||
* @cancellationpoint
|
||||
* @asyncsignalsafe
|
||||
* @restartable (unless SO_RCVTIMEO)
|
||||
*/
|
||||
|
|
|
@ -35,6 +35,7 @@
|
|||
* also means getsockname() can be called to retrieve routing details.
|
||||
*
|
||||
* @return 0 on success or -1 w/ errno
|
||||
* @cancellationpoint
|
||||
* @asyncsignalsafe
|
||||
* @restartable (unless SO_RCVTIMEO)
|
||||
*/
|
||||
|
|
|
@ -1499,6 +1499,7 @@ int epoll_ctl(int epfd, int op, int fd, struct epoll_event *ev) {
|
|||
* @param maxevents is array length of events
|
||||
* @param timeoutms is milliseconds, 0 to not block, or -1 for forever
|
||||
* @return number of events stored, 0 on timeout, or -1 w/ errno
|
||||
* @cancellationpoint
|
||||
* @norestart
|
||||
*/
|
||||
int epoll_wait(int epfd, struct epoll_event *events, int maxevents,
|
||||
|
|
|
@ -16,12 +16,12 @@
|
|||
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/intrin/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/intrin/strace.internal.h"
|
||||
#include "libc/sock/internal.h"
|
||||
#include "libc/sock/select.h"
|
||||
#include "libc/sysv/errfuns.h"
|
||||
|
@ -44,6 +44,11 @@
|
|||
*
|
||||
* This system call is supported on all platforms. It's like select()
|
||||
* except that it atomically changes the sigprocmask() during the op.
|
||||
*
|
||||
* @cancellationpoint
|
||||
* @asyncsignalsafe
|
||||
* @threadsafe
|
||||
* @norestart
|
||||
*/
|
||||
int pselect(int nfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds,
|
||||
const struct timespec *timeout, const sigset_t *sigmask) {
|
||||
|
|
|
@ -34,7 +34,7 @@ textwindows ssize_t sys_recv_nt(struct Fd *fd, const struct iovec *iov,
|
|||
struct SockFd *sockfd;
|
||||
struct NtIovec iovnt[16];
|
||||
struct NtOverlapped overlapped = {.hEvent = WSACreateEvent()};
|
||||
if (_check_interrupts(true, g_fds.p)) return eintr();
|
||||
if (_check_interrupts(true, g_fds.p)) return -1;
|
||||
err = errno;
|
||||
if (!WSARecv(fd->handle, iovnt, __iovec2nt(iovnt, iov, iovlen), &got, &flags,
|
||||
&overlapped, NULL)) {
|
||||
|
|
|
@ -35,7 +35,7 @@ textwindows ssize_t sys_recvfrom_nt(struct Fd *fd, const struct iovec *iov,
|
|||
struct SockFd *sockfd;
|
||||
struct NtIovec iovnt[16];
|
||||
struct NtOverlapped overlapped = {.hEvent = WSACreateEvent()};
|
||||
if (_check_interrupts(true, g_fds.p)) return eintr();
|
||||
if (_check_interrupts(true, g_fds.p)) return -1;
|
||||
err = errno;
|
||||
if (!WSARecvFrom(fd->handle, iovnt, __iovec2nt(iovnt, iov, iovlen), &got,
|
||||
&flags, opt_out_srcaddr, opt_inout_srcaddrsize, &overlapped,
|
||||
|
|
|
@ -44,6 +44,7 @@
|
|||
* @return number of bytes received, 0 on remote close, or -1 w/ errno
|
||||
* @error EINTR, EHOSTUNREACH, ECONNRESET (UDP ICMP Port Unreachable),
|
||||
* EPIPE (if MSG_NOSIGNAL), EMSGSIZE, ENOTSOCK, EFAULT, etc.
|
||||
* @cancellationpoint
|
||||
* @asyncsignalsafe
|
||||
* @restartable (unless SO_RCVTIMEO)
|
||||
*/
|
||||
|
|
|
@ -41,6 +41,7 @@
|
|||
* @return number of bytes received, or -1 w/ errno
|
||||
* @error EINTR, EHOSTUNREACH, ECONNRESET (UDP ICMP Port Unreachable),
|
||||
* EPIPE (if MSG_NOSIGNAL), EMSGSIZE, ENOTSOCK, EFAULT, etc.
|
||||
* @cancellationpoint
|
||||
* @asyncsignalsafe
|
||||
* @restartable (unless SO_RCVTIMEO)
|
||||
*/
|
||||
|
|
|
@ -16,11 +16,11 @@
|
|||
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/intrin/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/intrin/strace.internal.h"
|
||||
#include "libc/sock/internal.h"
|
||||
#include "libc/sock/select.h"
|
||||
#include "libc/sysv/errfuns.h"
|
||||
|
@ -31,6 +31,11 @@
|
|||
* This system call is supported on all platforms. However, on Windows,
|
||||
* this is polyfilled to translate into poll(). So it's recommended that
|
||||
* poll() be used instead.
|
||||
*
|
||||
* @cancellationpoint
|
||||
* @asyncsignalsafe
|
||||
* @threadsafe
|
||||
* @norestart
|
||||
*/
|
||||
int select(int nfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds,
|
||||
struct timeval *timeout) {
|
||||
|
|
|
@ -30,7 +30,7 @@ textwindows ssize_t sys_send_nt(int fd, const struct iovec *iov, size_t iovlen,
|
|||
struct SockFd *sockfd;
|
||||
struct NtIovec iovnt[16];
|
||||
struct NtOverlapped overlapped = {.hEvent = WSACreateEvent()};
|
||||
if (_check_interrupts(true, g_fds.p)) return eintr();
|
||||
if (_check_interrupts(true, g_fds.p)) return -1;
|
||||
if (!WSASend(g_fds.p[fd].handle, iovnt, __iovec2nt(iovnt, iov, iovlen), &sent,
|
||||
flags, &overlapped, NULL)) {
|
||||
rc = sent;
|
||||
|
|
|
@ -43,6 +43,7 @@
|
|||
// sendfile() isn't specified as raising eintr
|
||||
static textwindows int SendfileBlock(int64_t handle,
|
||||
struct NtOverlapped *overlapped) {
|
||||
int rc;
|
||||
uint32_t i, got, flags = 0;
|
||||
if (WSAGetLastError() != kNtErrorIoPending &&
|
||||
WSAGetLastError() != WSAEINPROGRESS) {
|
||||
|
@ -56,7 +57,7 @@ static textwindows int SendfileBlock(int64_t handle,
|
|||
NTTRACE("WSAWaitForMultipleEvents failed %lm");
|
||||
return __winsockerr();
|
||||
} else if (i == kNtWaitTimeout || i == kNtWaitIoCompletion) {
|
||||
_check_interrupts(true, g_fds.p);
|
||||
if (_check_interrupts(true, g_fds.p)) return -1;
|
||||
#if _NTTRACE
|
||||
POLLTRACE("WSAWaitForMultipleEvents...");
|
||||
#endif
|
||||
|
|
|
@ -43,6 +43,7 @@
|
|||
* @return number of bytes transmitted, or -1 w/ errno
|
||||
* @error EINTR, EHOSTUNREACH, ECONNRESET (UDP ICMP Port Unreachable),
|
||||
* EPIPE (if MSG_NOSIGNAL), EMSGSIZE, ENOTSOCK, EFAULT, etc.
|
||||
* @cancellationpoint
|
||||
* @asyncsignalsafe
|
||||
* @restartable (unless SO_RCVTIMEO)
|
||||
*/
|
||||
|
|
|
@ -31,7 +31,7 @@ textwindows ssize_t sys_sendto_nt(int fd, const struct iovec *iov,
|
|||
struct SockFd *sockfd;
|
||||
struct NtIovec iovnt[16];
|
||||
struct NtOverlapped overlapped = {.hEvent = WSACreateEvent()};
|
||||
if (_check_interrupts(true, g_fds.p)) return eintr();
|
||||
if (_check_interrupts(true, g_fds.p)) return -1;
|
||||
if (!WSASendTo(g_fds.p[fd].handle, iovnt, __iovec2nt(iovnt, iov, iovlen),
|
||||
&sent, flags, opt_in_addr, in_addrsize, &overlapped, NULL)) {
|
||||
rc = sent;
|
||||
|
|
|
@ -49,6 +49,7 @@
|
|||
* @return number of bytes transmitted, or -1 w/ errno
|
||||
* @error EINTR, EHOSTUNREACH, ECONNRESET (UDP ICMP Port Unreachable),
|
||||
* EPIPE (if MSG_NOSIGNAL), EMSGSIZE, ENOTSOCK, EFAULT, etc.
|
||||
* @cancellationpoint
|
||||
* @asyncsignalsafe
|
||||
* @restartable (unless SO_RCVTIMEO)
|
||||
*/
|
||||
|
|
|
@ -28,6 +28,7 @@
|
|||
textwindows int __wsablock(int64_t handle, struct NtOverlapped *overlapped,
|
||||
uint32_t *flags, bool restartable,
|
||||
uint32_t timeout) {
|
||||
int rc;
|
||||
uint32_t i, got;
|
||||
if (WSAGetLastError() != kNtErrorIoPending) {
|
||||
NTTRACE("sock i/o failed %lm");
|
||||
|
@ -41,7 +42,7 @@ textwindows int __wsablock(int64_t handle, struct NtOverlapped *overlapped,
|
|||
return __winsockerr();
|
||||
} else if (i == kNtWaitTimeout || i == kNtWaitIoCompletion) {
|
||||
if (_check_interrupts(restartable, g_fds.p)) {
|
||||
return eintr();
|
||||
return -1;
|
||||
}
|
||||
if (timeout) {
|
||||
if (timeout <= __SIG_POLLING_INTERVAL_MS) {
|
||||
|
|
|
@ -255,14 +255,20 @@ static textwindows dontinline struct dirent *readdir_nt(DIR *dir) {
|
|||
*
|
||||
* @returns newly allocated DIR object, or NULL w/ errno
|
||||
* @errors ENOENT, ENOTDIR, EACCES, EMFILE, ENFILE, ENOMEM
|
||||
* @cancellationpoint
|
||||
* @see glob()
|
||||
*/
|
||||
DIR *opendir(const char *name) {
|
||||
int fd;
|
||||
DIR *res;
|
||||
int fd, rc;
|
||||
struct stat st;
|
||||
struct Zipos *zip;
|
||||
struct ZiposUri zipname;
|
||||
if (_weaken(pthread_testcancel_np) &&
|
||||
(rc = _weaken(pthread_testcancel_np)())) {
|
||||
errno = rc;
|
||||
return 0;
|
||||
}
|
||||
if (!name || (IsAsan() && !__asan_is_valid_str(name))) {
|
||||
efault();
|
||||
res = 0;
|
||||
|
@ -271,20 +277,21 @@ DIR *opendir(const char *name) {
|
|||
if (_weaken(__zipos_stat)(&zipname, &st) != -1) {
|
||||
if (S_ISDIR(st.st_mode)) {
|
||||
zip = _weaken(__zipos_get)();
|
||||
res = calloc(1, sizeof(DIR));
|
||||
res->iszip = true;
|
||||
res->fd = -1;
|
||||
res->zip.offset = GetZipCdirOffset(zip->cdir);
|
||||
res->zip.records = GetZipCdirRecords(zip->cdir);
|
||||
res->zip.prefix = malloc(zipname.len + 2);
|
||||
memcpy(res->zip.prefix, zipname.path, zipname.len);
|
||||
if (zipname.len && res->zip.prefix[zipname.len - 1] != '/') {
|
||||
res->zip.prefix[zipname.len++] = '/';
|
||||
if ((res = calloc(1, sizeof(DIR)))) {
|
||||
res->iszip = true;
|
||||
res->fd = -1;
|
||||
res->zip.offset = GetZipCdirOffset(zip->cdir);
|
||||
res->zip.records = GetZipCdirRecords(zip->cdir);
|
||||
res->zip.prefix = malloc(zipname.len + 2);
|
||||
memcpy(res->zip.prefix, zipname.path, zipname.len);
|
||||
if (zipname.len && res->zip.prefix[zipname.len - 1] != '/') {
|
||||
res->zip.prefix[zipname.len++] = '/';
|
||||
}
|
||||
res->zip.prefix[zipname.len] = '\0';
|
||||
res->zip.prefixlen = zipname.len;
|
||||
}
|
||||
res->zip.prefix[zipname.len] = '\0';
|
||||
res->zip.prefixlen = zipname.len;
|
||||
} else {
|
||||
errno = ENOTDIR;
|
||||
enotdir();
|
||||
res = 0;
|
||||
}
|
||||
} else {
|
||||
|
|
|
@ -70,6 +70,7 @@ static bool have_getrandom;
|
|||
* @note this function takes around 900 cycles
|
||||
* @raise EINVAL if `f` is invalid
|
||||
* @raise ENOSYS on bare metal
|
||||
* @cancellationpoint
|
||||
* @asyncsignalsafe
|
||||
* @restartable
|
||||
* @vforksafe
|
||||
|
|
|
@ -19,6 +19,7 @@
|
|||
#include "libc/assert.h"
|
||||
#include "libc/calls/calls.h"
|
||||
#include "libc/errno.h"
|
||||
#include "libc/intrin/weaken.h"
|
||||
#include "libc/paths.h"
|
||||
#include "libc/runtime/runtime.h"
|
||||
#include "libc/stdio/internal.h"
|
||||
|
@ -27,6 +28,7 @@
|
|||
#include "libc/sysv/consts/fd.h"
|
||||
#include "libc/sysv/consts/o.h"
|
||||
#include "libc/sysv/errfuns.h"
|
||||
#include "libc/thread/thread.h"
|
||||
|
||||
/**
|
||||
* Spawns subprocess and returns pipe stream.
|
||||
|
@ -35,11 +37,12 @@
|
|||
* Bourne-like syntax on all platforms including Windows.
|
||||
*
|
||||
* @see pclose()
|
||||
* @cancellationpoint
|
||||
* @threadsafe
|
||||
*/
|
||||
FILE *popen(const char *cmdline, const char *mode) {
|
||||
FILE *f;
|
||||
int e, pid, dir, flags, pipefds[2];
|
||||
int e, rc, pid, dir, flags, pipefds[2];
|
||||
flags = fopenflags(mode);
|
||||
if ((flags & O_ACCMODE) == O_RDONLY) {
|
||||
dir = 0;
|
||||
|
@ -49,6 +52,11 @@ FILE *popen(const char *cmdline, const char *mode) {
|
|||
einval();
|
||||
return NULL;
|
||||
}
|
||||
if (_weaken(pthread_testcancel_np) &&
|
||||
(rc = _weaken(pthread_testcancel_np)())) {
|
||||
errno = rc;
|
||||
return 0;
|
||||
}
|
||||
if (pipe2(pipefds, O_CLOEXEC) == -1) return NULL;
|
||||
if ((f = fdopen(pipefds[dir], mode))) {
|
||||
switch ((pid = fork())) {
|
||||
|
|
|
@ -25,6 +25,7 @@
|
|||
#include "libc/stdio/posix_spawn.h"
|
||||
#include "libc/stdio/posix_spawn.internal.h"
|
||||
#include "libc/sysv/consts/sig.h"
|
||||
#include "libc/thread/thread.h"
|
||||
#include "libc/thread/tls.h"
|
||||
|
||||
static int RunFileActions(struct _posix_faction *a) {
|
||||
|
@ -67,6 +68,7 @@ static int RunFileActions(struct _posix_faction *a) {
|
|||
* @param envp is environment variables, or `environ` if null
|
||||
* @return 0 on success or error number on failure
|
||||
* @see posix_spawnp() for `$PATH` searching
|
||||
* @cancellationpoint
|
||||
* @tlsrequired
|
||||
* @threadsafe
|
||||
*/
|
||||
|
@ -79,6 +81,9 @@ int posix_spawn(int *pid, const char *path,
|
|||
int s, child, policy;
|
||||
struct sched_param param;
|
||||
struct sigaction dfl = {0};
|
||||
if (_weaken(pthread_testcancel)) {
|
||||
_weaken(pthread_testcancel)();
|
||||
}
|
||||
if (!(child = vfork())) {
|
||||
if (attrp && *attrp) {
|
||||
posix_spawnattr_getflags(attrp, &flags);
|
||||
|
|
|
@ -21,12 +21,14 @@
|
|||
#include "libc/calls/struct/sigaction.h"
|
||||
#include "libc/dce.h"
|
||||
#include "libc/errno.h"
|
||||
#include "libc/intrin/weaken.h"
|
||||
#include "libc/log/log.h"
|
||||
#include "libc/paths.h"
|
||||
#include "libc/runtime/runtime.h"
|
||||
#include "libc/str/str.h"
|
||||
#include "libc/sysv/consts/ok.h"
|
||||
#include "libc/sysv/consts/sig.h"
|
||||
#include "libc/thread/thread.h"
|
||||
|
||||
/**
|
||||
* Launches program with system command interpreter.
|
||||
|
@ -37,6 +39,7 @@
|
|||
* @param cmdline is an interpreted Turing-complete command
|
||||
* @return -1 if child process couldn't be created, otherwise a wait
|
||||
* status that can be accessed using macros like WEXITSTATUS(s)
|
||||
* @cancellationpoint
|
||||
* @threadsafe
|
||||
*/
|
||||
int system(const char *cmdline) {
|
||||
|
@ -44,6 +47,9 @@ int system(const char *cmdline) {
|
|||
sigset_t chldmask, savemask;
|
||||
struct sigaction ignore, saveint, savequit;
|
||||
if (!cmdline) return 1;
|
||||
if (_weaken(pthread_testcancel)) {
|
||||
_weaken(pthread_testcancel)();
|
||||
}
|
||||
ignore.sa_flags = 0;
|
||||
ignore.sa_handler = SIG_IGN;
|
||||
sigemptyset(&ignore.sa_mask);
|
||||
|
|
|
@ -1,2 +1,2 @@
|
|||
.include "o/libc/sysv/macros.internal.inc"
|
||||
.scall __sys_accept,0x01e01e21d201e02b,globl,hidden
|
||||
.scall __sys_accept,0x81e81ea1d281e82b,globl,hidden
|
||||
|
|
|
@ -1,2 +1,2 @@
|
|||
.include "o/libc/sysv/macros.internal.inc"
|
||||
.scall __sys_accept4,0xfff05d21dffff120,globl,hidden
|
||||
.scall __sys_accept4,0xfff85da1dffff920,globl,hidden
|
||||
|
|
|
@ -1,2 +1,2 @@
|
|||
.include "o/libc/sysv/macros.internal.inc"
|
||||
.scall __sys_connect,0x062062062206202a,globl,hidden
|
||||
.scall __sys_connect,0x862862862286282a,globl,hidden
|
||||
|
|
2
libc/sysv/calls/__sys_fcntl_cp.s
Normal file
2
libc/sysv/calls/__sys_fcntl_cp.s
Normal file
|
@ -0,0 +1,2 @@
|
|||
.include "o/libc/sysv/macros.internal.inc"
|
||||
.scall __sys_fcntl_cp,0x85c85c85c285c848,globl,hidden
|
|
@ -1,2 +1,2 @@
|
|||
.include "o/libc/sysv/macros.internal.inc"
|
||||
.scall __sys_openat,0x1d41411f321cf101,globl,hidden
|
||||
.scall __sys_openat,0x9d49419f329cf901,globl,hidden
|
||||
|
|
|
@ -1,2 +1,2 @@
|
|||
.include "o/libc/sysv/macros.internal.inc"
|
||||
.scall __sys_wait4,0x1c100b007200703d,globl,hidden
|
||||
.scall __sys_wait4,0x9c180b807280783d,globl,hidden
|
||||
|
|
|
@ -1,2 +1,2 @@
|
|||
.include "o/libc/sysv/macros.internal.inc"
|
||||
.scall posix_fallocate,0x1dffff212fffffff,globl,hidden
|
||||
.scall posix_fallocate,0x9dffffa12fffffff,globl,hidden
|
||||
|
|
|
@ -1,2 +1,2 @@
|
|||
.include "o/libc/sysv/macros.internal.inc"
|
||||
.scall sys_clock_nanosleep,0x1ddfff0f4ffff0e6,globl,hidden
|
||||
.scall sys_clock_nanosleep,0x9ddfff8f4ffff8e6,globl,hidden
|
||||
|
|
|
@ -1,2 +1,2 @@
|
|||
.include "o/libc/sysv/macros.internal.inc"
|
||||
.scall sys_epoll_wait,0xfffffffffffff0e8,globl,hidden
|
||||
.scall sys_epoll_wait,0xfffffffffffff8e8,globl,hidden
|
||||
|
|
|
@ -1,2 +1,2 @@
|
|||
.include "o/libc/sysv/macros.internal.inc"
|
||||
.scall sys_fallocate,0xfffffffffffff11d,globl
|
||||
.scall sys_fallocate,0xfffffffffffff91d,globl
|
||||
|
|
|
@ -1,2 +1,2 @@
|
|||
.include "o/libc/sysv/macros.internal.inc"
|
||||
.scall sys_fdatasync,0x0f105f22620bb04b,globl,hidden
|
||||
.scall sys_fdatasync,0x8f185fa2628bb84b,globl,hidden
|
||||
|
|
|
@ -1,2 +1,2 @@
|
|||
.include "o/libc/sysv/macros.internal.inc"
|
||||
.scall sys_flock,0x0830830832083049,globl,hidden
|
||||
.scall sys_flock,0x8838838832883849,globl,hidden
|
||||
|
|
|
@ -1,2 +1,2 @@
|
|||
.include "o/libc/sysv/macros.internal.inc"
|
||||
.scall sys_fstatfs,0x09e04022c215a08a,globl,hidden
|
||||
.scall sys_fstatfs,0x89e840a2c295a88a,globl,hidden
|
||||
|
|
|
@ -1,2 +1,2 @@
|
|||
.include "o/libc/sysv/macros.internal.inc"
|
||||
.scall sys_fsync,0x05f05f05f205f04a,globl,hidden
|
||||
.scall sys_fsync,0x85f85f85f285f84a,globl,hidden
|
||||
|
|
|
@ -1,2 +1,2 @@
|
|||
.include "o/libc/sysv/macros.internal.inc"
|
||||
.scall sys_ftruncate,0x0c90c91e020c904d,globl,hidden
|
||||
.scall sys_ftruncate,0x8c98c99e028c984d,globl,hidden
|
||||
|
|
|
@ -1,2 +1,2 @@
|
|||
.include "o/libc/sysv/macros.internal.inc"
|
||||
.scall sys_getrandom,0xfff00723321f413e,globl,hidden
|
||||
.scall sys_getrandom,0xfff807a3329f493e,globl,hidden
|
||||
|
|
2
libc/sysv/calls/sys_ioctl_cp.s
Normal file
2
libc/sysv/calls/sys_ioctl_cp.s
Normal file
|
@ -0,0 +1,2 @@
|
|||
.include "o/libc/sysv/macros.internal.inc"
|
||||
.scall sys_ioctl_cp,0x8368368362836810,globl,hidden
|
|
@ -1,2 +1,2 @@
|
|||
.include "o/libc/sysv/macros.internal.inc"
|
||||
.scall sys_msgrcv,0x0e30e30e32105046,globl
|
||||
.scall sys_msgrcv,0x8e38e38e32905846,globl
|
||||
|
|
|
@ -1,2 +1,2 @@
|
|||
.include "o/libc/sysv/macros.internal.inc"
|
||||
.scall sys_msgsnd,0x0e20e20e22104045,globl
|
||||
.scall sys_msgsnd,0x8e28e28e22904845,globl
|
||||
|
|
|
@ -1,2 +1,2 @@
|
|||
.include "o/libc/sysv/macros.internal.inc"
|
||||
.scall sys_msync,0x115100041204101a,globl,hidden
|
||||
.scall sys_msync,0x915900841284181a,globl,hidden
|
||||
|
|
|
@ -1,2 +1,2 @@
|
|||
.include "o/libc/sysv/macros.internal.inc"
|
||||
.scall sys_nanosleep,0x1ae05b0f0ffff023,globl,hidden
|
||||
.scall sys_nanosleep,0x9ae85b8f0ffff823,globl,hidden
|
||||
|
|
|
@ -1,2 +1,2 @@
|
|||
.include "o/libc/sysv/macros.internal.inc"
|
||||
.scall sys_open,0x0050050052005002,globl,hidden
|
||||
.scall sys_open,0x8058058052805802,globl,hidden
|
||||
|
|
|
@ -1,2 +1,2 @@
|
|||
.include "o/libc/sysv/macros.internal.inc"
|
||||
.scall sys_poll,0x0d10fc0d120e6007,globl,hidden
|
||||
.scall sys_poll,0x8d18fc8d128e6807,globl,hidden
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue