mirror of
https://github.com/jart/cosmopolitan.git
synced 2025-07-26 20:40:28 +00:00
Implement support for POSIX thread cancellations
This change makes some miracle modifications to the System Five system call support, which lets us have safe, correct, and atomic handling of thread cancellations. It all turned out to be cheaper than anticipated because it wasn't necessary to modify the system call veneers. We were able to encode the cancellability of each system call into the magnums found in libc/sysv/syscalls.sh. Since cancellations are so waq, we are also supporting a lovely Musl Libc mask feature for raising ECANCELED.
This commit is contained in:
parent
37d40e087f
commit
2278327eba
145 changed files with 715 additions and 265 deletions
|
@ -204,6 +204,7 @@ textwindows int __sig_raise(int sig, int si_code) {
|
|||
if (1 <= sig && sig <= 64) {
|
||||
if (!__sig_is_masked(sig)) {
|
||||
++__sig_count;
|
||||
// TODO(jart): ucontext_t support
|
||||
__sig_handle(false, sig, si_code, 0);
|
||||
return 0;
|
||||
} else {
|
||||
|
|
|
@ -34,7 +34,7 @@ textwindows int sys_clock_nanosleep_nt(int clock, int flags,
|
|||
for (;;) {
|
||||
if (sys_clock_gettime_nt(clock, &now)) return -1;
|
||||
if (_timespec_gte(now, abs)) return 0;
|
||||
if (_check_interrupts(false, g_fds.p)) return eintr();
|
||||
if (_check_interrupts(false, g_fds.p)) return -1;
|
||||
SleepEx(MIN(__SIG_POLLING_INTERVAL_MS,
|
||||
_timespec_tomillis(_timespec_sub(abs, now))),
|
||||
false);
|
||||
|
@ -47,7 +47,7 @@ textwindows int sys_clock_nanosleep_nt(int clock, int flags,
|
|||
if (_timespec_gte(now, abs)) return 0;
|
||||
if (_check_interrupts(false, g_fds.p)) {
|
||||
if (rem) *rem = _timespec_sub(abs, now);
|
||||
return eintr();
|
||||
return -1;
|
||||
}
|
||||
SleepEx(MIN(__SIG_POLLING_INTERVAL_MS,
|
||||
_timespec_tomillis(_timespec_sub(abs, now))),
|
||||
|
|
|
@ -80,6 +80,7 @@
|
|||
* @raise EINVAL if `flags` has an unrecognized value
|
||||
* @raise EINVAL if `req->tv_nsec ∉ [0,1000000000)`
|
||||
* @raise ENOSYS on bare metal
|
||||
* @cancellationpoint
|
||||
* @returnserrno
|
||||
* @norestart
|
||||
*/
|
||||
|
|
|
@ -26,7 +26,7 @@
|
|||
#include "libc/sysv/consts/o.h"
|
||||
#include "libc/sysv/errfuns.h"
|
||||
|
||||
int sys_fcntl(int fd, int cmd, uintptr_t arg) {
|
||||
int sys_fcntl(int fd, int cmd, uintptr_t arg, int impl(int, int, ...)) {
|
||||
int e, rc;
|
||||
bool islock;
|
||||
if ((islock = cmd == F_GETLK || //
|
||||
|
@ -40,12 +40,12 @@ int sys_fcntl(int fd, int cmd, uintptr_t arg) {
|
|||
cosmo2flock(arg);
|
||||
}
|
||||
e = errno;
|
||||
rc = __sys_fcntl(fd, cmd, arg);
|
||||
rc = impl(fd, cmd, arg);
|
||||
if (islock) {
|
||||
flock2cosmo(arg);
|
||||
} else if (rc == -1 && cmd == F_DUPFD_CLOEXEC && errno == EINVAL) {
|
||||
errno = e;
|
||||
rc = __fixupnewfd(__sys_fcntl(fd, F_DUPFD, arg), O_CLOEXEC);
|
||||
rc = __fixupnewfd(impl(fd, F_DUPFD, arg), O_CLOEXEC);
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
|
|
|
@ -94,6 +94,7 @@
|
|||
* @raise EDEADLK if `cmd` was `F_SETLKW` and waiting would deadlock
|
||||
* @raise EMFILE if `cmd` is `F_DUPFD` or `F_DUPFD_CLOEXEC` and
|
||||
* `RLIMIT_NOFILE` would be exceeded
|
||||
* @cancellationpoint when `cmd` is `F_SETLKW`
|
||||
* @asyncsignalsafe
|
||||
* @restartable
|
||||
*/
|
||||
|
@ -111,7 +112,11 @@ int fcntl(int fd, int cmd, ...) {
|
|||
if (fd < g_fds.n && g_fds.p[fd].kind == kFdZip) {
|
||||
rc = _weaken(__zipos_fcntl)(fd, cmd, arg);
|
||||
} else if (!IsWindows()) {
|
||||
rc = sys_fcntl(fd, cmd, arg);
|
||||
if (cmd == F_SETLKW) {
|
||||
rc = sys_fcntl(fd, cmd, arg, __sys_fcntl_cp);
|
||||
} else {
|
||||
rc = sys_fcntl(fd, cmd, arg, __sys_fcntl);
|
||||
}
|
||||
} else {
|
||||
rc = sys_fcntl_nt(fd, cmd, arg);
|
||||
}
|
||||
|
|
|
@ -30,6 +30,7 @@
|
|||
* @return 0 on success, or -1 w/ errno
|
||||
* @see sync(), fsync(), sync_file_range()
|
||||
* @see __nosync to secretly disable
|
||||
* @cancellationpoint
|
||||
* @asyncsignalsafe
|
||||
*/
|
||||
int fdatasync(int fd) {
|
||||
|
|
|
@ -17,10 +17,10 @@
|
|||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/calls/calls.h"
|
||||
#include "libc/intrin/strace.internal.h"
|
||||
#include "libc/calls/syscall-nt.internal.h"
|
||||
#include "libc/calls/syscall-sysv.internal.h"
|
||||
#include "libc/dce.h"
|
||||
#include "libc/intrin/strace.internal.h"
|
||||
|
||||
/**
|
||||
* Acquires lock on file.
|
||||
|
@ -30,6 +30,7 @@
|
|||
* @param op can have LOCK_{SH,EX,NB,UN} for shared, exclusive,
|
||||
* non-blocking, and unlocking
|
||||
* @return 0 on success, or -1 w/ errno
|
||||
* @cancellationpoint
|
||||
* @restartable
|
||||
*/
|
||||
int flock(int fd, int op) {
|
||||
|
|
|
@ -18,16 +18,17 @@
|
|||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/calls/calls.h"
|
||||
#include "libc/calls/internal.h"
|
||||
#include "libc/intrin/strace.internal.h"
|
||||
#include "libc/calls/struct/statfs-meta.internal.h"
|
||||
#include "libc/calls/struct/statfs.internal.h"
|
||||
#include "libc/dce.h"
|
||||
#include "libc/intrin/strace.internal.h"
|
||||
#include "libc/runtime/stack.h"
|
||||
#include "libc/sysv/errfuns.h"
|
||||
|
||||
/**
|
||||
* Returns information about filesystem.
|
||||
* @return 0 on success, or -1 w/ errno
|
||||
* @cancellationpoint
|
||||
*/
|
||||
int fstatfs(int fd, struct statfs *sf) {
|
||||
int rc;
|
||||
|
|
|
@ -30,6 +30,7 @@
|
|||
* @return 0 on success, or -1 w/ errno
|
||||
* @see fdatasync(), sync_file_range()
|
||||
* @see __nosync to secretly disable
|
||||
* @cancellationpoint
|
||||
* @asyncsignalsafe
|
||||
*/
|
||||
int fsync(int fd) {
|
||||
|
|
|
@ -56,7 +56,7 @@
|
|||
* @raise EINVAL if `fd` is a non-file, e.g. pipe, socket
|
||||
* @raise EINVAL if `fd` wasn't opened in a writeable mode
|
||||
* @raise ENOSYS on bare metal
|
||||
* @see truncate()
|
||||
* @cancellationpoint
|
||||
* @asyncsignalsafe
|
||||
* @threadsafe
|
||||
*/
|
||||
|
|
|
@ -43,7 +43,7 @@ forceinline size_t _clampio(size_t size) {
|
|||
}
|
||||
|
||||
int sys_close_nt(struct Fd *, int) hidden;
|
||||
bool _check_interrupts(bool, struct Fd *) hidden;
|
||||
int _check_interrupts(bool, struct Fd *) hidden;
|
||||
int sys_openat_metal(int, const char *, int, unsigned);
|
||||
|
||||
COSMOPOLITAN_C_END_
|
||||
|
|
|
@ -18,24 +18,33 @@
|
|||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/assert.h"
|
||||
#include "libc/calls/calls.h"
|
||||
#include "libc/calls/internal.h"
|
||||
#include "libc/calls/sig.internal.h"
|
||||
#include "libc/calls/state.internal.h"
|
||||
#include "libc/calls/struct/fd.internal.h"
|
||||
#include "libc/calls/struct/sigaction.h"
|
||||
#include "libc/calls/syscall_support-nt.internal.h"
|
||||
#include "libc/dce.h"
|
||||
#include "libc/errno.h"
|
||||
#include "libc/intrin/lockcmpxchgp.h"
|
||||
#include "libc/intrin/strace.internal.h"
|
||||
#include "libc/intrin/weaken.h"
|
||||
#include "libc/sysv/errfuns.h"
|
||||
#include "libc/thread/thread.h"
|
||||
#include "libc/thread/tls.h"
|
||||
|
||||
textwindows bool _check_interrupts(bool restartable, struct Fd *fd) {
|
||||
bool res;
|
||||
textwindows int _check_interrupts(bool restartable, struct Fd *fd) {
|
||||
int rc;
|
||||
if (_weaken(pthread_testcancel_np) &&
|
||||
(rc = _weaken(pthread_testcancel_np)())) {
|
||||
errno = rc;
|
||||
return -1;
|
||||
}
|
||||
if (_weaken(_check_sigalrm)) _weaken(_check_sigalrm)();
|
||||
if (!__tls_enabled || !(__get_tls()->tib_flags & TIB_FLAG_TIME_CRITICAL)) {
|
||||
if (_weaken(_check_sigchld)) _weaken(_check_sigchld)();
|
||||
if (fd && _weaken(_check_sigwinch)) _weaken(_check_sigwinch)(fd);
|
||||
}
|
||||
res = _weaken(__sig_check) && _weaken(__sig_check)(restartable);
|
||||
return res;
|
||||
if (_weaken(__sig_check) && _weaken(__sig_check)(restartable)) return eintr();
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -32,6 +32,7 @@
|
|||
* @raise EFAULT if `req` is NULL or `req` / `rem` is a bad pointer
|
||||
* @raise ENOSYS on bare metal
|
||||
* @see clock_nanosleep()
|
||||
* @cancellationpoint
|
||||
* @norestart
|
||||
*/
|
||||
int nanosleep(const struct timespec *req, struct timespec *rem) {
|
||||
|
|
|
@ -21,6 +21,8 @@
|
|||
#include "libc/nt/struct/context.h"
|
||||
#include "libc/str/str.h"
|
||||
|
||||
// TODO(jart): uc_sigmask support
|
||||
|
||||
privileged void _ntcontext2linux(ucontext_t *ctx, const struct NtContext *cr) {
|
||||
if (!cr) return;
|
||||
ctx->uc_mcontext.eflags = cr->EFlags;
|
||||
|
|
|
@ -29,6 +29,7 @@
|
|||
* @param file specifies filesystem path to open
|
||||
* @return file descriptor, or -1 w/ errno
|
||||
* @see openat() for further documentation
|
||||
* @cancellationpoint
|
||||
* @asyncsignalsafe
|
||||
* @restartable
|
||||
* @threadsafe
|
||||
|
|
|
@ -141,6 +141,7 @@
|
|||
* @raise ELOOP if `flags` had `O_NOFOLLOW` and `file` is a symbolic link
|
||||
* @raise ELOOP if a loop was detected resolving components of `file`
|
||||
* @raise EISDIR if writing is requested and `file` names a directory
|
||||
* @cancellationpoint
|
||||
* @asyncsignalsafe
|
||||
* @restartable
|
||||
* @threadsafe
|
||||
|
|
|
@ -18,8 +18,9 @@
|
|||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/calls/internal.h"
|
||||
#include "libc/calls/sig.internal.h"
|
||||
#include "libc/intrin/strace.internal.h"
|
||||
#include "libc/calls/syscall_support-nt.internal.h"
|
||||
#include "libc/errno.h"
|
||||
#include "libc/intrin/strace.internal.h"
|
||||
#include "libc/nt/errors.h"
|
||||
#include "libc/nt/synchronization.h"
|
||||
#include "libc/sysv/errfuns.h"
|
||||
|
@ -31,7 +32,7 @@ textwindows int sys_pause_nt(void) {
|
|||
for (;;) {
|
||||
|
||||
if (_check_interrupts(false, g_fds.p)) {
|
||||
return eintr();
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (SleepEx(__SIG_POLLING_INTERVAL_MS, true) == kNtWaitIoCompletion) {
|
||||
|
|
|
@ -17,9 +17,9 @@
|
|||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/calls/calls.h"
|
||||
#include "libc/intrin/strace.internal.h"
|
||||
#include "libc/calls/syscall_support-nt.internal.h"
|
||||
#include "libc/dce.h"
|
||||
#include "libc/intrin/strace.internal.h"
|
||||
#include "libc/sock/internal.h"
|
||||
|
||||
/**
|
||||
|
@ -37,6 +37,7 @@
|
|||
* However this has a tinier footprint and better logging.
|
||||
*
|
||||
* @return -1 w/ errno set to EINTR
|
||||
* @cancellationpoint
|
||||
* @see sigsuspend()
|
||||
* @norestart
|
||||
*/
|
||||
|
|
|
@ -21,7 +21,6 @@
|
|||
#include "libc/calls/sig.internal.h"
|
||||
#include "libc/calls/state.internal.h"
|
||||
#include "libc/calls/struct/sigaction.h"
|
||||
#include "libc/errno.h"
|
||||
#include "libc/intrin/bits.h"
|
||||
#include "libc/intrin/strace.internal.h"
|
||||
#include "libc/macros.internal.h"
|
||||
|
@ -64,8 +63,7 @@ textwindows int sys_poll_nt(struct pollfd *fds, uint64_t nfds, uint64_t *ms,
|
|||
if (sigmask) {
|
||||
__sig_mask(SIG_SETMASK, sigmask, &oldmask);
|
||||
}
|
||||
if (_check_interrupts(false, g_fds.p)) {
|
||||
rc = eintr();
|
||||
if ((rc = _check_interrupts(false, g_fds.p))) {
|
||||
goto ReturnPath;
|
||||
}
|
||||
|
||||
|
@ -190,8 +188,7 @@ textwindows int sys_poll_nt(struct pollfd *fds, uint64_t nfds, uint64_t *ms,
|
|||
}
|
||||
// otherwise loop limitlessly for timeout to elapse while
|
||||
// checking for signal delivery interrupts, along the way
|
||||
if (_check_interrupts(false, g_fds.p)) {
|
||||
rc = eintr();
|
||||
if ((rc = _check_interrupts(false, g_fds.p))) {
|
||||
goto ReturnPath;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -55,6 +55,7 @@
|
|||
* @return fds[𝑖].revents is always zero initializaed and then will
|
||||
* be populated with POLL{IN,OUT,PRI,HUP,ERR,NVAL} if something
|
||||
* was determined about the file descriptor
|
||||
* @cancellationpoint
|
||||
* @asyncsignalsafe
|
||||
* @threadsafe
|
||||
* @norestart
|
||||
|
|
|
@ -50,6 +50,7 @@
|
|||
*
|
||||
* @param timeout if null will block indefinitely
|
||||
* @param sigmask may be null in which case no mask change happens
|
||||
* @cancellationpoint
|
||||
* @asyncsignalsafe
|
||||
* @threadsafe
|
||||
* @norestart
|
||||
|
|
|
@ -48,6 +48,7 @@
|
|||
* @raise EIO if a complicated i/o error happened
|
||||
* @raise EINTR if signal was delivered instead
|
||||
* @see pwrite(), write()
|
||||
* @cancellationpoint
|
||||
* @asyncsignalsafe
|
||||
* @threadsafe
|
||||
* @vforksafe
|
||||
|
|
|
@ -108,6 +108,7 @@ static ssize_t Preadv(int fd, struct iovec *iov, int iovlen, int64_t off) {
|
|||
* Reads with maximum generality.
|
||||
*
|
||||
* @return number of bytes actually read, or -1 w/ errno
|
||||
* @cancellationpoint
|
||||
* @asyncsignalsafe
|
||||
* @vforksafe
|
||||
*/
|
||||
|
|
|
@ -42,6 +42,7 @@
|
|||
* @return [1..size] bytes on success, or -1 w/ errno; noting zero is
|
||||
* impossible unless size was passed as zero to do an error check
|
||||
* @see pread(), write()
|
||||
* @cancellationpoint
|
||||
* @asyncsignalsafe
|
||||
* @threadsafe
|
||||
* @vforksafe
|
||||
|
|
|
@ -114,6 +114,7 @@ static ssize_t Pwritev(int fd, const struct iovec *iov, int iovlen,
|
|||
* call using pwrite().
|
||||
*
|
||||
* @return number of bytes actually sent, or -1 w/ errno
|
||||
* @cancellationpoint
|
||||
* @asyncsignalsafe
|
||||
* @vforksafe
|
||||
*/
|
||||
|
|
|
@ -53,7 +53,7 @@ static textwindows ssize_t sys_read_nt_impl(struct Fd *fd, void *data,
|
|||
}
|
||||
if (_check_interrupts(true, g_fds.p)) {
|
||||
POLLTRACE("sys_read_nt interrupted");
|
||||
return eintr();
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
POLLTRACE("sys_read_nt ready to read");
|
||||
|
@ -94,7 +94,7 @@ textwindows ssize_t sys_read_nt(struct Fd *fd, const struct iovec *iov,
|
|||
uint32_t size;
|
||||
size_t i, total;
|
||||
if (opt_offset < -1) return einval();
|
||||
if (_check_interrupts(true, fd)) return eintr();
|
||||
if (_check_interrupts(true, fd)) return -1;
|
||||
while (iovlen && !iov[0].iov_len) iov++, iovlen--;
|
||||
if (iovlen) {
|
||||
for (total = i = 0; i < iovlen; ++i) {
|
||||
|
|
|
@ -56,6 +56,7 @@
|
|||
* or `SO_RCVTIMEO` is in play and the time interval elapsed
|
||||
* @raise ENOBUFS is specified by POSIX
|
||||
* @raise ENXIO is specified by POSIX
|
||||
* @cancellationpoint
|
||||
* @asyncsignalsafe
|
||||
* @restartable
|
||||
* @vforksafe
|
||||
|
|
|
@ -43,6 +43,7 @@
|
|||
* performance boost in the case of a single small iovec.
|
||||
*
|
||||
* @return number of bytes actually read, or -1 w/ errno
|
||||
* @cancellationpoint
|
||||
* @restartable
|
||||
*/
|
||||
ssize_t readv(int fd, const struct iovec *iov, int iovlen) {
|
||||
|
|
|
@ -17,15 +17,10 @@
|
|||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/calls/struct/sigset.h"
|
||||
#include "libc/str/str.h"
|
||||
|
||||
/**
|
||||
* Blocks all signals without strace logging.
|
||||
*
|
||||
* @param neu is new signal mask for process
|
||||
* @return old signal mask
|
||||
*/
|
||||
sigset_t _sigblockall(void) {
|
||||
sigset_t ss;
|
||||
sigfillset(&ss);
|
||||
memset(&ss, -1, sizeof(ss));
|
||||
return _sigsetmask(ss);
|
||||
}
|
||||
|
|
|
@ -75,6 +75,11 @@ privileged void __sigenter_netbsd(int sig, struct siginfo_netbsd *si,
|
|||
uc.uc_mcontext.rsp = ctx->uc_mcontext.rsp;
|
||||
*uc.uc_mcontext.fpregs = ctx->uc_mcontext.__fpregs;
|
||||
((sigaction_f)(_base + rva))(sig, &si2, &uc);
|
||||
ctx->uc_stack.ss_sp = uc.uc_stack.ss_sp;
|
||||
ctx->uc_stack.ss_size = uc.uc_stack.ss_size;
|
||||
ctx->uc_stack.ss_flags = uc.uc_stack.ss_flags;
|
||||
__repmovsb(&ctx->uc_sigmask, &uc.uc_sigmask,
|
||||
MIN(sizeof(uc.uc_sigmask), sizeof(ctx->uc_sigmask)));
|
||||
ctx->uc_mcontext.rdi = uc.uc_mcontext.rdi;
|
||||
ctx->uc_mcontext.rsi = uc.uc_mcontext.rsi;
|
||||
ctx->uc_mcontext.rdx = uc.uc_mcontext.rdx;
|
||||
|
|
|
@ -76,6 +76,7 @@ privileged void __sigenter_openbsd(int sig, struct siginfo_openbsd *openbsdinfo,
|
|||
*g.uc.uc_mcontext.fpregs = *ctx->sc_fpstate;
|
||||
}
|
||||
((sigaction_f)(_base + rva))(sig, &g.si, &g.uc);
|
||||
ctx->sc_mask = g.uc.uc_sigmask.__bits[0];
|
||||
ctx->sc_rdi = g.uc.uc_mcontext.rdi;
|
||||
ctx->sc_rsi = g.uc.uc_mcontext.rsi;
|
||||
ctx->sc_rdx = g.uc.uc_mcontext.rdx;
|
||||
|
|
|
@ -501,6 +501,7 @@ privileged void __sigenter_xnu(void *fn, int infostyle, int sig,
|
|||
xnuctx->uc_stack.ss_sp = g.uc.uc_stack.ss_sp;
|
||||
xnuctx->uc_stack.ss_flags = g.uc.uc_stack.ss_flags;
|
||||
xnuctx->uc_stack.ss_size = g.uc.uc_stack.ss_size;
|
||||
xnuctx->uc_sigmask = g.uc.uc_sigmask.__bits[0];
|
||||
if (xnuctx->uc_mcontext) {
|
||||
if (xnuctx->uc_mcsize >=
|
||||
sizeof(struct __darwin_x86_exception_state64)) {
|
||||
|
|
|
@ -26,6 +26,7 @@
|
|||
#include "libc/intrin/asan.internal.h"
|
||||
#include "libc/intrin/describeflags.internal.h"
|
||||
#include "libc/intrin/strace.internal.h"
|
||||
#include "libc/intrin/weaken.h"
|
||||
#include "libc/str/str.h"
|
||||
#include "libc/sysv/consts/sig.h"
|
||||
#include "libc/sysv/errfuns.h"
|
||||
|
@ -59,7 +60,9 @@ int sigprocmask(int how, const sigset_t *opt_set, sigset_t *opt_out_oldset) {
|
|||
rc = efault();
|
||||
} else if (IsMetal() || IsWindows()) {
|
||||
rc = __sig_mask(how, opt_set, &old);
|
||||
_check_interrupts(false, 0);
|
||||
if (_weaken(__sig_check)) {
|
||||
_weaken(__sig_check)(true);
|
||||
}
|
||||
} else {
|
||||
rc = sys_sigprocmask(how, opt_set, opt_out_oldset ? &old : 0);
|
||||
}
|
||||
|
|
|
@ -23,12 +23,6 @@
|
|||
#include "libc/dce.h"
|
||||
#include "libc/sysv/consts/sig.h"
|
||||
|
||||
/**
|
||||
* Sets signal mask without strace logging.
|
||||
*
|
||||
* @param neu is new signal mask for process
|
||||
* @return old signal mask
|
||||
*/
|
||||
sigset_t _sigsetmask(sigset_t neu) {
|
||||
sigset_t res;
|
||||
if (IsMetal() || IsWindows()) {
|
||||
|
|
|
@ -40,6 +40,7 @@
|
|||
* @param ignore is a bitset of signals to block temporarily, which if
|
||||
* NULL is equivalent to passing an empty signal set
|
||||
* @return -1 w/ EINTR (or possibly EFAULT)
|
||||
* @cancellationpoint
|
||||
* @asyncsignalsafe
|
||||
* @norestart
|
||||
*/
|
||||
|
@ -72,8 +73,7 @@ int sigsuspend(const sigset_t *ignore) {
|
|||
ms = 0;
|
||||
totoms = 0;
|
||||
do {
|
||||
if (_check_interrupts(false, g_fds.p)) {
|
||||
rc = eintr();
|
||||
if ((rc = _check_interrupts(false, g_fds.p))) {
|
||||
break;
|
||||
}
|
||||
if (SleepEx(__SIG_POLLING_INTERVAL_MS, true) == kNtWaitIoCompletion) {
|
||||
|
|
|
@ -40,6 +40,7 @@
|
|||
* @raise EAGAIN if deadline expired
|
||||
* @raise ENOSYS on Windows, XNU, OpenBSD, Metal
|
||||
* @raise EFAULT if invalid memory was supplied
|
||||
* @cancellationpoint
|
||||
*/
|
||||
int sigtimedwait(const sigset_t *set, siginfo_t *info,
|
||||
const struct timespec *timeout) {
|
||||
|
|
|
@ -27,6 +27,7 @@
|
|||
* @raise EINTR if an asynchronous signal was delivered instead
|
||||
* @raise ENOSYS on OpenBSD, XNU, and Windows
|
||||
* @see sigtimedwait()
|
||||
* @cancellationpoint
|
||||
*/
|
||||
int sigwaitinfo(const sigset_t *mask, siginfo_t *si) {
|
||||
return sigtimedwait(mask, si, 0);
|
||||
|
|
|
@ -29,6 +29,7 @@
|
|||
* this function shall return the number of unslept seconds rounded
|
||||
* using the ceiling function
|
||||
* @see clock_nanosleep()
|
||||
* @cancellationpoint
|
||||
* @asyncsignalsafe
|
||||
* @norestart
|
||||
*/
|
||||
|
|
|
@ -18,17 +18,18 @@
|
|||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/calls/calls.h"
|
||||
#include "libc/calls/state.internal.h"
|
||||
#include "libc/intrin/strace.internal.h"
|
||||
#include "libc/calls/struct/statfs-meta.internal.h"
|
||||
#include "libc/calls/struct/statfs.internal.h"
|
||||
#include "libc/calls/syscall_support-nt.internal.h"
|
||||
#include "libc/dce.h"
|
||||
#include "libc/intrin/strace.internal.h"
|
||||
#include "libc/runtime/stack.h"
|
||||
#include "libc/sysv/consts/at.h"
|
||||
|
||||
/**
|
||||
* Returns information about filesystem.
|
||||
* @return 0 on success, or -1 w/ errno
|
||||
* @cancellationpoint
|
||||
*/
|
||||
int statfs(const char *path, struct statfs *sf) {
|
||||
int rc;
|
||||
|
|
|
@ -18,6 +18,7 @@ char *sys_getcwd_xnu(char *, u64) hidden;
|
|||
i32 __sys_dup3(i32, i32, i32) hidden;
|
||||
i32 __sys_execve(const char *, char *const[], char *const[]) hidden;
|
||||
i32 __sys_fcntl(i32, i32, ...) hidden;
|
||||
i32 __sys_fcntl_cp(i32, i32, ...) hidden;
|
||||
i32 __sys_fstat(i32, void *) hidden;
|
||||
i32 __sys_fstatat(i32, const char *, void *, i32) hidden;
|
||||
i32 __sys_gettid(i64 *) hidden;
|
||||
|
@ -43,7 +44,7 @@ i32 sys_fchmod(i32, u32) hidden;
|
|||
i32 sys_fchmodat(i32, const char *, u32, u32) hidden;
|
||||
i32 sys_fchown(i64, u32, u32) hidden;
|
||||
i32 sys_fchownat(i32, const char *, u32, u32, u32) hidden;
|
||||
i32 sys_fcntl(i32, i32, u64) hidden;
|
||||
i32 sys_fcntl(i32, i32, u64, i32 (*)(i32, i32, ...)) hidden;
|
||||
i32 sys_fdatasync(i32) hidden;
|
||||
i32 sys_flock(i32, i32) hidden;
|
||||
i32 sys_fork(void) hidden;
|
||||
|
@ -59,6 +60,7 @@ i32 sys_getresuid(u32 *, u32 *, u32 *) hidden;
|
|||
i32 sys_getsid(i32) hidden;
|
||||
i32 sys_gettid(void) hidden;
|
||||
i32 sys_ioctl(i32, u64, ...) hidden;
|
||||
i32 sys_ioctl_cp(i32, u64, ...) hidden;
|
||||
i32 sys_issetugid(void) hidden;
|
||||
i32 sys_kill(i32, i32, i32) hidden;
|
||||
i32 sys_linkat(i32, const char *, i32, const char *, i32) hidden;
|
||||
|
|
|
@ -40,6 +40,7 @@ static textwindows int sys_tcdrain_nt(int fd) {
|
|||
* @raise EIO if process group of writer is orphoned, calling thread is
|
||||
* not blocking `SIGTTOU`, and process isn't ignoring `SIGTTOU`
|
||||
* @raise ENOSYS on bare metal
|
||||
* @cancellationpoint
|
||||
* @asyncsignalsafe
|
||||
*/
|
||||
int tcdrain(int fd) {
|
||||
|
@ -47,7 +48,7 @@ int tcdrain(int fd) {
|
|||
if (IsMetal()) {
|
||||
rc = enosys();
|
||||
} else if (!IsWindows()) {
|
||||
rc = sys_ioctl(fd, TCSBRK, (void *)(intptr_t)1);
|
||||
rc = sys_ioctl_cp(fd, TCSBRK, (void *)(intptr_t)1);
|
||||
} else {
|
||||
rc = sys_tcdrain_nt(fd);
|
||||
}
|
||||
|
|
|
@ -58,6 +58,7 @@
|
|||
* @raise ETXTBSY if `path` is an executable being executed
|
||||
* @raise EROFS if `path` is on a read-only filesystem
|
||||
* @raise ENOSYS on bare metal
|
||||
* @cancellationpoint
|
||||
* @see ftruncate()
|
||||
* @threadsafe
|
||||
*/
|
||||
|
|
|
@ -27,6 +27,7 @@
|
|||
* @return 0 on success, or -1 w/ errno
|
||||
* @raise EINTR if a signal was delivered while sleeping
|
||||
* @see clock_nanosleep()
|
||||
* @cancellationpoint
|
||||
* @norestart
|
||||
*/
|
||||
int usleep(uint32_t micros) {
|
||||
|
|
|
@ -24,6 +24,7 @@
|
|||
* @param opt_out_wstatus optionally returns status code, and *wstatus
|
||||
* may be inspected using WEEXITSTATUS(), etc.
|
||||
* @return process id of terminated child or -1 w/ errno
|
||||
* @cancellationpoint
|
||||
* @asyncsignalsafe
|
||||
* @restartable
|
||||
* @vforksafe
|
||||
|
|
|
@ -27,6 +27,7 @@
|
|||
* @param options can have WNOHANG, WUNTRACED, WCONTINUED, etc.
|
||||
* @param opt_out_rusage optionally returns accounting data
|
||||
* @return process id of terminated child or -1 w/ errno
|
||||
* @cancellationpoint
|
||||
* @asyncsignalsafe
|
||||
* @restartable
|
||||
*/
|
||||
|
|
|
@ -48,15 +48,15 @@
|
|||
static textwindows int sys_wait4_nt_impl(int pid, int *opt_out_wstatus,
|
||||
int options,
|
||||
struct rusage *opt_out_rusage) {
|
||||
int pids[64];
|
||||
int64_t handle;
|
||||
int rc, pids[64];
|
||||
int64_t handles[64];
|
||||
uint32_t dwExitCode;
|
||||
bool shouldinterrupt;
|
||||
uint32_t i, j, base, count, timeout;
|
||||
struct NtProcessMemoryCountersEx memcount;
|
||||
struct NtFileTime createfiletime, exitfiletime, kernelfiletime, userfiletime;
|
||||
if (_check_interrupts(true, g_fds.p)) return eintr();
|
||||
if (_check_interrupts(true, g_fds.p)) return -1;
|
||||
__fds_lock();
|
||||
if (pid != -1 && pid != 0) {
|
||||
if (pid < 0) {
|
||||
|
@ -94,7 +94,7 @@ static textwindows int sys_wait4_nt_impl(int pid, int *opt_out_wstatus,
|
|||
}
|
||||
__fds_unlock();
|
||||
for (;;) {
|
||||
if (_check_interrupts(true, 0)) return eintr();
|
||||
if (_check_interrupts(true, 0)) return -1;
|
||||
dwExitCode = kNtStillActive;
|
||||
if (options & WNOHANG) {
|
||||
i = WaitForMultipleObjects(count, handles, false, 0);
|
||||
|
|
|
@ -17,11 +17,11 @@
|
|||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/calls/calls.h"
|
||||
#include "libc/intrin/strace.internal.h"
|
||||
#include "libc/calls/struct/rusage.internal.h"
|
||||
#include "libc/calls/wait4.h"
|
||||
#include "libc/dce.h"
|
||||
#include "libc/intrin/asan.internal.h"
|
||||
#include "libc/intrin/strace.internal.h"
|
||||
#include "libc/sysv/errfuns.h"
|
||||
|
||||
/**
|
||||
|
@ -34,6 +34,7 @@
|
|||
* @param options can have WNOHANG, WUNTRACED, WCONTINUED, etc.
|
||||
* @param opt_out_rusage optionally returns accounting data
|
||||
* @return process id of terminated child or -1 w/ errno
|
||||
* @cancellationpoint
|
||||
* @asyncsignalsafe
|
||||
* @restartable
|
||||
*/
|
||||
|
|
|
@ -27,6 +27,7 @@
|
|||
* may be inspected using WEXITSTATUS(), etc.
|
||||
* @param options can have WNOHANG, WUNTRACED, WCONTINUED, etc.
|
||||
* @return process id of terminated child or -1 w/ errno
|
||||
* @cancellationpoint
|
||||
* @asyncsignalsafe
|
||||
* @restartable
|
||||
*/
|
||||
|
|
|
@ -57,6 +57,7 @@
|
|||
* as a general possibility; whereas other system don't specify it
|
||||
* @raise ENXIO is specified only by POSIX and XNU when a request is
|
||||
* made of a nonexistent device or outside device capabilities
|
||||
* @cancellationpoint
|
||||
* @asyncsignalsafe
|
||||
* @restartable
|
||||
* @vforksafe
|
||||
|
|
|
@ -47,6 +47,7 @@
|
|||
* call using write().
|
||||
*
|
||||
* @return number of bytes actually handed off, or -1 w/ errno
|
||||
* @cancellationpoint
|
||||
* @restartable
|
||||
*/
|
||||
ssize_t writev(int fd, const struct iovec *iov, int iovlen) {
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue