diff --git a/Makefile b/Makefile index 073ba83d3..0e492dc50 100644 --- a/Makefile +++ b/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: diff --git a/libc/calls/__sig2.c b/libc/calls/__sig2.c index cf820f486..a6ea8d4eb 100644 --- a/libc/calls/__sig2.c +++ b/libc/calls/__sig2.c @@ -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 { diff --git a/libc/calls/clock_nanosleep-nt.c b/libc/calls/clock_nanosleep-nt.c index e25605f8d..8aa89a1a9 100644 --- a/libc/calls/clock_nanosleep-nt.c +++ b/libc/calls/clock_nanosleep-nt.c @@ -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))), diff --git a/libc/calls/clock_nanosleep.c b/libc/calls/clock_nanosleep.c index 8b93f0740..faa004dff 100644 --- a/libc/calls/clock_nanosleep.c +++ b/libc/calls/clock_nanosleep.c @@ -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 */ diff --git a/libc/calls/fcntl-sysv.c b/libc/calls/fcntl-sysv.c index 2cfbf8d0c..42957aa84 100644 --- a/libc/calls/fcntl-sysv.c +++ b/libc/calls/fcntl-sysv.c @@ -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; } diff --git a/libc/calls/fcntl.c b/libc/calls/fcntl.c index 06369e9ba..f27beb4e9 100644 --- a/libc/calls/fcntl.c +++ b/libc/calls/fcntl.c @@ -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); } diff --git a/libc/calls/fdatasync.c b/libc/calls/fdatasync.c index 5153eb5e9..3fff9e44f 100644 --- a/libc/calls/fdatasync.c +++ b/libc/calls/fdatasync.c @@ -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) { diff --git a/libc/calls/flock.c b/libc/calls/flock.c index 460c105bc..c75017e89 100644 --- a/libc/calls/flock.c +++ b/libc/calls/flock.c @@ -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) { diff --git a/libc/calls/fstatfs.c b/libc/calls/fstatfs.c index 1e47c174e..52591f915 100644 --- a/libc/calls/fstatfs.c +++ b/libc/calls/fstatfs.c @@ -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; diff --git a/libc/calls/fsync.c b/libc/calls/fsync.c index 38afd2faa..98ff4ced2 100644 --- a/libc/calls/fsync.c +++ b/libc/calls/fsync.c @@ -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) { diff --git a/libc/calls/ftruncate.c b/libc/calls/ftruncate.c index 944540d37..854114667 100644 --- a/libc/calls/ftruncate.c +++ b/libc/calls/ftruncate.c @@ -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 */ diff --git a/libc/calls/internal.h b/libc/calls/internal.h index 68123098d..0b43a4a56 100644 --- a/libc/calls/internal.h +++ b/libc/calls/internal.h @@ -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_ diff --git a/libc/calls/interrupts-nt.c b/libc/calls/interrupts-nt.c index 18c5ea65f..b30c2fcb1 100644 --- a/libc/calls/interrupts-nt.c +++ b/libc/calls/interrupts-nt.c @@ -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; } diff --git a/libc/calls/nanosleep.c b/libc/calls/nanosleep.c index 9349320bf..2cffc641d 100644 --- a/libc/calls/nanosleep.c +++ b/libc/calls/nanosleep.c @@ -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) { diff --git a/libc/calls/ntcontext2linux.c b/libc/calls/ntcontext2linux.c index 818682d9e..1c1fc0fe0 100644 --- a/libc/calls/ntcontext2linux.c +++ b/libc/calls/ntcontext2linux.c @@ -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; diff --git a/libc/calls/open.c b/libc/calls/open.c index 48262b7d8..9ac2b3986 100644 --- a/libc/calls/open.c +++ b/libc/calls/open.c @@ -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 diff --git a/libc/calls/openat.c b/libc/calls/openat.c index 5c1f7d618..bd4fc3c95 100644 --- a/libc/calls/openat.c +++ b/libc/calls/openat.c @@ -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 diff --git a/libc/calls/pause-nt.c b/libc/calls/pause-nt.c index 072f8f550..b30d032fe 100644 --- a/libc/calls/pause-nt.c +++ b/libc/calls/pause-nt.c @@ -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) { diff --git a/libc/calls/pause.c b/libc/calls/pause.c index 4c3466654..3d0a475a8 100644 --- a/libc/calls/pause.c +++ b/libc/calls/pause.c @@ -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 */ diff --git a/libc/calls/poll-nt.c b/libc/calls/poll-nt.c index 726558c7e..b906b796c 100644 --- a/libc/calls/poll-nt.c +++ b/libc/calls/poll-nt.c @@ -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; } } diff --git a/libc/calls/poll.c b/libc/calls/poll.c index 7fe7a9bc8..8b20f9451 100644 --- a/libc/calls/poll.c +++ b/libc/calls/poll.c @@ -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 diff --git a/libc/calls/ppoll.c b/libc/calls/ppoll.c index 21a638ce6..87cea08dd 100644 --- a/libc/calls/ppoll.c +++ b/libc/calls/ppoll.c @@ -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 diff --git a/libc/calls/pread.c b/libc/calls/pread.c index 6c1a6bf6f..3d3732d14 100644 --- a/libc/calls/pread.c +++ b/libc/calls/pread.c @@ -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 diff --git a/libc/calls/preadv.c b/libc/calls/preadv.c index 0657395f1..1493f3007 100644 --- a/libc/calls/preadv.c +++ b/libc/calls/preadv.c @@ -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 */ diff --git a/libc/calls/pwrite.c b/libc/calls/pwrite.c index a8a12cf9b..fc502c6da 100644 --- a/libc/calls/pwrite.c +++ b/libc/calls/pwrite.c @@ -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 diff --git a/libc/calls/pwritev.c b/libc/calls/pwritev.c index 3197ca6c9..f8dd10fd8 100644 --- a/libc/calls/pwritev.c +++ b/libc/calls/pwritev.c @@ -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 */ diff --git a/libc/calls/read-nt.c b/libc/calls/read-nt.c index 35e531c0d..45fd0e5b6 100644 --- a/libc/calls/read-nt.c +++ b/libc/calls/read-nt.c @@ -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) { diff --git a/libc/calls/read.c b/libc/calls/read.c index e250c3c1d..2be56bb00 100644 --- a/libc/calls/read.c +++ b/libc/calls/read.c @@ -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 diff --git a/libc/calls/readv.c b/libc/calls/readv.c index f7c4d7e4b..5a05d51f3 100644 --- a/libc/calls/readv.c +++ b/libc/calls/readv.c @@ -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) { diff --git a/libc/calls/sigblockall.c b/libc/calls/sigblockall.c index 9ca00277c..7c0efd50c 100644 --- a/libc/calls/sigblockall.c +++ b/libc/calls/sigblockall.c @@ -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); } diff --git a/libc/calls/sigenter-netbsd.c b/libc/calls/sigenter-netbsd.c index 585076c43..14ecaa7fc 100644 --- a/libc/calls/sigenter-netbsd.c +++ b/libc/calls/sigenter-netbsd.c @@ -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; diff --git a/libc/calls/sigenter-openbsd.c b/libc/calls/sigenter-openbsd.c index f9b277ee8..b99b3abfb 100644 --- a/libc/calls/sigenter-openbsd.c +++ b/libc/calls/sigenter-openbsd.c @@ -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; diff --git a/libc/calls/sigenter-xnu.c b/libc/calls/sigenter-xnu.c index 80ff59d89..6804b1b75 100644 --- a/libc/calls/sigenter-xnu.c +++ b/libc/calls/sigenter-xnu.c @@ -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)) { diff --git a/libc/calls/sigprocmask.c b/libc/calls/sigprocmask.c index caab7e275..268490e59 100644 --- a/libc/calls/sigprocmask.c +++ b/libc/calls/sigprocmask.c @@ -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); } diff --git a/libc/calls/sigsetmask.c b/libc/calls/sigsetmask.c index 5cebef6f5..a6618ae0c 100644 --- a/libc/calls/sigsetmask.c +++ b/libc/calls/sigsetmask.c @@ -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()) { diff --git a/libc/calls/sigsuspend.c b/libc/calls/sigsuspend.c index 529ef7da5..7e2da624d 100644 --- a/libc/calls/sigsuspend.c +++ b/libc/calls/sigsuspend.c @@ -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) { diff --git a/libc/calls/sigtimedwait.c b/libc/calls/sigtimedwait.c index 3096d71af..c2063f49c 100644 --- a/libc/calls/sigtimedwait.c +++ b/libc/calls/sigtimedwait.c @@ -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) { diff --git a/libc/calls/sigwaitinfo.c b/libc/calls/sigwaitinfo.c index 816f243b9..394077983 100644 --- a/libc/calls/sigwaitinfo.c +++ b/libc/calls/sigwaitinfo.c @@ -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); diff --git a/libc/calls/sleep.c b/libc/calls/sleep.c index ab9962fc2..2631a82c3 100644 --- a/libc/calls/sleep.c +++ b/libc/calls/sleep.c @@ -29,6 +29,7 @@ * this function shall return the number of unslept seconds rounded * using the ceiling function * @see clock_nanosleep() + * @cancellationpoint * @asyncsignalsafe * @norestart */ diff --git a/libc/calls/statfs.c b/libc/calls/statfs.c index 02dad040e..97aa6be7a 100644 --- a/libc/calls/statfs.c +++ b/libc/calls/statfs.c @@ -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; diff --git a/libc/calls/syscall-sysv.internal.h b/libc/calls/syscall-sysv.internal.h index cd7f36ee4..42d1e7f57 100644 --- a/libc/calls/syscall-sysv.internal.h +++ b/libc/calls/syscall-sysv.internal.h @@ -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; diff --git a/libc/calls/tcdrain.c b/libc/calls/tcdrain.c index 5c6d2a6e3..40e5a41bd 100644 --- a/libc/calls/tcdrain.c +++ b/libc/calls/tcdrain.c @@ -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); } diff --git a/libc/calls/truncate.c b/libc/calls/truncate.c index d4a8915bb..3af89ab91 100644 --- a/libc/calls/truncate.c +++ b/libc/calls/truncate.c @@ -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 */ diff --git a/libc/calls/usleep.c b/libc/calls/usleep.c index a20c1ca67..820786004 100644 --- a/libc/calls/usleep.c +++ b/libc/calls/usleep.c @@ -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) { diff --git a/libc/calls/wait.c b/libc/calls/wait.c index f322cb9f5..6b9150293 100644 --- a/libc/calls/wait.c +++ b/libc/calls/wait.c @@ -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 diff --git a/libc/calls/wait3.c b/libc/calls/wait3.c index 9932081c4..74ae4eeb0 100644 --- a/libc/calls/wait3.c +++ b/libc/calls/wait3.c @@ -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 */ diff --git a/libc/calls/wait4-nt.c b/libc/calls/wait4-nt.c index bd68c737e..643f52a20 100644 --- a/libc/calls/wait4-nt.c +++ b/libc/calls/wait4-nt.c @@ -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); diff --git a/libc/calls/wait4.c b/libc/calls/wait4.c index b8b9672eb..d9afd2b66 100644 --- a/libc/calls/wait4.c +++ b/libc/calls/wait4.c @@ -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 */ diff --git a/libc/calls/waitpid.c b/libc/calls/waitpid.c index 9f457f066..e333134aa 100644 --- a/libc/calls/waitpid.c +++ b/libc/calls/waitpid.c @@ -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 */ diff --git a/libc/calls/write.c b/libc/calls/write.c index 9b421b460..8185c0fe6 100644 --- a/libc/calls/write.c +++ b/libc/calls/write.c @@ -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 diff --git a/libc/calls/writev.c b/libc/calls/writev.c index 292570c79..863cbb31a 100644 --- a/libc/calls/writev.c +++ b/libc/calls/writev.c @@ -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) { diff --git a/libc/intrin/ksignalnames.S b/libc/intrin/ksignalnames.S index 8336b3d5d..97fffaeb8 100644 --- a/libc/intrin/ksignalnames.S +++ b/libc/intrin/ksignalnames.S @@ -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" diff --git a/libc/intrin/sigaddset.c b/libc/intrin/sigaddset.c index b19ac04cf..5f6902db8 100644 --- a/libc/intrin/sigaddset.c +++ b/libc/intrin/sigaddset.c @@ -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 { diff --git a/libc/intrin/sigisprecious.inc b/libc/intrin/sigisprecious.inc index 5c08fd00b..923cc86b2 100644 --- a/libc/intrin/sigisprecious.inc +++ b/libc/intrin/sigisprecious.inc @@ -1,3 +1,4 @@ M(SIGKILL) M(SIGABRT) M(SIGSTOP) +M(SIGCANCEL) diff --git a/libc/runtime/msync.c b/libc/runtime/msync.c index 0f7c34e1f..c9c2ab193 100644 --- a/libc/runtime/msync.c +++ b/libc/runtime/msync.c @@ -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; diff --git a/libc/sock/accept-nt.c b/libc/sock/accept-nt.c index 81a398cac..f2087b9b5 100644 --- a/libc/sock/accept-nt.c +++ b/libc/sock/accept-nt.c @@ -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)) { diff --git a/libc/sock/accept.c b/libc/sock/accept.c index e4a08f0f6..ae2be472b 100644 --- a/libc/sock/accept.c +++ b/libc/sock/accept.c @@ -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) */ diff --git a/libc/sock/accept4.c b/libc/sock/accept4.c index bc030e6d0..0499c65bb 100644 --- a/libc/sock/accept4.c +++ b/libc/sock/accept4.c @@ -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) */ diff --git a/libc/sock/connect.c b/libc/sock/connect.c index d9d7b2c24..15db1cc03 100644 --- a/libc/sock/connect.c +++ b/libc/sock/connect.c @@ -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) */ diff --git a/libc/sock/epoll.c b/libc/sock/epoll.c index 596b6f87e..8622e86d7 100644 --- a/libc/sock/epoll.c +++ b/libc/sock/epoll.c @@ -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, diff --git a/libc/sock/pselect.c b/libc/sock/pselect.c index ba9311889..124ca1647 100644 --- a/libc/sock/pselect.c +++ b/libc/sock/pselect.c @@ -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) { diff --git a/libc/sock/recv-nt.c b/libc/sock/recv-nt.c index 2239bbb6b..a0f734c53 100644 --- a/libc/sock/recv-nt.c +++ b/libc/sock/recv-nt.c @@ -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)) { diff --git a/libc/sock/recvfrom-nt.c b/libc/sock/recvfrom-nt.c index 39d8c6c84..1a2099db6 100644 --- a/libc/sock/recvfrom-nt.c +++ b/libc/sock/recvfrom-nt.c @@ -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, diff --git a/libc/sock/recvfrom.c b/libc/sock/recvfrom.c index d34bcb1c5..d47991ce7 100644 --- a/libc/sock/recvfrom.c +++ b/libc/sock/recvfrom.c @@ -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) */ diff --git a/libc/sock/recvmsg.c b/libc/sock/recvmsg.c index 16ebd370c..6e44829e9 100644 --- a/libc/sock/recvmsg.c +++ b/libc/sock/recvmsg.c @@ -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) */ diff --git a/libc/sock/select.c b/libc/sock/select.c index a8e0219b6..f11a1e435 100644 --- a/libc/sock/select.c +++ b/libc/sock/select.c @@ -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) { diff --git a/libc/sock/send-nt.c b/libc/sock/send-nt.c index b69df9fdb..2a0f4aedf 100644 --- a/libc/sock/send-nt.c +++ b/libc/sock/send-nt.c @@ -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; diff --git a/libc/sock/sendfile.c b/libc/sock/sendfile.c index 2b6fd919f..53b2f8311 100644 --- a/libc/sock/sendfile.c +++ b/libc/sock/sendfile.c @@ -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 diff --git a/libc/sock/sendmsg.c b/libc/sock/sendmsg.c index 486930ab2..67a555d36 100644 --- a/libc/sock/sendmsg.c +++ b/libc/sock/sendmsg.c @@ -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) */ diff --git a/libc/sock/sendto-nt.c b/libc/sock/sendto-nt.c index 1fdbc3fba..d870fa149 100644 --- a/libc/sock/sendto-nt.c +++ b/libc/sock/sendto-nt.c @@ -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; diff --git a/libc/sock/sendto.c b/libc/sock/sendto.c index b7bf87e2d..43ac49e50 100644 --- a/libc/sock/sendto.c +++ b/libc/sock/sendto.c @@ -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) */ diff --git a/libc/sock/wsablock.c b/libc/sock/wsablock.c index 130baa518..a7669eb03 100644 --- a/libc/sock/wsablock.c +++ b/libc/sock/wsablock.c @@ -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) { diff --git a/libc/stdio/dirstream.c b/libc/stdio/dirstream.c index a7a545eb2..4c3c8f606 100644 --- a/libc/stdio/dirstream.c +++ b/libc/stdio/dirstream.c @@ -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 { diff --git a/libc/stdio/getrandom.c b/libc/stdio/getrandom.c index 14d766a5d..1acef9f25 100644 --- a/libc/stdio/getrandom.c +++ b/libc/stdio/getrandom.c @@ -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 diff --git a/libc/stdio/popen.c b/libc/stdio/popen.c index ffd5c71c2..5fb577315 100644 --- a/libc/stdio/popen.c +++ b/libc/stdio/popen.c @@ -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())) { diff --git a/libc/stdio/posix_spawn.c b/libc/stdio/posix_spawn.c index a754e25bf..953f55961 100644 --- a/libc/stdio/posix_spawn.c +++ b/libc/stdio/posix_spawn.c @@ -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); diff --git a/libc/stdio/system.c b/libc/stdio/system.c index 571401bd8..8b820ab79 100644 --- a/libc/stdio/system.c +++ b/libc/stdio/system.c @@ -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); diff --git a/libc/sysv/calls/__sys_accept.s b/libc/sysv/calls/__sys_accept.s index 1a9fbdb18..52e9a836b 100644 --- a/libc/sysv/calls/__sys_accept.s +++ b/libc/sysv/calls/__sys_accept.s @@ -1,2 +1,2 @@ .include "o/libc/sysv/macros.internal.inc" -.scall __sys_accept,0x01e01e21d201e02b,globl,hidden +.scall __sys_accept,0x81e81ea1d281e82b,globl,hidden diff --git a/libc/sysv/calls/__sys_accept4.s b/libc/sysv/calls/__sys_accept4.s index 941c30684..5ae850522 100644 --- a/libc/sysv/calls/__sys_accept4.s +++ b/libc/sysv/calls/__sys_accept4.s @@ -1,2 +1,2 @@ .include "o/libc/sysv/macros.internal.inc" -.scall __sys_accept4,0xfff05d21dffff120,globl,hidden +.scall __sys_accept4,0xfff85da1dffff920,globl,hidden diff --git a/libc/sysv/calls/__sys_connect.s b/libc/sysv/calls/__sys_connect.s index 25c89e111..dd07beae6 100644 --- a/libc/sysv/calls/__sys_connect.s +++ b/libc/sysv/calls/__sys_connect.s @@ -1,2 +1,2 @@ .include "o/libc/sysv/macros.internal.inc" -.scall __sys_connect,0x062062062206202a,globl,hidden +.scall __sys_connect,0x862862862286282a,globl,hidden diff --git a/libc/sysv/calls/__sys_fcntl_cp.s b/libc/sysv/calls/__sys_fcntl_cp.s new file mode 100644 index 000000000..dd46a0d5c --- /dev/null +++ b/libc/sysv/calls/__sys_fcntl_cp.s @@ -0,0 +1,2 @@ +.include "o/libc/sysv/macros.internal.inc" +.scall __sys_fcntl_cp,0x85c85c85c285c848,globl,hidden diff --git a/libc/sysv/calls/__sys_openat.s b/libc/sysv/calls/__sys_openat.s index 127fd0967..40b3ccebd 100644 --- a/libc/sysv/calls/__sys_openat.s +++ b/libc/sysv/calls/__sys_openat.s @@ -1,2 +1,2 @@ .include "o/libc/sysv/macros.internal.inc" -.scall __sys_openat,0x1d41411f321cf101,globl,hidden +.scall __sys_openat,0x9d49419f329cf901,globl,hidden diff --git a/libc/sysv/calls/__sys_wait4.s b/libc/sysv/calls/__sys_wait4.s index 15180408c..96c889e9b 100644 --- a/libc/sysv/calls/__sys_wait4.s +++ b/libc/sysv/calls/__sys_wait4.s @@ -1,2 +1,2 @@ .include "o/libc/sysv/macros.internal.inc" -.scall __sys_wait4,0x1c100b007200703d,globl,hidden +.scall __sys_wait4,0x9c180b807280783d,globl,hidden diff --git a/libc/sysv/calls/posix_fallocate.s b/libc/sysv/calls/posix_fallocate.s index 41815859a..0e65e104e 100644 --- a/libc/sysv/calls/posix_fallocate.s +++ b/libc/sysv/calls/posix_fallocate.s @@ -1,2 +1,2 @@ .include "o/libc/sysv/macros.internal.inc" -.scall posix_fallocate,0x1dffff212fffffff,globl,hidden +.scall posix_fallocate,0x9dffffa12fffffff,globl,hidden diff --git a/libc/sysv/calls/sys_clock_nanosleep.s b/libc/sysv/calls/sys_clock_nanosleep.s index 70fef5259..82c21586c 100644 --- a/libc/sysv/calls/sys_clock_nanosleep.s +++ b/libc/sysv/calls/sys_clock_nanosleep.s @@ -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 diff --git a/libc/sysv/calls/sys_epoll_wait.s b/libc/sysv/calls/sys_epoll_wait.s index f38c97423..af328026e 100644 --- a/libc/sysv/calls/sys_epoll_wait.s +++ b/libc/sysv/calls/sys_epoll_wait.s @@ -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 diff --git a/libc/sysv/calls/sys_fallocate.s b/libc/sysv/calls/sys_fallocate.s index fbd91988f..52181e8d4 100644 --- a/libc/sysv/calls/sys_fallocate.s +++ b/libc/sysv/calls/sys_fallocate.s @@ -1,2 +1,2 @@ .include "o/libc/sysv/macros.internal.inc" -.scall sys_fallocate,0xfffffffffffff11d,globl +.scall sys_fallocate,0xfffffffffffff91d,globl diff --git a/libc/sysv/calls/sys_fdatasync.s b/libc/sysv/calls/sys_fdatasync.s index d050c1aea..dbe9435a5 100644 --- a/libc/sysv/calls/sys_fdatasync.s +++ b/libc/sysv/calls/sys_fdatasync.s @@ -1,2 +1,2 @@ .include "o/libc/sysv/macros.internal.inc" -.scall sys_fdatasync,0x0f105f22620bb04b,globl,hidden +.scall sys_fdatasync,0x8f185fa2628bb84b,globl,hidden diff --git a/libc/sysv/calls/sys_flock.s b/libc/sysv/calls/sys_flock.s index 2626a05d7..b49d322f1 100644 --- a/libc/sysv/calls/sys_flock.s +++ b/libc/sysv/calls/sys_flock.s @@ -1,2 +1,2 @@ .include "o/libc/sysv/macros.internal.inc" -.scall sys_flock,0x0830830832083049,globl,hidden +.scall sys_flock,0x8838838832883849,globl,hidden diff --git a/libc/sysv/calls/sys_fstatfs.s b/libc/sysv/calls/sys_fstatfs.s index 1cc25d2c3..de5c1cccf 100644 --- a/libc/sysv/calls/sys_fstatfs.s +++ b/libc/sysv/calls/sys_fstatfs.s @@ -1,2 +1,2 @@ .include "o/libc/sysv/macros.internal.inc" -.scall sys_fstatfs,0x09e04022c215a08a,globl,hidden +.scall sys_fstatfs,0x89e840a2c295a88a,globl,hidden diff --git a/libc/sysv/calls/sys_fsync.s b/libc/sysv/calls/sys_fsync.s index 99f60f440..da50a6244 100644 --- a/libc/sysv/calls/sys_fsync.s +++ b/libc/sysv/calls/sys_fsync.s @@ -1,2 +1,2 @@ .include "o/libc/sysv/macros.internal.inc" -.scall sys_fsync,0x05f05f05f205f04a,globl,hidden +.scall sys_fsync,0x85f85f85f285f84a,globl,hidden diff --git a/libc/sysv/calls/sys_ftruncate.s b/libc/sysv/calls/sys_ftruncate.s index a5809ee92..8c5e6d2dc 100644 --- a/libc/sysv/calls/sys_ftruncate.s +++ b/libc/sysv/calls/sys_ftruncate.s @@ -1,2 +1,2 @@ .include "o/libc/sysv/macros.internal.inc" -.scall sys_ftruncate,0x0c90c91e020c904d,globl,hidden +.scall sys_ftruncate,0x8c98c99e028c984d,globl,hidden diff --git a/libc/sysv/calls/sys_getrandom.s b/libc/sysv/calls/sys_getrandom.s index f6ddb33f1..fb8772447 100644 --- a/libc/sysv/calls/sys_getrandom.s +++ b/libc/sysv/calls/sys_getrandom.s @@ -1,2 +1,2 @@ .include "o/libc/sysv/macros.internal.inc" -.scall sys_getrandom,0xfff00723321f413e,globl,hidden +.scall sys_getrandom,0xfff807a3329f493e,globl,hidden diff --git a/libc/sysv/calls/sys_ioctl_cp.s b/libc/sysv/calls/sys_ioctl_cp.s new file mode 100644 index 000000000..3c29af533 --- /dev/null +++ b/libc/sysv/calls/sys_ioctl_cp.s @@ -0,0 +1,2 @@ +.include "o/libc/sysv/macros.internal.inc" +.scall sys_ioctl_cp,0x8368368362836810,globl,hidden diff --git a/libc/sysv/calls/sys_msgrcv.s b/libc/sysv/calls/sys_msgrcv.s index 6b2b4374b..fd1749054 100644 --- a/libc/sysv/calls/sys_msgrcv.s +++ b/libc/sysv/calls/sys_msgrcv.s @@ -1,2 +1,2 @@ .include "o/libc/sysv/macros.internal.inc" -.scall sys_msgrcv,0x0e30e30e32105046,globl +.scall sys_msgrcv,0x8e38e38e32905846,globl diff --git a/libc/sysv/calls/sys_msgsnd.s b/libc/sysv/calls/sys_msgsnd.s index d1062e639..cb30eee9b 100644 --- a/libc/sysv/calls/sys_msgsnd.s +++ b/libc/sysv/calls/sys_msgsnd.s @@ -1,2 +1,2 @@ .include "o/libc/sysv/macros.internal.inc" -.scall sys_msgsnd,0x0e20e20e22104045,globl +.scall sys_msgsnd,0x8e28e28e22904845,globl diff --git a/libc/sysv/calls/sys_msync.s b/libc/sysv/calls/sys_msync.s index 3dd327fbc..0295e1431 100644 --- a/libc/sysv/calls/sys_msync.s +++ b/libc/sysv/calls/sys_msync.s @@ -1,2 +1,2 @@ .include "o/libc/sysv/macros.internal.inc" -.scall sys_msync,0x115100041204101a,globl,hidden +.scall sys_msync,0x915900841284181a,globl,hidden diff --git a/libc/sysv/calls/sys_nanosleep.s b/libc/sysv/calls/sys_nanosleep.s index af2f8b156..e5dc327b4 100644 --- a/libc/sysv/calls/sys_nanosleep.s +++ b/libc/sysv/calls/sys_nanosleep.s @@ -1,2 +1,2 @@ .include "o/libc/sysv/macros.internal.inc" -.scall sys_nanosleep,0x1ae05b0f0ffff023,globl,hidden +.scall sys_nanosleep,0x9ae85b8f0ffff823,globl,hidden diff --git a/libc/sysv/calls/sys_open.s b/libc/sysv/calls/sys_open.s index ff76ad2b1..329edd4ab 100644 --- a/libc/sysv/calls/sys_open.s +++ b/libc/sysv/calls/sys_open.s @@ -1,2 +1,2 @@ .include "o/libc/sysv/macros.internal.inc" -.scall sys_open,0x0050050052005002,globl,hidden +.scall sys_open,0x8058058052805802,globl,hidden diff --git a/libc/sysv/calls/sys_poll.s b/libc/sysv/calls/sys_poll.s index 31799ccbf..5724fca7c 100644 --- a/libc/sysv/calls/sys_poll.s +++ b/libc/sysv/calls/sys_poll.s @@ -1,2 +1,2 @@ .include "o/libc/sysv/macros.internal.inc" -.scall sys_poll,0x0d10fc0d120e6007,globl,hidden +.scall sys_poll,0x8d18fc8d128e6807,globl,hidden diff --git a/libc/sysv/calls/sys_ppoll.s b/libc/sysv/calls/sys_ppoll.s index 425c2eea4..d67abbd13 100644 --- a/libc/sysv/calls/sys_ppoll.s +++ b/libc/sysv/calls/sys_ppoll.s @@ -1,2 +1,2 @@ .include "o/libc/sysv/macros.internal.inc" -.scall sys_ppoll,0xfff06d221ffff10f,globl,hidden +.scall sys_ppoll,0xfff86da21ffff90f,globl,hidden diff --git a/libc/sysv/calls/sys_pread.s b/libc/sysv/calls/sys_pread.s index bce4dfa06..8b447da4b 100644 --- a/libc/sysv/calls/sys_pread.s +++ b/libc/sysv/calls/sys_pread.s @@ -1,2 +1,2 @@ .include "o/libc/sysv/macros.internal.inc" -.scall sys_pread,0x0ad0ad1db2099011,globl,hidden +.scall sys_pread,0x8ad8ad9db2899811,globl,hidden diff --git a/libc/sysv/calls/sys_preadv.s b/libc/sysv/calls/sys_preadv.s index 3a5f810fd..7f4c57db5 100644 --- a/libc/sysv/calls/sys_preadv.s +++ b/libc/sysv/calls/sys_preadv.s @@ -1,2 +1,2 @@ .include "o/libc/sysv/macros.internal.inc" -.scall sys_preadv,0x12110b121221c127,globl,hidden +.scall sys_preadv,0x92190b9212a1c927,globl,hidden diff --git a/libc/sysv/calls/sys_pselect.s b/libc/sysv/calls/sys_pselect.s index ce670ff94..1f72f24bf 100644 --- a/libc/sysv/calls/sys_pselect.s +++ b/libc/sysv/calls/sys_pselect.s @@ -1,2 +1,2 @@ .include "o/libc/sysv/macros.internal.inc" -.scall sys_pselect,0x1b406e20a218a10e,globl,hidden +.scall sys_pselect,0x9b486ea0a298a90e,globl,hidden diff --git a/libc/sysv/calls/sys_pwrite.s b/libc/sysv/calls/sys_pwrite.s index 703fb9de7..9e568cdab 100644 --- a/libc/sysv/calls/sys_pwrite.s +++ b/libc/sysv/calls/sys_pwrite.s @@ -1,2 +1,2 @@ .include "o/libc/sysv/macros.internal.inc" -.scall sys_pwrite,0x0ae0ae1dc209a012,globl,hidden +.scall sys_pwrite,0x8ae8ae9dc289a812,globl,hidden diff --git a/libc/sysv/calls/sys_pwritev.s b/libc/sysv/calls/sys_pwritev.s index 985983a7d..a769d7bd6 100644 --- a/libc/sysv/calls/sys_pwritev.s +++ b/libc/sysv/calls/sys_pwritev.s @@ -1,2 +1,2 @@ .include "o/libc/sysv/macros.internal.inc" -.scall sys_pwritev,0x12210c122221d128,globl,hidden +.scall sys_pwritev,0x92290c9222a1d928,globl,hidden diff --git a/libc/sysv/calls/sys_read.s b/libc/sysv/calls/sys_read.s index 0f8185e48..5736be16d 100644 --- a/libc/sysv/calls/sys_read.s +++ b/libc/sysv/calls/sys_read.s @@ -1,2 +1,2 @@ .include "o/libc/sysv/macros.internal.inc" -.scall sys_read,0x0030030032003000,globl,hidden +.scall sys_read,0x8038038032803800,globl,hidden diff --git a/libc/sysv/calls/sys_readv.s b/libc/sysv/calls/sys_readv.s index 0d985abc2..2675256c9 100644 --- a/libc/sysv/calls/sys_readv.s +++ b/libc/sysv/calls/sys_readv.s @@ -1,2 +1,2 @@ .include "o/libc/sysv/macros.internal.inc" -.scall sys_readv,0x0780780782078013,globl,hidden +.scall sys_readv,0x8788788782878813,globl,hidden diff --git a/libc/sysv/calls/sys_recvfrom.s b/libc/sysv/calls/sys_recvfrom.s index cfeab7b7b..cfb1d4997 100644 --- a/libc/sysv/calls/sys_recvfrom.s +++ b/libc/sysv/calls/sys_recvfrom.s @@ -1,2 +1,2 @@ .include "o/libc/sysv/macros.internal.inc" -.scall sys_recvfrom,0x01d01d01d201d02d,globl,hidden +.scall sys_recvfrom,0x81d81d81d281d82d,globl,hidden diff --git a/libc/sysv/calls/sys_recvmsg.s b/libc/sysv/calls/sys_recvmsg.s index 32177e64a..661d6bdb2 100644 --- a/libc/sysv/calls/sys_recvmsg.s +++ b/libc/sysv/calls/sys_recvmsg.s @@ -1,2 +1,2 @@ .include "o/libc/sysv/macros.internal.inc" -.scall sys_recvmsg,0x01b01b01b201b02f,globl,hidden +.scall sys_recvmsg,0x81b81b81b281b82f,globl,hidden diff --git a/libc/sysv/calls/sys_select.s b/libc/sysv/calls/sys_select.s index bb8184dcc..099846215 100644 --- a/libc/sysv/calls/sys_select.s +++ b/libc/sysv/calls/sys_select.s @@ -1,2 +1,2 @@ .include "o/libc/sysv/macros.internal.inc" -.scall sys_select,0x1a104705d205d017,globl,hidden +.scall sys_select,0x9a184785d285d817,globl,hidden diff --git a/libc/sysv/calls/sys_sendmsg.s b/libc/sysv/calls/sys_sendmsg.s index 015899bd3..aaf95bed8 100644 --- a/libc/sysv/calls/sys_sendmsg.s +++ b/libc/sysv/calls/sys_sendmsg.s @@ -1,2 +1,2 @@ .include "o/libc/sysv/macros.internal.inc" -.scall sys_sendmsg,0x01c01c01c201c02e,globl,hidden +.scall sys_sendmsg,0x81c81c81c281c82e,globl,hidden diff --git a/libc/sysv/calls/sys_sendto.s b/libc/sysv/calls/sys_sendto.s index b0162e9b1..8a0056186 100644 --- a/libc/sysv/calls/sys_sendto.s +++ b/libc/sysv/calls/sys_sendto.s @@ -1,2 +1,2 @@ .include "o/libc/sysv/macros.internal.inc" -.scall sys_sendto,0x085085085208502c,globl,hidden +.scall sys_sendto,0x885885885288582c,globl,hidden diff --git a/libc/sysv/calls/sys_sigsuspend.s b/libc/sysv/calls/sys_sigsuspend.s index cbf2b659e..9974260d0 100644 --- a/libc/sysv/calls/sys_sigsuspend.s +++ b/libc/sysv/calls/sys_sigsuspend.s @@ -1,2 +1,2 @@ .include "o/libc/sysv/macros.internal.inc" -.scall sys_sigsuspend,0x12606f155206f082,globl,hidden +.scall sys_sigsuspend,0x92686f955286f882,globl,hidden diff --git a/libc/sysv/calls/sys_sigtimedwait.s b/libc/sysv/calls/sys_sigtimedwait.s index 33ba49272..2113a46e2 100644 --- a/libc/sysv/calls/sys_sigtimedwait.s +++ b/libc/sysv/calls/sys_sigtimedwait.s @@ -1,2 +1,2 @@ .include "o/libc/sysv/macros.internal.inc" -.scall sys_sigtimedwait,0x1affff159ffff080,globl,hidden +.scall sys_sigtimedwait,0x9affff959ffff880,globl,hidden diff --git a/libc/sysv/calls/sys_statfs.s b/libc/sysv/calls/sys_statfs.s index a1990e83f..aec6af5e7 100644 --- a/libc/sysv/calls/sys_statfs.s +++ b/libc/sysv/calls/sys_statfs.s @@ -1,2 +1,2 @@ .include "o/libc/sysv/macros.internal.inc" -.scall sys_statfs,0x09d03f22b2159089,globl,hidden +.scall sys_statfs,0x89d83fa2b2959889,globl,hidden diff --git a/libc/sysv/calls/sys_truncate.s b/libc/sysv/calls/sys_truncate.s index e2710fe4e..768200310 100644 --- a/libc/sysv/calls/sys_truncate.s +++ b/libc/sysv/calls/sys_truncate.s @@ -1,2 +1,2 @@ .include "o/libc/sysv/macros.internal.inc" -.scall sys_truncate,0x0c80c81df20c804c,globl,hidden +.scall sys_truncate,0x8c88c89df28c884c,globl,hidden diff --git a/libc/sysv/calls/sys_waitid.s b/libc/sysv/calls/sys_waitid.s index eab72d6a0..b77e7a078 100644 --- a/libc/sysv/calls/sys_waitid.s +++ b/libc/sysv/calls/sys_waitid.s @@ -1,2 +1,2 @@ .include "o/libc/sysv/macros.internal.inc" -.scall sys_waitid,0xfffffffff20ad0f7,globl +.scall sys_waitid,0xfffffffff28ad8f7,globl diff --git a/libc/sysv/calls/sys_write.s b/libc/sysv/calls/sys_write.s index 4162549d1..fd196f011 100644 --- a/libc/sysv/calls/sys_write.s +++ b/libc/sysv/calls/sys_write.s @@ -1,2 +1,2 @@ .include "o/libc/sysv/macros.internal.inc" -.scall sys_write,0x0040040042004001,globl,hidden +.scall sys_write,0x8048048042804801,globl,hidden diff --git a/libc/sysv/calls/sys_writev.s b/libc/sysv/calls/sys_writev.s index 45b8beb55..11f8ffb20 100644 --- a/libc/sysv/calls/sys_writev.s +++ b/libc/sysv/calls/sys_writev.s @@ -1,2 +1,2 @@ .include "o/libc/sysv/macros.internal.inc" -.scall sys_writev,0x0790790792079014,globl,hidden +.scall sys_writev,0x8798798792879814,globl,hidden diff --git a/libc/sysv/consts.sh b/libc/sysv/consts.sh index 58e7e37bb..20334d0d5 100755 --- a/libc/sysv/consts.sh +++ b/libc/sysv/consts.sh @@ -168,9 +168,10 @@ syscon sig SIGPROF 27 27 27 27 27 27 # profiling timer expired; syscon sig SIGWINCH 28 28 28 28 28 28 # terminal resized; unix consensus & faked on nt syscon sig SIGIO 29 23 23 23 23 29 # bsd consensus syscon sig SIGSYS 31 12 12 12 12 31 # wut; bsd consensus +syscon sig SIGINFO 0 29 29 29 29 0 # bsd consensus syscon sig SIGEMT 0 7 7 7 7 0 # not implemented in most community editions of system five; consider doing this using SIGUSR1 or SIGUSR2 instead syscon sig SIGPWR 30 30 30 30 32 30 # not implemented in most community editions of system five; consider doing this using SIGUSR1 or SIGUSR2 instead -syscon sig SIGINFO 0 29 29 29 29 0 # bsd consensus +syscon sig SIGCANCEL 32 7 65 7 33 32 # SIGRTMIN+0; faked as SIGEMT on XNU and OpenBSD syscon sig SIGRTMIN 32 0 65 0 33 32 syscon sig SIGRTMAX 64 0 126 0 63 64 syscon compat SIGPOLL 29 23 23 23 23 29 # same as SIGIO diff --git a/libc/sysv/consts/EDEVERR.s b/libc/sysv/consts/EDEVERR.s index 1deaa2ea7..b9fd0c96c 100644 --- a/libc/sysv/consts/EDEVERR.s +++ b/libc/sysv/consts/EDEVERR.s @@ -1,2 +1,2 @@ .include "o/libc/sysv/consts/syscon.internal.inc" -.syscon errno,EDEVERR,311,83,311,311,311,0 +.syscon errno,EDEVERR,311,83,311,311,311,483 diff --git a/libc/sysv/consts/SIGCANCEL.s b/libc/sysv/consts/SIGCANCEL.s new file mode 100644 index 000000000..b7ab88be7 --- /dev/null +++ b/libc/sysv/consts/SIGCANCEL.s @@ -0,0 +1,2 @@ +.include "o/libc/sysv/consts/syscon.internal.inc" +.syscon sig,SIGCANCEL,32,7,65,7,33,32 diff --git a/libc/sysv/consts/sig.h b/libc/sysv/consts/sig.h index 46e58f763..a2f996688 100644 --- a/libc/sysv/consts/sig.h +++ b/libc/sysv/consts/sig.h @@ -7,6 +7,7 @@ COSMOPOLITAN_C_START_ extern const int SIGABRT; extern const int SIGALRM; extern const int SIGBUS; +extern const int SIGCANCEL; extern const int SIGCHLD; extern const int SIGCONT; extern const int SIGEMT; @@ -72,6 +73,7 @@ COSMOPOLITAN_C_END_ #define SIGXFSZ LITERALLY(25) #define SIGBUS SYMBOLIC(SIGBUS) +#define SIGCANCEL SYMBOLIC(SIGCANCEL) #define SIGCHLD SYMBOLIC(SIGCHLD) #define SIGCONT SYMBOLIC(SIGCONT) #define SIGEMT SYMBOLIC(SIGEMT) diff --git a/libc/sysv/syscalls.sh b/libc/sysv/syscalls.sh index bcba2eea7..8cab83c6a 100755 --- a/libc/sysv/syscalls.sh +++ b/libc/sysv/syscalls.sh @@ -22,43 +22,44 @@ dir=libc/sysv/calls # The Fifth Bell System Interface, Community Edition ┌─────────────────────────┐ # » so many numbers │ legend │ # ├─────────────────────────┤ -# GNU/Systemd┐ │ ffff │ unavailable │ -# 2.6.18+│ │ sys_ │ wrapped │ -# Mac OS X┐ │ │ __sys_ │ wrapped twice │ -# 15.6+│ │ └─────────────────────────┘ -# FreeBSD┐ │ │ -# 12+│ ┌─│──│── XnuClass{1:Mach,2:Unix} -# OpenBSD┐ │ │ │ │ +# GNU/Systemd┐ │ fff │ unavailable │ +# 2.6.18+│ │ 800 │ cancellable │ +# Mac OS X┐ │ │ sys_ │ wrapped │ +# 15.6+│ │ │ __sys_ │ wrapped twice │ +# FreeBSD┐ │ │ └─────────────────────────┘ +# 12+│ │ │ +# OpenBSD┐ │ ┌─│──│── XnuClass{1:Mach,2:Unix} # 6.4+│ │ │ │ │ # NetBSD┐ │ │ │ │ │ # 9.1+│ │ │ │ │ │ # Symbol ┌┴┐┌┴┐┌┴┐│┬┴┐┌┴┐ Directives & Commentary scall sys_exit 0x00100100120010e7 globl hidden # a.k.a. exit_group -scall sys_read 0x0030030032003000 globl hidden -scall sys_write 0x0040040042004001 globl hidden -scall sys_open 0x0050050052005002 globl hidden +scall sys_read 0x8038038032803800 globl hidden +scall sys_write 0x8048048042804801 globl hidden +scall sys_open 0x8058058052805802 globl hidden scall sys_close 0x0060060062006003 globl hidden scall __sys_stat 0x1b7026fff2152004 globl hidden # FreeBSD 11→12 fumble; use sys_fstatat(); blocked on Android scall __sys_fstat 0x1b80352272153005 globl hidden # needs __stat2linux() scall __sys_lstat 0x1b90280282154006 globl hidden # needs __stat2linux(); blocked on Android -scall sys_poll 0x0d10fc0d120e6007 globl hidden -scall sys_ppoll 0xfff06d221ffff10f globl hidden # consider INTON/INTOFF tutorial in examples/unbourne.c +scall sys_poll 0x8d18fc8d128e6807 globl hidden +scall sys_ppoll 0xfff86da21ffff90f globl hidden # consider INTON/INTOFF tutorial in examples/unbourne.c scall sys_lseek 0x0c70c71de20c7008 globl hidden # netbsd+openbsd:evilpad scall __sys_mmap 0x0c50c51dd20c5009 globl hidden # netbsd+openbsd:pad -scall sys_msync 0x115100041204101a globl hidden +scall sys_msync 0x915900841284181a globl hidden scall sys_mprotect 0x04a04a04a204a00a globl hidden scall __sys_munmap 0x049049049204900b globl hidden scall sys_sigaction 0x15402e1a0202e00d globl hidden # rt_sigaction on Lunix; __sigaction_sigtramp() on NetBSD scall __sys_sigprocmask 0x125030154214900e globl hidden # a.k.a. rt_sigprocmask, openbsd:byvalue, a.k.a. pthread_sigmask scall sys_ioctl 0x0360360362036010 globl hidden -scall sys_pread 0x0ad0ad1db2099011 globl hidden # a.k.a. pread64; netbsd+openbsd:pad -scall sys_pwrite 0x0ae0ae1dc209a012 globl hidden # a.k.a. pwrite64; netbsd+openbsd:pad -scall sys_readv 0x0780780782078013 globl hidden -scall sys_writev 0x0790790792079014 globl hidden +scall sys_ioctl_cp 0x8368368362836810 globl hidden +scall sys_pread 0x8ad8ad9db2899811 globl hidden # a.k.a. pread64; netbsd+openbsd:pad +scall sys_pwrite 0x8ae8ae9dc289a812 globl hidden # a.k.a. pwrite64; netbsd+openbsd:pad +scall sys_readv 0x8788788782878813 globl hidden +scall sys_writev 0x8798798792879814 globl hidden scall sys_access 0x0210210212021015 globl hidden scall __sys_pipe 0x02a10721e202a016 globl hidden # NOTE: pipe2() on FreeBSD; XNU is pipe(void)→eax:edx -scall sys_select 0x1a104705d205d017 globl hidden -scall sys_pselect 0x1b406e20a218a10e globl hidden # pselect6() on gnu/systemd +scall sys_select 0x9a184785d285d817 globl hidden +scall sys_pselect 0x9b486ea0a298a90e globl hidden # pselect6() on gnu/systemd scall sys_sched_yield 0x15e12a14bf25d018 globl hidden # select() on XNU (previously swtch() but removed in 12.4) scall __sys_mremap 0x19bffffffffff019 globl hidden scall sys_mincore 0x04e04e04e204e01b globl hidden @@ -69,20 +70,20 @@ scall sys_shmctl 0x1bb128200210701f globl # no wrapper; consider mmap scall sys_dup 0x0290290292029020 globl hidden scall sys_dup2 0x05a05a05a205a021 globl hidden scall sys_pause 0xfffffffffffff022 globl hidden -scall sys_nanosleep 0x1ae05b0f0ffff023 globl hidden -scall sys_clock_nanosleep 0x1ddfff0f4ffff0e6 globl hidden +scall sys_nanosleep 0x9ae85b8f0ffff823 globl hidden +scall sys_clock_nanosleep 0x9ddfff8f4ffff8e6 globl hidden scall sys_getitimer 0x1aa0460562056024 globl hidden scall sys_setitimer 0x1a90450532053026 globl hidden scall sys_alarm 0xfffffffffffff025 globl hidden scall sys_getpid 0x0140140142014027 globl hidden # netbsd returns ppid in edx scall sys_sendfile 0xffffff1892151028 globl hidden # Linux vs. XNU/BSD ABIs very different scall __sys_socket 0x18a0610612061029 globl hidden -scall __sys_connect 0x062062062206202a globl hidden -scall __sys_accept 0x01e01e21d201e02b globl hidden # accept4 on freebsd -scall sys_sendto 0x085085085208502c globl hidden -scall sys_recvfrom 0x01d01d01d201d02d globl hidden -scall sys_sendmsg 0x01c01c01c201c02e globl hidden -scall sys_recvmsg 0x01b01b01b201b02f globl hidden +scall __sys_connect 0x862862862286282a globl hidden +scall __sys_accept 0x81e81ea1d281e82b globl hidden # accept4 on freebsd +scall sys_sendto 0x885885885288582c globl hidden +scall sys_recvfrom 0x81d81d81d281d82d globl hidden +scall sys_sendmsg 0x81c81c81c281c82e globl hidden +scall sys_recvmsg 0x81b81b81b281b82f globl hidden scall sys_shutdown 0x0860860862086030 globl hidden scall __sys_bind 0x0680680682068031 globl hidden scall sys_listen 0x06a06a06a206a032 globl hidden @@ -95,7 +96,7 @@ scall __sys_fork 0x0020020022002039 globl hidden # xnu needs eax&=~-edx bc eax #scall vfork 0x042042042204203a globl # this syscall is from the moon so we implement it by hand in libc/runtime/vfork.S; probably removed from XNU in 12.5 scall sys_posix_spawn 0x1daffffff20f4fff globl hidden # good luck figuring out how xnu defines this scall __sys_execve 0x03b03b03b203b03b globl hidden -scall __sys_wait4 0x1c100b007200703d globl hidden +scall __sys_wait4 0x9c180b807280783d globl hidden scall sys_kill 0x02507a025202503e globl hidden # kill(pid, sig, 1) b/c xnu scall sys_killpg 0x092fff092fffffff globl hidden scall sys_clone 0x11fffffffffff038 globl hidden @@ -109,15 +110,16 @@ scall sys_semop 0x0de1220de2100041 globl # no wrapper; won't polyfill for windo scall sys_semctl 0xfff1271fe20fe042 globl # no wrapper; won't polyfill for windows scall sys_shmdt 0x0e60e60e62108043 globl # no wrapper; won't polyfill for windows scall sys_msgget 0x0e10e10e12103044 globl # no wrapper; won't polyfill for windows -scall sys_msgsnd 0x0e20e20e22104045 globl # no wrapper; won't polyfill for windows -scall sys_msgrcv 0x0e30e30e32105046 globl # no wrapper; won't polyfill for windows +scall sys_msgsnd 0x8e28e28e22904845 globl # no wrapper; won't polyfill for windows +scall sys_msgrcv 0x8e38e38e32905846 globl # no wrapper; won't polyfill for windows scall sys_msgctl 0x1bc1291ff2102047 globl # no wrapper; won't polyfill for windows scall __sys_fcntl 0x05c05c05c205c048 globl hidden -scall sys_flock 0x0830830832083049 globl hidden -scall sys_fsync 0x05f05f05f205f04a globl hidden -scall sys_fdatasync 0x0f105f22620bb04b globl hidden # fsync() on openbsd -scall sys_truncate 0x0c80c81df20c804c globl hidden # netbsd+openbsd:pad -scall sys_ftruncate 0x0c90c91e020c904d globl hidden # netbsd+openbsd:pad +scall __sys_fcntl_cp 0x85c85c85c285c848 globl hidden +scall sys_flock 0x8838838832883849 globl hidden +scall sys_fsync 0x85f85f85f285f84a globl hidden +scall sys_fdatasync 0x8f185fa2628bb84b globl hidden # fsync() on openbsd +scall sys_truncate 0x8c88c89df28c884c globl hidden # netbsd+openbsd:pad +scall sys_ftruncate 0x8c98c99e028c984d globl hidden # netbsd+openbsd:pad scall sys_getcwd 0x128130146ffff04f globl hidden scall sys_chdir 0x00c00c00c200c050 globl hidden scall sys_fchdir 0x00d00d00d200d051 globl hidden @@ -163,14 +165,14 @@ scall sys_setresgid 0xfff11c138ffff077 globl hidden # polyfilled for xnu scall sys_getresuid 0xfff119168ffff076 globl hidden # semantics aren't well-defined scall sys_getresgid 0xfff11b169ffff078 globl hidden # semantics aren't well-defined scall sys_sigpending 0x124034157203407f globl hidden # a.k.a. rt_sigpending on linux -scall sys_sigsuspend 0x12606f155206f082 globl hidden # a.k.a. rt_sigsuspend on Linux; openbsd:byvalue, sigsuspend_nocancel on XNU +scall sys_sigsuspend 0x92686f955286f882 globl hidden # a.k.a. rt_sigsuspend on Linux; openbsd:byvalue, sigsuspend_nocancel on XNU scall sys_sigaltstack 0x1191200352035083 globl hidden scall sys_mknod 0x1c200e00e200e085 globl hidden scall sys_mknodat 0x1cc14022fffff103 globl # no wrapper; FreeBSD 12+ scall sys_mkfifo 0x0840840842084fff globl hidden scall sys_mkfifoat 0x1cb13f1f1fffffff globl # no wrapper -scall sys_statfs 0x09d03f22b2159089 globl hidden -scall sys_fstatfs 0x09e04022c215a08a globl hidden +scall sys_statfs 0x89d83fa2b2959889 globl hidden +scall sys_fstatfs 0x89e840a2c295a88a globl hidden scall sys_getpriority 0x064064064206408c globl hidden scall sys_setpriority 0x060060060206008d globl hidden # modern nice() scall sys_mlock 0x0cb0cb0cb20cb095 globl # no wrapper @@ -191,7 +193,7 @@ scall sys_setfsuid 0xfffffffffffff07a globl hidden scall sys_setfsgid 0xfffffffffffff07b globl hidden scall sys_capget 0xfffffffffffff07d globl # no wrapper scall sys_capset 0xfffffffffffff07e globl # no wrapper -scall sys_sigtimedwait 0x1affff159ffff080 globl hidden +scall sys_sigtimedwait 0x9affff959ffff880 globl hidden scall sys_sigqueue 0xffffff1c8fffffff globl hidden scall sys_sigqueueinfo 0x0f5ffffffffff081 globl hidden # a.k.a. rt_sigqueueinfo on linux scall sys_personality 0xfffffffffffff087 globl # no wrapper @@ -242,7 +244,7 @@ scall sys_io_submit 0xfffffffffffff0d1 globl # no wrapper scall sys_io_cancel 0xfffffffffffff0d2 globl # no wrapper scall sys_lookup_dcookie 0xfffffffffffff0d4 globl # no wrapper scall sys_epoll_create 0xfffffffffffff0d5 globl hidden -scall sys_epoll_wait 0xfffffffffffff0e8 globl hidden +scall sys_epoll_wait 0xfffffffffffff8e8 globl hidden scall sys_epoll_ctl 0xfffffffffffff0e9 globl hidden scall sys_getdents 0x18606311020c40d9 globl hidden # use opendir/readdir; four args b/c xnu, getdirentries on xnu, 32-bit on xnu/freebsd, a.k.a. getdents64 on linux, 64-bit on openbsd scall sys_set_tid_address 0xfffffffffffff0da globl # no wrapper @@ -273,7 +275,7 @@ scall sys_mq_timedreceive 0x1b1ffffffffff0f3 globl # won't polyfill scall sys_mq_notify 0x106ffffffffff0f4 globl # won't polyfill scall sys_mq_getsetattr 0xfffffffffffff0f5 globl # won't polyfill scall sys_kexec_load 0xfffffffffffff0f6 globl # no wrapper -scall sys_waitid 0xfffffffff20ad0f7 globl # Linux 2.6.9+; no wrapper +scall sys_waitid 0xfffffffff28ad8f7 globl # Linux 2.6.9+; no wrapper scall sys_add_key 0xfffffffffffff0f8 globl # no wrapper scall sys_request_key 0xfffffffffffff0f9 globl # no wrapper scall sys_keyctl 0xfffffffffffff0fa globl # no wrapper @@ -282,7 +284,7 @@ scall ioprio_get 0xfffffffffffff0fc globl scall sys_inotify_init 0xfffffffffffff0fd globl # wicked # no wrapper scall sys_inotify_add_watch 0xfffffffffffff0fe globl # no wrapper scall sys_inotify_rm_watch 0xfffffffffffff0ff globl # no wrapper -scall __sys_openat 0x1d41411f321cf101 globl hidden # Linux 2.6.16+ (c. 2007) +scall __sys_openat 0x9d49419f329cf901 globl hidden # Linux 2.6.16+ (c. 2007) scall sys_mkdirat 0x1cd13e1f021db102 globl hidden scall sys_fchownat 0x1d013b1eb21d4104 globl hidden # @asyncsignalsafe scall sys_utime 0xfffffffffffff084 globl hidden @@ -306,12 +308,12 @@ scall sys_vmsplice 0xfffffffffffff116 globl hidden scall sys_migrate_pages 0xfffffffffffff100 globl # no wrapper; numa numa yay scall sys_move_pages 0xfffffffffffff117 globl # no wrapper; NOTE: We view Red Hat versions as "epochs" for all distros. #──────────────────────RHEL 5.0 LIMIT──────────────────────── # ←┬─ last distro with gplv2 licensed compiler c. 2007 -scall sys_preadv 0x12110b121221c127 globl hidden # ├─ last distro with system v shell script init -scall sys_pwritev 0x12210c122221d128 globl hidden # ├─ rob landley unleashes busybox gpl lawsuits +scall sys_preadv 0x92190b9212a1c927 globl hidden # ├─ last distro with system v shell script init +scall sys_pwritev 0x92290c9222a1d928 globl hidden # ├─ rob landley unleashes busybox gpl lawsuits scall __sys_utimensat 0x1d3054223ffff118 globl hidden # ├─ python modules need this due to pep513 -scall sys_fallocate 0xfffffffffffff11d globl # ├─ end of life 2020-11-30 (extended) -scall posix_fallocate 0x1dffff212fffffff globl hidden # └─ cosmopolitan supports rhel5+ -scall __sys_accept4 0xfff05d21dffff120 globl hidden # Linux 2.6.28+ +scall sys_fallocate 0xfffffffffffff91d globl # ├─ end of life 2020-11-30 (extended) +scall posix_fallocate 0x9dffffa12fffffff globl hidden # └─ cosmopolitan supports rhel5+ +scall __sys_accept4 0xfff85da1dffff920 globl hidden # Linux 2.6.28+ scall __sys_dup3 0x1c6066fffffff124 globl hidden # Linux 2.6.27+ scall __sys_pipe2 0x1c506521effff125 globl hidden # Linux 2.6.27+ scall sys_epoll_pwait 0xfffffffffffff119 globl # no wrapper @@ -347,7 +349,7 @@ scall sys_sched_setattr 0xfffffffffffff13a globl # ├─ desktop replaced with scall sys_sched_getattr 0xfffffffffffff13b globl # ├─ karen sandler requires systemd init and boot for tablet gui scall sys_renameat2 0xfffffffffffff13c globl # └─ debian founder ian murdock found strangled with vacuum cord #scall seccomp 0xfffffffffffff13d globl # wrapped manually -scall sys_getrandom 0xfff00723321f413e globl hidden # Linux 3.17+ and getentropy() on XNU/OpenBSD, coming to NetBSD in 9.2 +scall sys_getrandom 0xfff807a3329f493e globl hidden # Linux 3.17+ and getentropy() on XNU/OpenBSD, coming to NetBSD in 9.2 scall sys_memfd_create 0xfffffffffffff13f globl hidden scall sys_kexec_file_load 0xfffffffffffff140 globl # no wrapper scall sys_bpf 0xfffffffffffff141 globl # no wrapper diff --git a/libc/sysv/systemfive.S b/libc/sysv/systemfive.S index a16b00d1b..08b0e4b38 100644 --- a/libc/sysv/systemfive.S +++ b/libc/sysv/systemfive.S @@ -21,6 +21,7 @@ #include "libc/macros.internal.h" #include "libc/nexgen32e/macros.h" #include "libc/sysv/consts/sig.h" +#include "libc/thread/posixthread.internal.h" #include "libc/sysv/consts/nr.h" #define SIG_IGN 1 @@ -107,19 +108,60 @@ __pid: .quad 0 .endobj __pid,globl,hidden .previous - .privileged +systemfive_cancellable: # our pthread_cancel() miracle code + cmpb $0,__tls_enabled(%rip) # inspired by the musl libc design! + je 1f # we handle linux and bsd together! + mov %fs:0,%r10 # CosmoTib::tib_self + mov 0x28(%r10),%r10 # CosmoTib::tib_pthread + test %r10,%r10 # is it a posix thread? + jz 1f # it's spawn() probably + testb $PT_NOCANCEL,0x00(%r10) # PosixThread::flags + jnz 1f # canceler no cancelling + cmp $0,0x04(%r10) # PosixThread::cancelled + jne _pthread_cancel_sys # tail call for masked mode + .weak _pthread_cancel_sys # must be linked if we're cancelled +1: mov %rcx,%r10 # move the fourth argument + clc # no cancellable system calls exist + syscall # that have 7+ args on the bsd OSes +systemfive_cancellable_end: # i/o calls park here for long time + jc systemfive_errno + jmp 0f + jc 3f # we're now out of the limbo state! +1: cmp $-4095,%rax # but we still check again on eintr + jae 2f + ret # done if the system call succeeded +2: neg %eax # now examine the nature of failure +3: cmp EINTR(%rip),%eax # did SIGCANCEL cancel our i/o call + jne systemfive_errno # werent interrupted by OnSigCancel + cmpb $0,__tls_enabled(%rip) # make sure it's safe to grab %fs:0 + je systemfive_errno # tls is disabled we can't continue + mov %fs:0,%rcx # CosmoTib::tib_self + mov 0x28(%rcx),%rcx # CosmoTib::tib_pthread + test %rcx,%rcx # is it a posix thread? + jz systemfive_errno # it's spawn() probably + testb $PT_NOCANCEL,0x00(%rcx) # PosixThread::flags + jnz systemfive_errno # cancellation is disabled + cmp $0,0x04(%rcx) # PosixThread::cancelled + je systemfive_errno # we aren't actually cancelled + jmp _pthread_cancel_sys # now we are in fact cancelled + .endfn systemfive_cancellable,globl,hidden + .globl systemfive_cancellable_end + .hidden systemfive_cancellable_end + .Lanchorpoint: #if SupportsLinux() || SupportsMetal() systemfive_linux: - and $0xfff,%eax - cmp $0xfff,%eax + and $0xfff,%eax # remove nonlinux bits from ordinal + cmp $0xfff,%eax # checks if unsupported by platform je systemfive_enosys # never taken branches cost nothing + btr $11,%eax # 0x800 means a call is cancellable + jc systemfive_cancellable # it is handled by the holiest code mov %rcx,%r10 # syscall instruction clobbers %rcx push %rbp # linux never reads args from stack mov %rsp,%rbp # having frame will help backtraces syscall # this is known as a context switch pop %rbp # next we check to see if it failed - cmp $-4095,%rax # system five nexgen32e abi § a.2.1 +0: cmp $-4095,%rax # system five nexgen32e abi § a.2.1 jae systemfive_error # encodes errno as neg return value ret .endfn systemfive_linux,globl,hidden @@ -167,17 +209,10 @@ systemfive_bsdscrub: systemfive_bsd: cmp $0xfff,%ax je systemfive_enosys + btr $11,%eax # checks/reset the 800 cancellable bit + jc systemfive_cancellable mov %rcx,%r10 - push %rbx - push 32(%rsp) - push 24(%rsp) - push 16(%rsp) - mov %rax,%rbx # save ordinal for SIGSYS crash report syscall # bsd will need arg on stack sometimes - pop %rbx - pop %rbx - pop %rbx - pop %rbx jc systemfive_errno # bsd sets carry flag if %rax is errno ret .endfn systemfive_bsd @@ -391,22 +426,6 @@ _init_systemfive_sigsys: pop %rdi 1: .endfn _init_systemfive_sigsys #endif -#if SupportsSystemv() && !defined(TINY) -_init_systemfive_syscall: - mov __NR_msyscall,%eax # syscall origin protect - cmp $0xfff,%ax # openbsd is pretty cool - jae _init_systemfive_done - push %rdi - push %rsi - .weak __privileged_addr - .weak __privileged_size - mov $__privileged_addr,%edi - mov $__privileged_size,%esi - syscall - pop %rsi - pop %rdi -// 𝑠𝑙𝑖𝑑𝑒 -#endif /* TINY */ _init_systemfive_done: nop .init.end 300,_init_systemfive,globl,hidden diff --git a/libc/thread/posixthread.internal.h b/libc/thread/posixthread.internal.h index d7cb697c9..b63df05af 100644 --- a/libc/thread/posixthread.internal.h +++ b/libc/thread/posixthread.internal.h @@ -8,14 +8,13 @@ #define PT_OWNSTACK 1 #define PT_MAINTHREAD 2 +#define PT_ASYNC 4 +#define PT_NOCANCEL 8 +#define PT_MASKED 16 #if !(__ASSEMBLER__ + __LINKER__ + 0) COSMOPOLITAN_C_START_ -/** - * @fileoverview Cosmopolitan POSIX Thread Internals - */ - // LEGAL TRANSITIONS ┌──> TERMINATED // pthread_create ─┬─> JOINABLE ─┴┬─> DETACHED ──> ZOMBIE // └──────────────┘ @@ -60,15 +59,13 @@ enum PosixThreadStatus { }; struct PosixThread { + int flags; // 0x00: see PT_* constants + _Atomic(int) cancelled; // 0x04: thread has bad beliefs _Atomic(enum PosixThreadStatus) status; - void *(*start_routine)(void *); - void *arg; // start_routine's parameter - void *rc; // start_routine's return value int tid; // clone parent tid - int flags; // see PT_* constants - _Atomic(int) cancelled; // thread has bad beliefs - char cancelasync; // PTHREAD_CANCEL_DEFERRED/ASYNCHRONOUS - char canceldisable; // PTHREAD_CANCEL_ENABLE/DISABLE + void *(*start)(void *); // creation callback + void *arg; // start's parameter + void *rc; // start's return value char *altstack; // thread sigaltstack char *tls; // bottom of tls allocation struct CosmoTib *tib; // middle of tls allocation @@ -98,6 +95,7 @@ void _pthread_key_destruct(void) hidden; void _pthread_onfork_prepare(void) hidden; void _pthread_onfork_parent(void) hidden; void _pthread_onfork_child(void) hidden; +int _pthread_cancel_sys(void) hidden; COSMOPOLITAN_C_END_ #endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */ diff --git a/libc/thread/pthread_cancel.c b/libc/thread/pthread_cancel.c index 520f0646f..79371dd93 100644 --- a/libc/thread/pthread_cancel.c +++ b/libc/thread/pthread_cancel.c @@ -16,52 +16,184 @@ │ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │ │ PERFORMANCE OF THIS SOFTWARE. │ ╚─────────────────────────────────────────────────────────────────────────────*/ -#include "libc/intrin/kprintf.h" +#include "libc/assert.h" +#include "libc/calls/calls.h" +#include "libc/calls/struct/sigaction.h" +#include "libc/calls/struct/siginfo.h" +#include "libc/calls/struct/sigset.h" +#include "libc/calls/ucontext.h" +#include "libc/errno.h" +#include "libc/intrin/atomic.h" #include "libc/runtime/runtime.h" +#include "libc/str/str.h" +#include "libc/sysv/consts/sa.h" +#include "libc/sysv/consts/sig.h" +#include "libc/sysv/errfuns.h" +#include "libc/thread/posixthread.internal.h" #include "libc/thread/thread.h" +#include "libc/thread/tls.h" + +extern const char systemfive_cancellable[] hidden; +extern const char systemfive_cancellable_end[] hidden; + +int _pthread_cancel_sys(void) { + struct PosixThread *pt; + pt = (struct PosixThread *)__get_tls()->tib_pthread; + if (!(pt->flags & (PT_NOCANCEL | PT_MASKED)) || (pt->flags & PT_ASYNC)) { + pthread_exit(PTHREAD_CANCELED); + } + pt->flags |= PT_NOCANCEL; + return ecanceled(); +} + +static void OnSigCancel(int sig, siginfo_t *si, void *ctx) { + ucontext_t *uc = ctx; + struct CosmoTib *tib = __get_tls(); + struct PosixThread *pt = (struct PosixThread *)tib->tib_pthread; + if (pt && !(pt->flags & PT_NOCANCEL) && + atomic_load_explicit(&pt->cancelled, memory_order_acquire)) { + sigaddset(&uc->uc_sigmask, sig); + if ((pt->flags & PT_ASYNC) || + (systemfive_cancellable <= (char *)uc->uc_mcontext.rip && + (char *)uc->uc_mcontext.rip < systemfive_cancellable_end)) { + uc->uc_mcontext.rip = (intptr_t)_pthread_cancel_sys; + } else { + tkill(atomic_load_explicit(&tib->tib_tid, memory_order_relaxed), sig); + } + } +} + +static void ListenForSigCancel(void) { + struct sigaction sa; + sa.sa_sigaction = OnSigCancel; + sa.sa_flags = SA_SIGINFO | SA_RESTART | SA_ONSTACK; + memset(&sa.sa_mask, -1, sizeof(sa.sa_mask)); + _npassert(!sigaction(SIGCANCEL, &sa, 0)); +} /** * Cancels thread. * - * This function currently isn't supported. In order to support this - * function we'd need to redesign the system call interface, and add - * bloat and complexity to every function that can return EINTR. You - * might want to consider using `nsync_note` instead, which provides - * much better cancellations because posix cancellations is a broken - * design. If you need to cancel i/o operations, try doing this: + * When a thread is cancelled, it'll interrupt blocking i/o calls, + * invoke any cleanup handlers that were pushed on the thread's stack + * as well as key destructors, and then the thread exits. * - * _Thread_local bool gotusr1; - * void OnUsr1(int sig) { gotusr1 = true; } - * struct sigaction sa = {.sa_handler = OnUsr1}; - * sigaction(SIGUSR1, &sa, 0); - * pthread_kill(thread, SIGUSR1); + * By default, pthread_cancel() can only take effect when a thread is + * blocked on a @cancellationpoint, which is any system call that's + * specified as raising `EINTR`. For example, `openat`, `poll`, `ppoll`, + * `select`, `pselect`, `read`, `readv`, `pread`, `preadv`, `write`, + * `writev`, `pwrite`, `pwritev`, `accept`, `connect`, `recvmsg`, + * `sendmsg`, `recv`, `send`, `tcdrain`, `clock_nanosleep`, `fsync`, + * `fdatasync`, `fcntl(F_SETLKW)`, `epoll`, `sigsuspend`, `msync`, + * `wait4`, `getrandom`, `pthread_cond_timedwait` are most cancellation + * points, plus many userspace libraries that call the above functions, + * unless they're using pthread_setcancelstate() to temporarily disable + * the cancellation mechanism. Some userspace functions, e.g. system() + * and popen() will eagerly call pthread_testcancel_np() to help avoid + * the potential for resource leaks later on. * - * The above code should successfully cancel a thread's blocking io - * operations in most cases, e.g. + * It's possible to put a thread in asynchronous cancellation mode using + * pthread_setcanceltype(), thus allowing a cancellation to occur at any + * assembly opcode. Please be warned that doing so is risky since it can + * easily result in resource leaks. For example, a cancellation might be + * triggered between calling open() and pthread_cleanup_push(), in which + * case the application will leak a file descriptor. * - * void *MyThread(void *arg) { - * sigset_t ss; - * sigfillset(&ss); - * sigdelset(&ss, SIGUSR1); - * sigprocmask(SIG_SETMASK, &ss, 0); - * while (!gotusr1) { - * char buf[512]; - * ssize_t rc = read(0, buf, sizeof(buf)); - * if (rc == -1 && errno == EINTR) continue; - * write(1, buf, rc); - * } - * return 0; - * } + * If none of the above options seem savory to you, then a third way is + * offered for doing cancellations. Cosmopolitan Libc supports the Musl + * Libc `PTHREAD_CANCEL_MASKED` non-POSIX extension. Any thread may pass + * this setting to pthread_setcancelstate(), in which case threads won't + * be abruptly destroyed upon cancellation and have their stack unwound; + * instead, cancellation points will simply raise an `ECANCELED` error, + * which can be more safely and intuitively handled for many use cases. * - * This has the same correctness issue as glibc, but it's usually - * "good enough" if you only need cancellations to perform things - * like server shutdown and socket options like `SO_RCVTIMEO` can - * ensure it's even safer, since it can't possibly block forever. - * - * @see https://sourceware.org/bugzilla/show_bug.cgi?id=12683 + * @return 0 on success, or errno on error + * @raise ESRCH if thread isn't alive */ int pthread_cancel(pthread_t thread) { - kprintf("error: pthread_cancel() isn't supported, please see the" - " cosmopolitan libc documentation for further details\n"); - _Exit(1); + int e, rc, tid; + static bool once; + struct PosixThread *pt; + __require_tls(); + if (!once) ListenForSigCancel(), once = true; + pt = (struct PosixThread *)thread; + switch (atomic_load_explicit(&pt->status, memory_order_acquire)) { + case kPosixThreadZombie: + case kPosixThreadTerminated: + return ESRCH; + default: + break; + } + atomic_store_explicit(&pt->cancelled, 1, memory_order_release); + if (thread == __get_tls()->tib_pthread) { + if (!(pt->flags & PT_NOCANCEL) && (pt->flags & PT_ASYNC)) { + pthread_exit(PTHREAD_CANCELED); + } + return 0; + } + if (IsWindows()) return 0; // TODO(jart): Should we do this? + tid = atomic_load_explicit(&pt->tib->tib_tid, memory_order_acquire); + if (tid <= 0) return 0; // TODO(jart): Do we need this? + e = errno; + if (!tkill(tid, SIGCANCEL)) { + return 0; + } else { + rc = errno; + errno = e; + return rc; + } + return 0; +} + +/** + * Creates cancellation point in calling thread. + * + * This function can be used to force `PTHREAD_CANCEL_DEFERRED` threads + * to cancel without needing to invoke an interruptible system call. If + * the calling thread is in the `PTHREAD_CANCEL_DISABLE` then this will + * do nothing. If the calling thread hasn't yet been cancelled, this'll + * do nothing. In `PTHREAD_CANCEL_MASKED` mode, this also does nothing. + * + * @see pthread_testcancel_np() + */ +void pthread_testcancel(void) { + struct PosixThread *pt; + if (!__tls_enabled) return; + pt = (struct PosixThread *)__get_tls()->tib_pthread; + if (pt->flags & PT_NOCANCEL) return; + if ((!(pt->flags & PT_MASKED) || (pt->flags & PT_ASYNC)) && + atomic_load_explicit(&pt->cancelled, memory_order_acquire)) { + pthread_exit(PTHREAD_CANCELED); + } +} + +/** + * Creates cancellation point in calling thread. + * + * This function can be used to force `PTHREAD_CANCEL_DEFERRED` threads + * to cancel without needing to invoke an interruptible system call. If + * the calling thread is in the `PTHREAD_CANCEL_DISABLE` then this will + * do nothing. If the calling thread hasn't yet been cancelled, this'll + * do nothing. If the calling thread uses `PTHREAD_CANCEL_MASKED`, then + * this function returns `ECANCELED` if a cancellation occurred, rather + * than the normal behavior which is to destroy and cleanup the thread. + * Any `ECANCELED` result must not be ignored, because the thread shall + * have cancellations disabled once it occurs. + * + * @return 0 if not cancelled or cancellation is blocked or `ECANCELED` + * in masked mode when the calling thread has been cancelled + */ +int pthread_testcancel_np(void) { + int rc; + struct PosixThread *pt; + if (!__tls_enabled) return 0; + pt = (struct PosixThread *)__get_tls()->tib_pthread; + if (pt->flags & PT_NOCANCEL) return 0; + if (!atomic_load_explicit(&pt->cancelled, memory_order_acquire)) return 0; + if (!(pt->flags & PT_MASKED) || (pt->flags & PT_ASYNC)) { + pthread_exit(PTHREAD_CANCELED); + } else { + pt->flags |= PT_NOCANCEL; + return ECANCELED; + } } diff --git a/libc/thread/pthread_cond_timedwait.c b/libc/thread/pthread_cond_timedwait.c index 77da43c44..03de7b369 100644 --- a/libc/thread/pthread_cond_timedwait.c +++ b/libc/thread/pthread_cond_timedwait.c @@ -43,6 +43,7 @@ * @raise EINVAL if `0 ≤ abstime->tv_nsec < 1000000000` wasn't the case * @see pthread_cond_broadcast * @see pthread_cond_signal + * @cancellationpoint */ errno_t pthread_cond_timedwait(pthread_cond_t *cond, pthread_mutex_t *mutex, const struct timespec *abstime) { diff --git a/libc/thread/pthread_cond_wait.c b/libc/thread/pthread_cond_wait.c index 260a4ce20..6606f7787 100644 --- a/libc/thread/pthread_cond_wait.c +++ b/libc/thread/pthread_cond_wait.c @@ -36,6 +36,7 @@ * @see pthread_cond_timedwait * @see pthread_cond_broadcast * @see pthread_cond_signal + * @cancellationpoint */ errno_t pthread_cond_wait(pthread_cond_t *cond, pthread_mutex_t *mutex) { return pthread_cond_timedwait(cond, mutex, 0); diff --git a/libc/thread/pthread_create.c b/libc/thread/pthread_create.c index 408a793ee..af8396466 100644 --- a/libc/thread/pthread_create.c +++ b/libc/thread/pthread_create.c @@ -98,7 +98,7 @@ static int PosixThread(void *arg, int tid) { if (!setjmp(pt->exiter)) { __get_tls()->tib_pthread = (pthread_t)pt; _sigsetmask(pt->sigmask); - pt->rc = pt->start_routine(pt->arg); + pt->rc = pt->start(pt->arg); // ensure pthread_cleanup_pop(), and pthread_exit() popped cleanup _npassert(!pt->cleanup); } @@ -150,7 +150,7 @@ static errno_t pthread_create_impl(pthread_t *thread, errno = e; return EAGAIN; } - pt->start_routine = start_routine; + pt->start = start_routine; pt->arg = arg; // create thread local storage memory diff --git a/libc/thread/pthread_join.c b/libc/thread/pthread_join.c index c5b7389a2..082854970 100644 --- a/libc/thread/pthread_join.c +++ b/libc/thread/pthread_join.c @@ -25,9 +25,12 @@ * Waits for thread to terminate. * * @param value_ptr if non-null will receive pthread_exit() argument + * if the thread called pthread_exit(), or `PTHREAD_CANCELED` if + * pthread_cancel() destroyed the thread instead * @return 0 on success, or errno with error * @raise EDEADLK if `thread` is the current thread * @raise EINVAL if `thread` is detached + * @cancellationpoint * @returnserrno * @threadsafe */ diff --git a/libc/thread/pthread_setcancelstate.c b/libc/thread/pthread_setcancelstate.c index ddb2c66aa..7889c07a2 100644 --- a/libc/thread/pthread_setcancelstate.c +++ b/libc/thread/pthread_setcancelstate.c @@ -24,22 +24,47 @@ /** * Sets cancelability state. * + * This function may be used to temporarily disable cancellation for the + * calling thread, which is necessary in cases when a @cancellationpoint + * function is invoked from an @asyncsignalsafe function. + * + * Cosmopolitan Libc supports the Musl Libc `PTHREAD_CANCEL_MASKED` + * non-POSIX extension. Any thread may use this setting, in which case + * the thread won't be abruptly destroyed upon a cancellation and have + * its stack unwound; instead, the thread will encounter an `ECANCELED` + * errno the next time it calls a cancellation point. + * * @param state may be one of: * - `PTHREAD_CANCEL_ENABLE` (default) * - `PTHREAD_CANCEL_DISABLE` + * - `PTHREAD_CANCEL_MASKED` * @param oldstate optionally receives old value * @return 0 on success, or errno on error * @raise EINVAL if `state` has bad value - * @see pthread_cancel() for docs + * @asyncsignalsafe */ int pthread_setcancelstate(int state, int *oldstate) { struct PosixThread *pt; switch (state) { case PTHREAD_CANCEL_ENABLE: case PTHREAD_CANCEL_DISABLE: + case PTHREAD_CANCEL_MASKED: pt = (struct PosixThread *)__get_tls()->tib_pthread; - if (oldstate) *oldstate = pt->canceldisable; - pt->canceldisable = state; + if (oldstate) { + if (pt->flags & PT_NOCANCEL) { + *oldstate = PTHREAD_CANCEL_DISABLE; + } else if (pt->flags & PT_MASKED) { + *oldstate = PTHREAD_CANCEL_MASKED; + } else { + *oldstate = PTHREAD_CANCEL_ENABLE; + } + } + pt->flags &= ~(PT_NOCANCEL | PT_MASKED); + if (state == PTHREAD_CANCEL_MASKED) { + pt->flags |= PT_MASKED; + } else if (state == PTHREAD_CANCEL_DISABLE) { + pt->flags |= PT_NOCANCEL; + } return 0; default: return EINVAL; diff --git a/libc/thread/pthread_setcanceltype.c b/libc/thread/pthread_setcanceltype.c index d95d3bb81..65c7d7f2a 100644 --- a/libc/thread/pthread_setcanceltype.c +++ b/libc/thread/pthread_setcanceltype.c @@ -26,7 +26,7 @@ * * @param type may be one of: * - `PTHREAD_CANCEL_DEFERRED` (default) - * - `PTHREAD_CANCEL_ASYNCHRONOUS` + * - `PTHREAD_CANCEL_ASYNCHRONOUS` (cray cray) * @param oldtype optionally receives old value * @return 0 on success, or errno on error * @raise EINVAL if `type` has bad value @@ -38,8 +38,18 @@ int pthread_setcanceltype(int type, int *oldtype) { case PTHREAD_CANCEL_DEFERRED: case PTHREAD_CANCEL_ASYNCHRONOUS: pt = (struct PosixThread *)__get_tls()->tib_pthread; - if (oldtype) *oldtype = pt->cancelasync; - pt->cancelasync = type; + if (oldtype) { + if (pt->flags & PT_ASYNC) { + *oldtype = PTHREAD_CANCEL_ASYNCHRONOUS; + } else { + *oldtype = PTHREAD_CANCEL_DEFERRED; + } + } + if (type == PTHREAD_CANCEL_DEFERRED) { + pt->flags &= ~PT_ASYNC; + } else { + pt->flags |= PT_ASYNC; + } return 0; default: return EINVAL; diff --git a/libc/thread/sem_timedwait.c b/libc/thread/sem_timedwait.c index bdcb9a46a..dd098c044 100644 --- a/libc/thread/sem_timedwait.c +++ b/libc/thread/sem_timedwait.c @@ -60,6 +60,7 @@ static struct timespec *sem_timeout(struct timespec *memory, * @raise EDEADLK if deadlock was detected * @raise ETIMEDOUT if deadline expired * @raise EINVAL if `sem` is invalid + * @cancellationpoint */ int sem_timedwait(sem_t *sem, const struct timespec *abstime) { int e, i, v, rc; diff --git a/libc/thread/sem_wait.c b/libc/thread/sem_wait.c index 5aabfa571..e32b41ed3 100644 --- a/libc/thread/sem_wait.c +++ b/libc/thread/sem_wait.c @@ -25,6 +25,7 @@ * @raise EINTR if signal was delivered instead * @raise EDEADLK if deadlock was detected * @raise EINVAL if `sem` is invalid + * @cancellationpoint */ int sem_wait(sem_t *sem) { return sem_timedwait(sem, 0); diff --git a/libc/thread/thread.h b/libc/thread/thread.h index b38171bbc..b3f70496b 100644 --- a/libc/thread/thread.h +++ b/libc/thread/thread.h @@ -27,6 +27,7 @@ #define PTHREAD_CANCEL_ENABLE 0 #define PTHREAD_CANCEL_DISABLE 1 +#define PTHREAD_CANCEL_MASKED 2 #define PTHREAD_CANCEL_DEFERRED 0 #define PTHREAD_CANCEL_ASYNCHRONOUS 1 @@ -109,6 +110,8 @@ int pthread_create(pthread_t *, const pthread_attr_t *, void *(*)(void *), void *); int pthread_yield(void); +void pthread_testcancel(void); +int pthread_testcancel_np(void); void pthread_exit(void *) wontreturn; pthread_t pthread_self(void) pureconst; pthread_id_np_t pthread_getthreadid_np(void); diff --git a/libc/thread/thread.mk b/libc/thread/thread.mk index ce9740284..704c99e19 100644 --- a/libc/thread/thread.mk +++ b/libc/thread/thread.mk @@ -50,11 +50,6 @@ $(LIBC_THREAD_A).pkg: \ $(LIBC_THREAD_A_OBJS) \ $(foreach x,$(LIBC_THREAD_A_DIRECTDEPS),$($(x)_A).pkg) -$(LIBC_THREAD_A_OBJS): private \ - OVERRIDE_CCFLAGS += \ - -ffunction-sections \ - -fdata-sections - LIBC_THREAD_LIBS = $(foreach x,$(LIBC_THREAD_ARTIFACTS),$($(x))) LIBC_THREAD_SRCS = $(foreach x,$(LIBC_THREAD_ARTIFACTS),$($(x)_SRCS)) LIBC_THREAD_HDRS = $(foreach x,$(LIBC_THREAD_ARTIFACTS),$($(x)_HDRS)) diff --git a/libc/zipos/open.c b/libc/zipos/open.c index 097b4eb3f..fa7d2ef29 100644 --- a/libc/zipos/open.c +++ b/libc/zipos/open.c @@ -30,6 +30,7 @@ #include "libc/intrin/cmpxchg.h" #include "libc/intrin/directmap.internal.h" #include "libc/intrin/extend.internal.h" +#include "libc/intrin/weaken.h" #include "libc/nexgen32e/crc32.h" #include "libc/runtime/internal.h" #include "libc/runtime/memtrack.internal.h" @@ -40,6 +41,7 @@ #include "libc/sysv/consts/prot.h" #include "libc/sysv/consts/sig.h" #include "libc/sysv/errfuns.h" +#include "libc/thread/thread.h" #include "libc/zip.h" #include "libc/zipos/zipos.internal.h" @@ -188,6 +190,7 @@ static int __zipos_load(struct Zipos *zipos, size_t cf, unsigned flags, * Loads compressed file from αcτµαlly pδrταblε εxεcµταblε object store. * * @param uri is obtained via __zipos_parseuri() + * @cancellationpoint * @asyncsignalsafe * @threadsafe */ @@ -195,6 +198,11 @@ int __zipos_open(const struct ZiposUri *name, unsigned flags, int mode) { int rc; ssize_t cf; struct Zipos *zipos; + if (_weaken(pthread_testcancel_np) && + (rc = _weaken(pthread_testcancel_np)())) { + errno = rc; + return -1; + } BLOCK_SIGNALS; if ((flags & O_ACCMODE) == O_RDONLY) { if ((zipos = __zipos_get())) { diff --git a/test/libc/calls/sigaction_test.c b/test/libc/calls/sigaction_test.c index 6157d0cbb..86806b071 100644 --- a/test/libc/calls/sigaction_test.c +++ b/test/libc/calls/sigaction_test.c @@ -21,6 +21,7 @@ #include "libc/calls/struct/sigaction.h" #include "libc/calls/struct/siginfo.h" #include "libc/calls/struct/sigset.h" +#include "libc/calls/struct/sigset.internal.h" #include "libc/calls/syscall_support-sysv.internal.h" #include "libc/calls/ucontext.h" #include "libc/dce.h" @@ -28,6 +29,7 @@ #include "libc/nexgen32e/nexgen32e.h" #include "libc/runtime/internal.h" #include "libc/runtime/runtime.h" +#include "libc/str/str.h" #include "libc/sysv/consts/sa.h" #include "libc/sysv/consts/sig.h" #include "libc/sysv/consts/uc.h" @@ -211,3 +213,29 @@ TEST(sigaction, enosys_returnsErrnoRatherThanSigsysByDefault) { if (IsOpenbsd()) return; // TODO: Why does OpenBSD raise SIGABRT? ASSERT_SYS(ENOSYS, -1, sys_bogus()); } + +sig_atomic_t gotusr1; + +void OnSigMask(int sig, struct siginfo *si, void *ctx) { + ucontext_t *uc = ctx; + sigaddset(&uc->uc_sigmask, sig); + gotusr1 = true; +} + +TEST(uc_sigmask, signalHandlerCanChangeSignalMaskOfTrappedThread) { + if (IsWindows()) return; // TODO(jart): uc_sigmask support on windows + sigset_t want, got; + struct sigaction oldsa; + struct sigaction sa = {.sa_sigaction = OnSigMask, .sa_flags = SA_SIGINFO}; + sigemptyset(&want); + ASSERT_SYS(0, 0, sigprocmask(SIG_SETMASK, &want, 0)); + ASSERT_SYS(0, 0, sigaction(SIGUSR1, &sa, &oldsa)); + ASSERT_SYS(0, 0, raise(SIGUSR1)); + ASSERT_TRUE(gotusr1); + ASSERT_SYS(0, 0, sigprocmask(SIG_SETMASK, 0, &got)); + sigaddset(&want, SIGUSR1); + ASSERT_STREQ(DescribeSigset(0, &want), DescribeSigset(0, &got)); + ASSERT_SYS(0, 0, sigaction(SIGUSR1, &oldsa, 0)); + sigdelset(&want, SIGUSR1); + ASSERT_SYS(0, 0, sigprocmask(SIG_SETMASK, &want, 0)); +} diff --git a/test/libc/intrin/describesigset_test.c b/test/libc/intrin/describesigset_test.c index 66c35a302..567734487 100644 --- a/test/libc/intrin/describesigset_test.c +++ b/test/libc/intrin/describesigset_test.c @@ -26,7 +26,11 @@ TEST(DescribeSigset, full) { sigset_t ss; sigfillset(&ss); - EXPECT_STREQ("~{ABRT,KILL,STOP}", DescribeSigset(0, &ss)); + if (IsXnu() || IsOpenbsd()) { + EXPECT_STREQ("~{ABRT,CANCEL,KILL,STOP}", DescribeSigset(0, &ss)); + } else { + EXPECT_STREQ("~{ABRT,KILL,STOP,CANCEL}", DescribeSigset(0, &ss)); + } } TEST(DescribeSigset, present) { @@ -42,9 +46,11 @@ TEST(DescribeSigset, absent) { sigfillset(&ss); sigdelset(&ss, SIGINT); sigdelset(&ss, SIGUSR1); - if (IsBsd()) { - EXPECT_STREQ("~{INT,ABRT,KILL,STOP,USR1}", DescribeSigset(0, &ss)); + if (IsOpenbsd() || IsXnu()) { + EXPECT_STREQ("~{INT,ABRT,CANCEL,KILL,STOP,USR1}", DescribeSigset(0, &ss)); + } else if (IsFreebsd() || IsNetbsd()) { + EXPECT_STREQ("~{INT,ABRT,KILL,STOP,USR1,CANCEL}", DescribeSigset(0, &ss)); } else { - EXPECT_STREQ("~{INT,ABRT,KILL,USR1,STOP}", DescribeSigset(0, &ss)); + EXPECT_STREQ("~{INT,ABRT,KILL,USR1,STOP,CANCEL}", DescribeSigset(0, &ss)); } } diff --git a/test/libc/intrin/strsignal_r_test.c b/test/libc/intrin/strsignal_r_test.c index e4c4a2cd1..e0636cdb0 100644 --- a/test/libc/intrin/strsignal_r_test.c +++ b/test/libc/intrin/strsignal_r_test.c @@ -34,6 +34,5 @@ TEST(strsignal, test) { TEST(strsignal, realtime) { if (!SIGRTMIN) return; - ASSERT_STREQ("SIGRTMIN", strsignal(SIGRTMIN)); ASSERT_STREQ("SIGRTMIN+1", strsignal(SIGRTMIN + 1)); } diff --git a/test/libc/thread/pthread_cancel_test.c b/test/libc/thread/pthread_cancel_test.c new file mode 100644 index 000000000..16eb3e0bf --- /dev/null +++ b/test/libc/thread/pthread_cancel_test.c @@ -0,0 +1,111 @@ +/*-*- 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/atomic.h" +#include "libc/calls/blocksigs.internal.h" +#include "libc/calls/calls.h" +#include "libc/dce.h" +#include "libc/errno.h" +#include "libc/runtime/runtime.h" +#include "libc/testlib/testlib.h" +#include "libc/thread/thread.h" + +int pfds[2]; +atomic_bool gotcleanup; +char testlib_enable_tmp_setup_teardown; + +void SetUp(void) { + gotcleanup = false; +} + +void OnCleanup(void *arg) { + gotcleanup = true; +} + +void *Worker(void *arg) { + int n; + char buf[8]; + pthread_cleanup_push(OnCleanup, 0); + read(pfds[0], buf, sizeof(buf)); + pthread_cleanup_pop(0); + return 0; +} + +TEST(pthread_cancel, synchronous) { + void *rc; + pthread_t th; + ASSERT_SYS(0, 0, pipe(pfds)); + ASSERT_EQ(0, pthread_create(&th, 0, Worker, 0)); + ASSERT_EQ(0, pthread_cancel(th)); + ASSERT_EQ(0, pthread_join(th, &rc)); + ASSERT_EQ(PTHREAD_CANCELED, rc); + ASSERT_TRUE(gotcleanup); + ASSERT_SYS(0, 0, close(pfds[1])); + ASSERT_SYS(0, 0, close(pfds[0])); +} + +TEST(pthread_cancel, synchronous_delayed) { + void *rc; + pthread_t th; + ASSERT_SYS(0, 0, pipe(pfds)); + ASSERT_EQ(0, pthread_create(&th, 0, Worker, 0)); + usleep(10); + ASSERT_EQ(0, pthread_cancel(th)); + ASSERT_EQ(0, pthread_join(th, &rc)); + ASSERT_EQ(PTHREAD_CANCELED, rc); + ASSERT_TRUE(gotcleanup); + ASSERT_SYS(0, 0, close(pfds[1])); + ASSERT_SYS(0, 0, close(pfds[0])); +} + +void *DisabledWorker(void *arg) { + int n; + char buf[8]; + pthread_setcancelstate(PTHREAD_CANCEL_MASKED, 0); + pthread_cleanup_push(OnCleanup, 0); + ASSERT_SYS(ECANCELED, -1, read(pfds[0], buf, sizeof(buf))); + pthread_cleanup_pop(0); + return 0; +} + +TEST(pthread_cancel, masked) { + void *rc; + pthread_t th; + ASSERT_SYS(0, 0, pipe(pfds)); + ASSERT_EQ(0, pthread_create(&th, 0, DisabledWorker, 0)); + ASSERT_EQ(0, pthread_cancel(th)); + ASSERT_EQ(0, pthread_join(th, &rc)); + ASSERT_EQ(0, rc); + ASSERT_FALSE(gotcleanup); + ASSERT_SYS(0, 0, close(pfds[1])); + ASSERT_SYS(0, 0, close(pfds[0])); +} + +TEST(pthread_cancel, masked_delayed) { + void *rc; + pthread_t th; + ASSERT_SYS(0, 0, pipe(pfds)); + ASSERT_EQ(0, pthread_create(&th, 0, DisabledWorker, 0)); + usleep(10); + ASSERT_EQ(0, pthread_cancel(th)); + ASSERT_EQ(0, pthread_join(th, &rc)); + ASSERT_EQ(0, rc); + ASSERT_FALSE(gotcleanup); + ASSERT_SYS(0, 0, close(pfds[1])); + ASSERT_SYS(0, 0, close(pfds[0])); +} diff --git a/third_party/musl/lockf.c b/third_party/musl/lockf.c index 2e6a26b6e..8d729554e 100644 --- a/third_party/musl/lockf.c +++ b/third_party/musl/lockf.c @@ -39,6 +39,11 @@ Copyright 2005-2014 Rich Felker, et. al.\""); asm(".include \"libc/disclaimer.inc\""); // clang-format off +/** + * Locks file. + * + * @cancellationpoint when `op` is `F_LOCK` + */ int lockf(int fd, int op, off_t size) { struct flock l = { diff --git a/third_party/nsync/futex.c b/third_party/nsync/futex.c index 377402b97..8f5c5c0b0 100644 --- a/third_party/nsync/futex.c +++ b/third_party/nsync/futex.c @@ -152,7 +152,7 @@ static int nsync_futex_polyfill_ (atomic_int *w, int expect, struct timespec *ti int nsync_futex_wait_ (atomic_int *w, int expect, char pshare, struct timespec *timeout) { uint32_t ms; - int rc, op, fop; + int e, rc, op, fop; op = FUTEX_WAIT_; if (pshare == PTHREAD_PROCESS_PRIVATE) { @@ -170,8 +170,10 @@ int nsync_futex_wait_ (atomic_int *w, int expect, char pshare, struct timespec * if (pshare) { goto Polyfill; } + e = errno; if (_check_interrupts (false, 0)) { - rc = -EINTR; + rc = -errno; + errno = e; } else { if (timeout) { ms = _timespec_tomillis (*timeout);