mirror of
https://github.com/jart/cosmopolitan.git
synced 2025-07-06 11:18:30 +00:00
Make signal handling work well across platforms
- Fix sigsuspend() on XNU - Fix strsignal() on non-Linux - Add unit tests for strsignal() - Add unit tests for setitimer() - Add unit tests for sigsuspend() - Rewrite setitimer() for New Technology - Rewrite nanosleep() for New Technology - Polyfill SIGALRM on the New Technology - select(0,0,0,0) on NT now calls pause() - Remove some NTDLL calls that aren't needed - Polyfill SA_NOCLDWAIT on the New Technology - Polyfill SA_RESETHAND on the New Technology - Polyfill sigprocmask() on the New Technology - Polyfill SIGCHLD+SIG_IGN on the New Technology - Polyfill SA_RESTART masking on the New Technology - Deliver console signals from main thread on New Technology - Document SA_RESTART behavior w/ @sarestartable / @norestart - System call trace in MODE=dbg now prints inherited FDs and signal mask
This commit is contained in:
parent
3b9e66ecba
commit
072e1d2910
82 changed files with 1388 additions and 450 deletions
|
@ -18,6 +18,7 @@
|
|||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/assert.h"
|
||||
#include "libc/calls/internal.h"
|
||||
#include "libc/calls/strace.internal.h"
|
||||
#include "libc/calls/struct/timeval.h"
|
||||
#include "libc/dce.h"
|
||||
#include "libc/fmt/conv.h"
|
||||
|
@ -39,9 +40,10 @@
|
|||
* @see strftime(), gettimeofday()
|
||||
* @asyncsignalsafe
|
||||
*/
|
||||
int clock_gettime(int clockid, struct timespec *ts) {
|
||||
noinstrument int clock_gettime(int clockid, struct timespec *ts) {
|
||||
int rc, e;
|
||||
axdx_t ad;
|
||||
char buf[45];
|
||||
if (!ts) {
|
||||
rc = efault();
|
||||
} else if (IsAsan() && !__asan_is_valid(ts, sizeof(*ts))) {
|
||||
|
@ -64,6 +66,9 @@ int clock_gettime(int clockid, struct timespec *ts) {
|
|||
} else {
|
||||
rc = sys_clock_gettime_nt(clockid, ts);
|
||||
}
|
||||
/* TODO(jart): Add get_clock_gettime() so we can STRACE() */
|
||||
if (!__time_critical) {
|
||||
STRACE("clock_gettime(%d, [%s]) → %d% m", clockid,
|
||||
__strace_timespec(buf, sizeof(buf), rc, ts), rc);
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
|
|
|
@ -19,6 +19,7 @@
|
|||
#include "libc/bits/weaken.h"
|
||||
#include "libc/calls/calls.h"
|
||||
#include "libc/calls/internal.h"
|
||||
#include "libc/calls/strace.internal.h"
|
||||
#include "libc/dce.h"
|
||||
#include "libc/sysv/errfuns.h"
|
||||
#include "libc/zipos/zipos.internal.h"
|
||||
|
@ -47,8 +48,10 @@
|
|||
* @param arg can be FD_CLOEXEC, etc. depending
|
||||
* @return 0 on success, or -1 w/ errno
|
||||
* @asyncsignalsafe
|
||||
* @restartable
|
||||
*/
|
||||
int fcntl(int fd, int cmd, ...) {
|
||||
int rc;
|
||||
va_list va;
|
||||
uintptr_t arg;
|
||||
va_start(va, cmd);
|
||||
|
@ -56,13 +59,15 @@ int fcntl(int fd, int cmd, ...) {
|
|||
va_end(va);
|
||||
if (fd >= 0) {
|
||||
if (fd < g_fds.n && g_fds.p[fd].kind == kFdZip) {
|
||||
return weaken(__zipos_fcntl)(fd, cmd, arg);
|
||||
rc = weaken(__zipos_fcntl)(fd, cmd, arg);
|
||||
} else if (!IsWindows()) {
|
||||
return sys_fcntl(fd, cmd, arg);
|
||||
rc = sys_fcntl(fd, cmd, arg);
|
||||
} else {
|
||||
return sys_fcntl_nt(fd, cmd, arg);
|
||||
rc = sys_fcntl_nt(fd, cmd, arg);
|
||||
}
|
||||
} else {
|
||||
return einval();
|
||||
rc = einval();
|
||||
}
|
||||
STRACE("fcntl(%d, %d, %p) → %d% m", fd, cmd, arg);
|
||||
return rc;
|
||||
}
|
||||
|
|
|
@ -29,6 +29,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
|
||||
* @restartable
|
||||
*/
|
||||
int flock(int fd, int op) {
|
||||
int rc;
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*-*- mode:unix-assembly; indent-tabs-mode:t; tab-width:8; coding:utf-8 -*-│
|
||||
│vi: set et ft=asm ts=8 tw=8 fenc=utf-8 :vi│
|
||||
│vi: set et ft=asm ts=8 sw=8 fenc=utf-8 :vi│
|
||||
╞══════════════════════════════════════════════════════════════════════════════╡
|
||||
│ Copyright 2020 Justine Alexandra Roberts Tunney │
|
||||
│ │
|
||||
|
@ -16,10 +16,29 @@
|
|||
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/runtime/pc.internal.h"
|
||||
#include "libc/macros.internal.h"
|
||||
.text.windows
|
||||
|
||||
__winalarm_nt:
|
||||
ezlea __winalarm,ax
|
||||
jmp __nt2sysv
|
||||
.endfn __winalarm_nt,globl,hidden
|
||||
// fmod [sic] does (𝑥 rem 𝑦) w/ round()-style rounding.
|
||||
//
|
||||
// @param 𝑥 is an 80-bit long double passed on stack in 16-bytes
|
||||
// @param 𝑦 is the power, also pushed on stack, in reverse order
|
||||
// @return remainder ∈ (-|𝑦|,|𝑦|) in %st
|
||||
// @define 𝑥-truncl(𝑥/𝑦)*𝑦
|
||||
// @see emod()
|
||||
fmodl: push %rbp
|
||||
mov %rsp,%rbp
|
||||
.profilable
|
||||
fldt 32(%rbp)
|
||||
fldt 16(%rbp)
|
||||
1: fprem
|
||||
fnstsw
|
||||
test $FPU_C2>>8,%ah
|
||||
jnz 1b
|
||||
fstp %st(1)
|
||||
pop %rbp
|
||||
ret
|
||||
1: int3
|
||||
pop %rbp
|
||||
ret
|
||||
.endfn fmodl,globl
|
|
@ -19,3 +19,4 @@
|
|||
#include "libc/calls/internal.h"
|
||||
|
||||
unsigned __sighandrvas[NSIG];
|
||||
unsigned __sighandflags[NSIG];
|
||||
|
|
|
@ -9,8 +9,6 @@ static inline int GetConsoleCtrlEvent(int sig) {
|
|||
switch (sig) {
|
||||
case SIGINT:
|
||||
return kNtCtrlCEvent;
|
||||
case SIGHUP:
|
||||
return kNtCtrlCloseEvent;
|
||||
case SIGQUIT:
|
||||
return kNtCtrlBreakEvent;
|
||||
default:
|
||||
|
|
|
@ -58,6 +58,7 @@ struct Fd {
|
|||
unsigned flags;
|
||||
int64_t handle;
|
||||
int64_t extra;
|
||||
bool zombie;
|
||||
};
|
||||
|
||||
struct Fds {
|
||||
|
@ -69,9 +70,10 @@ struct Fds {
|
|||
|
||||
extern const struct Fd kEmptyFd;
|
||||
|
||||
hidden extern volatile bool __interrupted;
|
||||
hidden extern int __vforked;
|
||||
hidden extern bool __time_critical;
|
||||
hidden extern unsigned __sighandrvas[NSIG];
|
||||
hidden extern unsigned __sighandflags[NSIG];
|
||||
hidden extern struct Fds g_fds;
|
||||
hidden extern const struct NtSecurityAttributes kNtIsInheritable;
|
||||
|
||||
|
@ -306,8 +308,10 @@ int ioctl_tiocgwinsz_nt(struct Fd *, struct winsize *) hidden;
|
|||
│ cosmopolitan § syscalls » windows nt » support ─╬─│┼
|
||||
╚────────────────────────────────────────────────────────────────────────────│*/
|
||||
|
||||
bool _check_sigchld(void) hidden;
|
||||
int __sample_pids(int[hasatleast 64], int64_t[hasatleast 64]) hidden;
|
||||
bool _check_interrupts(bool, struct Fd *) hidden;
|
||||
void _check_sigchld(void) hidden;
|
||||
void _check_sigalrm(void) hidden;
|
||||
int __sample_pids(int[hasatleast 64], int64_t[hasatleast 64], bool) hidden;
|
||||
bool isdirectory_nt(const char *) hidden;
|
||||
bool isregularfile_nt(const char *) hidden;
|
||||
bool issymlink_nt(const char *) hidden;
|
||||
|
@ -327,7 +331,6 @@ struct NtOverlapped *offset2overlap(int64_t, struct NtOverlapped *) hidden;
|
|||
unsigned __wincrash_nt(struct NtExceptionPointers *);
|
||||
void *GetProcAddressModule(const char *, const char *) hidden;
|
||||
void WinMainForked(void) hidden;
|
||||
void __winalarm(void *, uint32_t, uint32_t) hidden;
|
||||
void ntcontext2linux(struct ucontext *, const struct NtContext *) hidden;
|
||||
|
||||
/*───────────────────────────────────────────────────────────────────────────│─╗
|
||||
|
|
33
libc/calls/interrupts-nt.c
Normal file
33
libc/calls/interrupts-nt.c
Normal file
|
@ -0,0 +1,33 @@
|
|||
/*-*- 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/assert.h"
|
||||
#include "libc/bits/weaken.h"
|
||||
#include "libc/calls/internal.h"
|
||||
#include "libc/calls/sig.internal.h"
|
||||
#include "libc/calls/strace.internal.h"
|
||||
#include "libc/calls/struct/sigaction.h"
|
||||
#include "libc/dce.h"
|
||||
|
||||
textwindows bool _check_interrupts(bool restartable, struct Fd *fd) {
|
||||
if (__time_critical) return false;
|
||||
if (weaken(_check_sigalrm)) weaken(_check_sigalrm)();
|
||||
if (weaken(_check_sigchld)) weaken(_check_sigchld)();
|
||||
if (fd && weaken(_check_sigwinch)) weaken(_check_sigwinch)(fd);
|
||||
return weaken(__sig_check) && weaken(__sig_check)(restartable);
|
||||
}
|
|
@ -25,6 +25,7 @@
|
|||
|
||||
/**
|
||||
* Controls settings on device.
|
||||
* @restartable
|
||||
* @vforksafe
|
||||
*/
|
||||
int(ioctl)(int fd, uint64_t request, ...) {
|
||||
|
|
|
@ -16,6 +16,7 @@
|
|||
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/calls/calls.h"
|
||||
#include "libc/calls/getconsolectrlevent.h"
|
||||
#include "libc/calls/internal.h"
|
||||
#include "libc/dce.h"
|
||||
|
@ -35,7 +36,7 @@ textwindows int sys_kill_nt(int pid, int sig) {
|
|||
if (pid) {
|
||||
pid = ABS(pid);
|
||||
if ((event = GetConsoleCtrlEvent(sig)) != -1) {
|
||||
/* kill(pid, SIGINT|SIGHUP|SIGQUIT) */
|
||||
/* kill(pid, SIGINT|SIGQUIT) */
|
||||
if (__isfdkind(pid, kFdProcess)) {
|
||||
ntpid = GetProcessId(g_fds.p[pid].handle);
|
||||
} else if (!__isfdopen(pid)) {
|
||||
|
|
|
@ -16,33 +16,61 @@
|
|||
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#define ShouldUseMsabiAttribute() 1
|
||||
#include "libc/calls/internal.h"
|
||||
#include "libc/calls/sig.internal.h"
|
||||
#include "libc/calls/strace.internal.h"
|
||||
#include "libc/errno.h"
|
||||
#include "libc/macros.internal.h"
|
||||
#include "libc/nt/errors.h"
|
||||
#include "libc/nt/nt/time.h"
|
||||
#include "libc/nt/synchronization.h"
|
||||
#include "libc/sysv/errfuns.h"
|
||||
|
||||
textwindows noinstrument int sys_nanosleep_nt(const struct timespec *req,
|
||||
struct timespec *rem) {
|
||||
/* no function tracing because timing sensitive */
|
||||
int64_t millis, hectonanos, relasleep;
|
||||
if (rem) memcpy(rem, req, sizeof(*rem));
|
||||
hectonanos = req->tv_sec * 10000000 + req->tv_nsec / 100;
|
||||
hectonanos = MAX(1, hectonanos);
|
||||
relasleep = -hectonanos;
|
||||
if (NtError(__imp_NtDelayExecution(true, &relasleep))) {
|
||||
millis = hectonanos / 10000;
|
||||
millis = MAX(1, millis);
|
||||
if (__imp_SleepEx(millis, true) == kNtWaitIoCompletion) {
|
||||
errno = EINTR;
|
||||
return -1;
|
||||
int rc;
|
||||
int64_t sec, nsec;
|
||||
uint64_t ms, slice;
|
||||
if (__builtin_mul_overflow(req->tv_sec, 1000, &ms) ||
|
||||
__builtin_add_overflow(ms, req->tv_nsec / 1000000, &ms)) {
|
||||
ms = -1;
|
||||
}
|
||||
if (!ms && (req->tv_sec || req->tv_nsec)) {
|
||||
ms = 1;
|
||||
}
|
||||
rc = 0;
|
||||
do {
|
||||
if (!__time_critical && _check_interrupts(false, g_fds.p)) {
|
||||
rc = eintr();
|
||||
break;
|
||||
}
|
||||
if (ms > __SIG_POLLING_INTERVAL_MS) {
|
||||
slice = __SIG_POLLING_INTERVAL_MS;
|
||||
} else {
|
||||
slice = ms;
|
||||
}
|
||||
if (!__time_critical) {
|
||||
STRACE("SleepEx(%u, true)", slice);
|
||||
}
|
||||
if (SleepEx(slice, true) == kNtWaitIoCompletion) {
|
||||
rc = eintr();
|
||||
break;
|
||||
}
|
||||
ms -= slice;
|
||||
} while (ms);
|
||||
if (rem) {
|
||||
sec = ms / 1000;
|
||||
nsec = ms % 1000 * 1000000000;
|
||||
rem->tv_nsec -= nsec;
|
||||
if (rem->tv_nsec < 0) {
|
||||
--rem->tv_sec;
|
||||
rem->tv_nsec = 1000000000 - rem->tv_nsec;
|
||||
}
|
||||
rem->tv_sec -= sec;
|
||||
if (rem->tv_sec < 0) {
|
||||
rem->tv_sec = 0;
|
||||
rem->tv_nsec = 0;
|
||||
}
|
||||
}
|
||||
if (rem) {
|
||||
rem->tv_sec = 0;
|
||||
rem->tv_nsec = 0;
|
||||
}
|
||||
return 0;
|
||||
return rc;
|
||||
}
|
||||
|
|
|
@ -18,24 +18,35 @@
|
|||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/calls/calls.h"
|
||||
#include "libc/calls/internal.h"
|
||||
#include "libc/calls/strace.internal.h"
|
||||
#include "libc/dce.h"
|
||||
#include "libc/sysv/errfuns.h"
|
||||
|
||||
/**
|
||||
* Sleeps for a particular amount of time.
|
||||
* @norestart
|
||||
*/
|
||||
int nanosleep(const struct timespec *req, struct timespec *rem) {
|
||||
if (!req) return efault();
|
||||
if (req->tv_sec < 0 || !(0 <= req->tv_nsec && req->tv_nsec <= 999999999)) {
|
||||
return einval();
|
||||
}
|
||||
if (!IsWindows() && !IsMetal() && !IsXnu()) {
|
||||
return sys_nanosleep(req, rem);
|
||||
noinstrument int nanosleep(const struct timespec *req, struct timespec *rem) {
|
||||
int rc;
|
||||
char buf[2][45];
|
||||
if (!req) {
|
||||
rc = efault();
|
||||
} else if (req->tv_sec < 0 ||
|
||||
!(0 <= req->tv_nsec && req->tv_nsec <= 999999999)) {
|
||||
rc = einval();
|
||||
} else if (!IsWindows() && !IsMetal() && !IsXnu()) {
|
||||
rc = sys_nanosleep(req, rem);
|
||||
} else if (IsXnu()) {
|
||||
return sys_nanosleep_xnu(req, rem);
|
||||
rc = sys_nanosleep_xnu(req, rem);
|
||||
} else if (IsMetal()) {
|
||||
return enosys(); /* TODO: Sleep on Metal */
|
||||
rc = enosys(); /* TODO: Sleep on Metal */
|
||||
} else {
|
||||
return sys_nanosleep_nt(req, rem);
|
||||
rc = sys_nanosleep_nt(req, rem);
|
||||
}
|
||||
if (!__time_critical) {
|
||||
STRACE("nanosleep(%s, [%s]) → %d% m",
|
||||
__strace_timespec(buf[0], sizeof(buf[0]), rc, req),
|
||||
__strace_timespec(buf[1], sizeof(buf[1]), rc, rem), rc);
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
|
|
|
@ -20,6 +20,8 @@
|
|||
#include "libc/bits/initializer.internal.h"
|
||||
#include "libc/bits/safemacros.internal.h"
|
||||
#include "libc/calls/calls.h"
|
||||
#include "libc/calls/internal.h"
|
||||
#include "libc/calls/strace.internal.h"
|
||||
#include "libc/dce.h"
|
||||
#include "libc/macros.internal.h"
|
||||
#include "libc/nexgen32e/rdtsc.h"
|
||||
|
@ -40,17 +42,20 @@ static long double GetTimeSample(void) {
|
|||
sched_yield();
|
||||
time1 = dtime(CLOCK_REALTIME);
|
||||
tick1 = rdtsc();
|
||||
nanosleep(&(struct timespec){0, 100000}, NULL);
|
||||
nanosleep(&(struct timespec){0, 1000000}, NULL);
|
||||
time2 = dtime(CLOCK_REALTIME);
|
||||
tick2 = rdtsc();
|
||||
return (time2 - time1) * 1e9 / MAX(1, tick2 - tick1);
|
||||
}
|
||||
|
||||
static long double MeasureNanosPerCycle(void) {
|
||||
bool tc;
|
||||
int i, n;
|
||||
long double avg, samp;
|
||||
tc = __time_critical;
|
||||
__time_critical = true;
|
||||
if (IsWindows()) {
|
||||
n = 20;
|
||||
n = 10;
|
||||
} else {
|
||||
n = 5;
|
||||
}
|
||||
|
@ -58,6 +63,8 @@ static long double MeasureNanosPerCycle(void) {
|
|||
samp = GetTimeSample();
|
||||
avg += (samp - avg) / i;
|
||||
}
|
||||
__time_critical = tc;
|
||||
STRACE("MeasureNanosPerCycle cpn*1000=%d", (long)(avg * 1000));
|
||||
return avg;
|
||||
}
|
||||
|
||||
|
|
|
@ -16,52 +16,25 @@
|
|||
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/bits/pushpop.h"
|
||||
#include "libc/calls/internal.h"
|
||||
#include "libc/calls/strace.internal.h"
|
||||
#include "libc/calls/struct/siginfo.h"
|
||||
#include "libc/calls/typedef/sigaction_f.h"
|
||||
#include "libc/calls/sig.internal.h"
|
||||
#include "libc/nt/enum/ctrlevent.h"
|
||||
#include "libc/nt/runtime.h"
|
||||
#include "libc/runtime/runtime.h"
|
||||
#include "libc/str/str.h"
|
||||
#include "libc/sysv/consts/sicode.h"
|
||||
#include "libc/sysv/consts/sig.h"
|
||||
|
||||
textwindows bool32 __onntconsoleevent(uint32_t CtrlType) {
|
||||
int sig;
|
||||
unsigned rva;
|
||||
siginfo_t info;
|
||||
switch (CtrlType) {
|
||||
textwindows bool32 __onntconsoleevent(uint32_t dwCtrlType) {
|
||||
switch (dwCtrlType) {
|
||||
case kNtCtrlCEvent:
|
||||
STRACE("kNtCtrlCEvent");
|
||||
sig = pushpop(SIGINT);
|
||||
break;
|
||||
__sig_add(SIGINT, SI_KERNEL);
|
||||
return true;
|
||||
case kNtCtrlBreakEvent:
|
||||
STRACE("kNtCtrlBreakEvent");
|
||||
sig = pushpop(SIGQUIT);
|
||||
break;
|
||||
__sig_add(SIGQUIT, SI_KERNEL);
|
||||
return true;
|
||||
case kNtCtrlCloseEvent:
|
||||
STRACE("kNtCtrlCloseEvent");
|
||||
sig = pushpop(SIGHUP);
|
||||
break;
|
||||
case kNtCtrlLogoffEvent: // only received by services so hack hack hack
|
||||
case kNtCtrlShutdownEvent: // only received by services so hack hack hack
|
||||
STRACE("kNtCtrlLogoffEvent");
|
||||
sig = pushpop(SIGALRM);
|
||||
break;
|
||||
case kNtCtrlLogoffEvent: // only received by services
|
||||
case kNtCtrlShutdownEvent: // only received by services
|
||||
__sig_add(SIGHUP, SI_KERNEL);
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
switch ((rva = __sighandrvas[sig])) {
|
||||
case (uintptr_t)SIG_DFL:
|
||||
_Exit(128 + sig);
|
||||
case (uintptr_t)SIG_IGN:
|
||||
return true;
|
||||
default:
|
||||
bzero(&info, sizeof(info));
|
||||
info.si_signo = sig;
|
||||
((sigaction_f)(_base + rva))(sig, &info, NULL);
|
||||
__interrupted = true;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -29,6 +29,7 @@
|
|||
* ignored if O_CREAT or O_TMPFILE weren't passed
|
||||
* @return number needing close(), or -1 w/ errno
|
||||
* @asyncsignalsafe
|
||||
* @restartable
|
||||
* @vforksafe
|
||||
*/
|
||||
int open(const char *file, int flags, ...) {
|
||||
|
|
|
@ -20,28 +20,32 @@
|
|||
#include "libc/calls/internal.h"
|
||||
#include "libc/calls/strace.internal.h"
|
||||
#include "libc/calls/struct/sigset.h"
|
||||
#include "libc/dce.h"
|
||||
#include "libc/errno.h"
|
||||
#include "libc/nt/synchronization.h"
|
||||
#include "libc/sysv/consts/sig.h"
|
||||
#include "libc/sysv/errfuns.h"
|
||||
|
||||
/**
|
||||
* Waits for signal.
|
||||
* Waits for any signal.
|
||||
*
|
||||
* This suspends execution until an unmasked signal is delivered
|
||||
* and its callback function has been called. It's a better idea
|
||||
* to use sigsuspend() w/ sigprocmask() to avoid race conditions
|
||||
* This suspends execution until an unmasked signal is delivered and its
|
||||
* callback function has been called. The current signal mask is used.
|
||||
*
|
||||
* @return should always be -1 w/ EINTR
|
||||
* @see sigsuspend()
|
||||
* @norestart
|
||||
*/
|
||||
int pause(void) {
|
||||
int rc, olderr;
|
||||
sigset_t oldmask;
|
||||
olderr = errno;
|
||||
STRACE("pause()");
|
||||
int e, rc;
|
||||
sigset_t mask;
|
||||
e = errno;
|
||||
STRACE("pause() → [...]");
|
||||
if ((rc = sys_pause()) == -1 && errno == ENOSYS) {
|
||||
errno = olderr;
|
||||
if (sigprocmask(SIG_BLOCK, NULL, &oldmask) == -1) return -1;
|
||||
rc = sigsuspend(&oldmask);
|
||||
errno = e;
|
||||
if (sigprocmask(SIG_BLOCK, 0, &mask) == -1) return -1;
|
||||
rc = sigsuspend(&mask);
|
||||
}
|
||||
STRACE("[...] pause → %d% m", rc);
|
||||
return rc;
|
||||
}
|
||||
|
|
|
@ -19,10 +19,12 @@
|
|||
#include "libc/calls/calls.h"
|
||||
#include "libc/calls/getconsolectrlevent.h"
|
||||
#include "libc/calls/internal.h"
|
||||
#include "libc/calls/sig.internal.h"
|
||||
#include "libc/calls/strace.internal.h"
|
||||
#include "libc/nt/console.h"
|
||||
#include "libc/nt/runtime.h"
|
||||
#include "libc/runtime/runtime.h"
|
||||
#include "libc/sysv/consts/sicode.h"
|
||||
#include "libc/sysv/consts/sig.h"
|
||||
|
||||
/**
|
||||
|
@ -33,26 +35,28 @@
|
|||
* @asyncsignalsafe
|
||||
*/
|
||||
int raise(int sig) {
|
||||
int event;
|
||||
STRACE("raise(%d)", sig);
|
||||
int rc, event;
|
||||
STRACE("raise(%d) → [...]", sig);
|
||||
if (sig == SIGTRAP) {
|
||||
DebugBreak();
|
||||
return 0;
|
||||
}
|
||||
if (sig == SIGFPE) {
|
||||
rc = 0;
|
||||
} else if (sig == SIGFPE) {
|
||||
volatile int x = 0;
|
||||
x = 1 / x;
|
||||
return 0;
|
||||
}
|
||||
if (!IsWindows()) {
|
||||
return sys_kill(getpid(), sig, 1);
|
||||
} else if ((event = GetConsoleCtrlEvent(sig))) {
|
||||
if (GenerateConsoleCtrlEvent(event, 0)) {
|
||||
return 0;
|
||||
} else {
|
||||
return __winerr();
|
||||
}
|
||||
rc = 0;
|
||||
} else if (!IsWindows()) {
|
||||
rc = sys_kill(getpid(), sig, 1);
|
||||
} else {
|
||||
_Exit(128 + sig);
|
||||
if ((event = GetConsoleCtrlEvent(sig)) != -1) {
|
||||
if (GenerateConsoleCtrlEvent(event, 0)) {
|
||||
rc = 0;
|
||||
} else {
|
||||
rc = __winerr();
|
||||
}
|
||||
} else {
|
||||
rc = __sig_add(sig, SI_USER);
|
||||
}
|
||||
}
|
||||
STRACE("[...] raise → %d% m", rc);
|
||||
return rc;
|
||||
}
|
||||
|
|
|
@ -51,11 +51,7 @@ textwindows ssize_t sys_read_nt(struct Fd *fd, const struct iovec *iov,
|
|||
ssize_t rc;
|
||||
uint32_t size;
|
||||
size_t i, total;
|
||||
if (cmpxchg(&__interrupted, true, false) ||
|
||||
(weaken(_check_sigchld) && weaken(_check_sigchld)()) ||
|
||||
(weaken(_check_sigwinch) && weaken(_check_sigwinch)(fd))) {
|
||||
return eintr();
|
||||
}
|
||||
if (_check_interrupts(true, fd)) return eintr();
|
||||
while (iovlen && !iov[0].iov_len) iov++, iovlen--;
|
||||
if (iovlen) {
|
||||
for (total = i = 0; i < iovlen; ++i) {
|
||||
|
|
|
@ -38,6 +38,7 @@
|
|||
* exception of size==0, in which case return zero means no error
|
||||
* @see write(), pread(), readv()
|
||||
* @asyncsignalsafe
|
||||
* @restartable
|
||||
*/
|
||||
ssize_t read(int fd, void *buf, size_t size) {
|
||||
ssize_t rc;
|
||||
|
|
|
@ -30,7 +30,7 @@
|
|||
* Reads data to multiple buffers.
|
||||
*
|
||||
* @return number of bytes actually read, or -1 w/ errno
|
||||
* @asyncsignalsafe
|
||||
* @restartable
|
||||
*/
|
||||
ssize_t readv(int fd, const struct iovec *iov, int iovlen) {
|
||||
ssize_t rc;
|
||||
|
|
|
@ -16,7 +16,9 @@
|
|||
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/assert.h"
|
||||
#include "libc/calls/internal.h"
|
||||
#include "libc/dce.h"
|
||||
#include "libc/rand/lcg.internal.h"
|
||||
|
||||
/**
|
||||
|
@ -28,13 +30,15 @@
|
|||
*
|
||||
* @return number of items returned in pids and handles
|
||||
*/
|
||||
int __sample_pids(int pids[hasatleast 64], int64_t handles[hasatleast 64]) {
|
||||
textwindows int __sample_pids(int pids[hasatleast 64],
|
||||
int64_t handles[hasatleast 64],
|
||||
bool exploratory) {
|
||||
static uint64_t rando = 1;
|
||||
uint32_t i, j, base, count;
|
||||
base = KnuthLinearCongruentialGenerator(&rando);
|
||||
for (count = i = 0; i < g_fds.n; ++i) {
|
||||
j = (base + i) % g_fds.n;
|
||||
if (g_fds.p[j].kind == kFdProcess) {
|
||||
if (g_fds.p[j].kind == kFdProcess && (!exploratory || !g_fds.p[j].zombie)) {
|
||||
pids[count] = j;
|
||||
handles[count] = g_fds.p[j].handle;
|
||||
if (++count == 64) {
|
||||
|
|
|
@ -19,11 +19,16 @@
|
|||
#include "libc/calls/internal.h"
|
||||
#include "libc/nt/enum/status.h"
|
||||
#include "libc/nt/ntdll.h"
|
||||
#include "libc/nt/synchronization.h"
|
||||
|
||||
textwindows int sys_sched_yield_nt(void) {
|
||||
size_t i;
|
||||
if (NtYieldExecution() == kNtStatusDllNotFound) {
|
||||
for (i = 0; i < 16; ++i) asm("pause");
|
||||
}
|
||||
// A value of zero, together with the bAlertable parameter set to
|
||||
// FALSE, causes the thread to relinquish the remainder of its time
|
||||
// slice to any other thread that is ready to run, if there are no
|
||||
// pending user APCs on the calling thread. If there are no other
|
||||
// threads ready to run and no user APCs are queued, the function
|
||||
// returns immediately, and the thread continues execution.
|
||||
// ──Quoth MSDN
|
||||
SleepEx(0, false);
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -16,20 +16,31 @@
|
|||
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/assert.h"
|
||||
#include "libc/bits/bits.h"
|
||||
#include "libc/calls/calls.h"
|
||||
#include "libc/calls/internal.h"
|
||||
#include "libc/calls/sig.internal.h"
|
||||
#include "libc/calls/strace.internal.h"
|
||||
#include "libc/calls/struct/itimerval.h"
|
||||
#include "libc/calls/struct/siginfo.h"
|
||||
#include "libc/dce.h"
|
||||
#include "libc/errno.h"
|
||||
#include "libc/fmt/conv.h"
|
||||
#include "libc/log/check.h"
|
||||
#include "libc/math.h"
|
||||
#include "libc/nexgen32e/nexgen32e.h"
|
||||
#include "libc/nexgen32e/nt2sysv.h"
|
||||
#include "libc/nt/files.h"
|
||||
#include "libc/nt/runtime.h"
|
||||
#include "libc/nt/synchronization.h"
|
||||
#include "libc/nt/thread.h"
|
||||
#include "libc/str/str.h"
|
||||
#include "libc/sysv/consts/itimer.h"
|
||||
#include "libc/sysv/consts/sicode.h"
|
||||
#include "libc/sysv/consts/sig.h"
|
||||
#include "libc/sysv/errfuns.h"
|
||||
#include "libc/time/time.h"
|
||||
|
||||
/**
|
||||
* @fileoverview Heartbreaking polyfill for SIGALRM on NT.
|
||||
|
@ -45,59 +56,68 @@
|
|||
* interrupting i/o operations on the standard input handle.
|
||||
*/
|
||||
|
||||
static struct ItimerNt {
|
||||
int64_t ith;
|
||||
uint32_t tid;
|
||||
struct itimerval itv;
|
||||
} g_itimernt;
|
||||
static bool __hastimer;
|
||||
static bool __singleshot;
|
||||
static long double __lastalrm;
|
||||
static long double __interval;
|
||||
|
||||
static uint32_t ItimerWorker(void *arg) {
|
||||
do {
|
||||
if (!WaitForSingleObject(g_itimernt.ith, -1)) {
|
||||
__winalarm(NULL, 0, 0);
|
||||
textwindows void _check_sigalrm(void) {
|
||||
// TODO(jart): use a different timing source
|
||||
// TODO(jart): synchronize across intervals?
|
||||
long double now, elapsed;
|
||||
if (!__hastimer) return;
|
||||
now = nowl();
|
||||
elapsed = now - __lastalrm;
|
||||
if (elapsed > __interval) {
|
||||
__sig_add(SIGALRM, SI_TIMER);
|
||||
if (__singleshot) {
|
||||
__hastimer = false;
|
||||
} else {
|
||||
__lastalrm = now;
|
||||
}
|
||||
} while (g_itimernt.ith && g_itimernt.tid == GetCurrentThreadId());
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
textwindows int sys_setitimer_nt(int which, const struct itimerval *newvalue,
|
||||
struct itimerval *out_opt_oldvalue) {
|
||||
int32_t period;
|
||||
int64_t ith, duetime;
|
||||
long double elapsed, untilnext;
|
||||
if (which != ITIMER_REAL) return einval();
|
||||
if (newvalue) {
|
||||
if (newvalue->it_value.tv_sec && newvalue->it_value.tv_usec) {
|
||||
if (!(ith = CreateWaitableTimer(NULL, false, NULL))) {
|
||||
return __winerr();
|
||||
}
|
||||
duetime = -(newvalue->it_value.tv_sec * HECTONANOSECONDS +
|
||||
newvalue->it_value.tv_usec * 10);
|
||||
period = newvalue->it_value.tv_sec * 1000 +
|
||||
div1000int64(newvalue->it_value.tv_usec);
|
||||
if (!period && newvalue->it_value.tv_usec) period = 1;
|
||||
if (!SetWaitableTimer(ith, &duetime, period, NULL, NULL, false)) {
|
||||
errno = GetLastError();
|
||||
CloseHandle(ith);
|
||||
return -1;
|
||||
}
|
||||
} else {
|
||||
ith = 0;
|
||||
}
|
||||
if (g_itimernt.ith) {
|
||||
CloseHandle(g_itimernt.ith);
|
||||
g_itimernt.ith = 0;
|
||||
}
|
||||
} else {
|
||||
ith = 0;
|
||||
}
|
||||
if (out_opt_oldvalue) {
|
||||
memcpy(out_opt_oldvalue, &g_itimernt.itv, sizeof(struct itimerval));
|
||||
if (__hastimer) {
|
||||
elapsed = nowl() - __lastalrm;
|
||||
if (elapsed > __interval) {
|
||||
untilnext = 0;
|
||||
} else {
|
||||
untilnext = __interval - elapsed;
|
||||
}
|
||||
out_opt_oldvalue->it_interval.tv_sec = __interval;
|
||||
out_opt_oldvalue->it_interval.tv_usec = 1 / 1e6 * fmodl(__interval, 1);
|
||||
out_opt_oldvalue->it_value.tv_sec = untilnext;
|
||||
out_opt_oldvalue->it_value.tv_usec = 1 / 1e6 * fmodl(untilnext, 1);
|
||||
} else {
|
||||
out_opt_oldvalue->it_interval.tv_sec = 0;
|
||||
out_opt_oldvalue->it_interval.tv_usec = 0;
|
||||
out_opt_oldvalue->it_value.tv_sec = 0;
|
||||
out_opt_oldvalue->it_value.tv_usec = 0;
|
||||
}
|
||||
}
|
||||
if (ith) {
|
||||
g_itimernt.ith = ith;
|
||||
memcpy(&g_itimernt.itv, newvalue, sizeof(struct itimerval));
|
||||
CloseHandle(
|
||||
CreateThread(NULL, STACKSIZE, ItimerWorker, NULL, 0, &g_itimernt.tid));
|
||||
if (newvalue) {
|
||||
if (newvalue->it_interval.tv_sec || newvalue->it_interval.tv_usec ||
|
||||
newvalue->it_value.tv_sec || newvalue->it_value.tv_usec) {
|
||||
__hastimer = true;
|
||||
if (newvalue->it_interval.tv_sec || newvalue->it_interval.tv_usec) {
|
||||
__singleshot = false;
|
||||
__interval = newvalue->it_interval.tv_sec +
|
||||
1 / 1e6 * newvalue->it_interval.tv_usec;
|
||||
} else {
|
||||
__singleshot = true;
|
||||
__interval =
|
||||
newvalue->it_value.tv_sec + 1 / 1e6 * newvalue->it_value.tv_usec;
|
||||
}
|
||||
__lastalrm = nowl();
|
||||
} else {
|
||||
__hastimer = false;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
|
220
libc/calls/sig.c
Normal file
220
libc/calls/sig.c
Normal file
|
@ -0,0 +1,220 @@
|
|||
/*-*- 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/bits/bits.h"
|
||||
#include "libc/calls/calls.h"
|
||||
#include "libc/calls/internal.h"
|
||||
#include "libc/calls/sig.internal.h"
|
||||
#include "libc/calls/sigbits.h"
|
||||
#include "libc/calls/strace.internal.h"
|
||||
#include "libc/calls/struct/sigset.h"
|
||||
#include "libc/calls/typedef/sigaction_f.h"
|
||||
#include "libc/macros.internal.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/errfuns.h"
|
||||
|
||||
/**
|
||||
* @fileoverview UNIX signals for the New Technology.
|
||||
* @threadsafe
|
||||
*/
|
||||
|
||||
#define LOCK \
|
||||
for (;;) \
|
||||
if (lockcmpxchg(&__sig.lock, false, true)) { \
|
||||
asm volatile("" ::: "memory")
|
||||
|
||||
#define UNLOCK \
|
||||
asm volatile("" ::: "memory"); \
|
||||
__sig.lock = false; \
|
||||
break; \
|
||||
} \
|
||||
else sched_yield()
|
||||
|
||||
struct Signal {
|
||||
struct Signal *next;
|
||||
bool used;
|
||||
int sig;
|
||||
int si_code;
|
||||
};
|
||||
|
||||
struct Signals {
|
||||
bool lock;
|
||||
sigset_t mask;
|
||||
struct Signal *queue;
|
||||
struct Signal mem[__SIG_QUEUE_LENGTH];
|
||||
};
|
||||
|
||||
struct Signals __sig;
|
||||
|
||||
/**
|
||||
* Allocates piece of memory for storing pending signal.
|
||||
*/
|
||||
static textwindows struct Signal *__sig_alloc(void) {
|
||||
int i;
|
||||
for (i = 0; i < ARRAYLEN(__sig.mem); ++i) {
|
||||
if (!__sig.mem[i].used && lockcmpxchg(&__sig.mem[i].used, false, true)) {
|
||||
return __sig.mem + i;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns signal memory to static pool.
|
||||
*/
|
||||
static textwindows void __sig_free(struct Signal *mem) {
|
||||
mem->used = false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Dequeues signal that isn't masked.
|
||||
* @return signal or null if empty or none unmasked
|
||||
*/
|
||||
static textwindows struct Signal *__sig_remove(void) {
|
||||
struct Signal *prev, *res;
|
||||
if (__sig.queue) {
|
||||
LOCK;
|
||||
for (prev = 0, res = __sig.queue; res; prev = res, res = res->next) {
|
||||
if (!sigismember(&__sig.mask, res->sig)) {
|
||||
if (res == __sig.queue) {
|
||||
__sig.queue = res->next;
|
||||
} else if (prev) {
|
||||
prev->next = res->next;
|
||||
}
|
||||
res->next = 0;
|
||||
break;
|
||||
} else {
|
||||
STRACE("%s is masked", strsignal(res->sig));
|
||||
}
|
||||
}
|
||||
UNLOCK;
|
||||
} else {
|
||||
res = 0;
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
/**
|
||||
* Delivers signal.
|
||||
* @note called from main thread
|
||||
* @return true if EINTR should be returned by caller
|
||||
*/
|
||||
static textwindows bool __sig_deliver(bool restartable, struct Signal *sig,
|
||||
unsigned rva) {
|
||||
unsigned flags;
|
||||
siginfo_t info;
|
||||
flags = __sighandflags[sig->sig];
|
||||
// TODO(jart): polyfill prevention of re-entry
|
||||
if (flags & SA_RESETHAND) {
|
||||
__sighandrvas[sig->sig] = (int32_t)(intptr_t)SIG_DFL;
|
||||
}
|
||||
STRACE("delivering %s", strsignal(sig->sig));
|
||||
bzero(&info, sizeof(info));
|
||||
info.si_signo = sig->sig;
|
||||
info.si_code = sig->si_code;
|
||||
((sigaction_f)(_base + rva))(sig->sig, &info, 0);
|
||||
if (!restartable) {
|
||||
return true; // always send EINTR for wait4(), poll(), etc.
|
||||
} else if (flags & SA_RESTART) {
|
||||
STRACE("restarting syscall on %s", strsignal(sig->sig));
|
||||
return false; // resume syscall for read(), write(), etc.
|
||||
} else {
|
||||
return true; // default course is to raise EINTR
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if signal default action is to end process.
|
||||
*/
|
||||
static textwindows bool __sig_isfatal(int sig) {
|
||||
return sig != SIGCHLD;
|
||||
}
|
||||
|
||||
/**
|
||||
* Enqueues generic signal for delivery on New Technology.
|
||||
* @threadsafe
|
||||
*/
|
||||
textwindows int __sig_add(int sig, int si_code) {
|
||||
struct Signal *mem;
|
||||
if (1 <= sig && sig <= NSIG) {
|
||||
if ((mem = __sig_alloc())) {
|
||||
mem->sig = sig;
|
||||
mem->si_code = si_code;
|
||||
LOCK;
|
||||
mem->next = __sig.queue;
|
||||
__sig.queue = mem;
|
||||
UNLOCK;
|
||||
return 0;
|
||||
} else {
|
||||
return enomem();
|
||||
}
|
||||
} else {
|
||||
return einval();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Enqueues generic signal for delivery on New Technology.
|
||||
*
|
||||
* @param restartable is for functions like read() but not poll()
|
||||
* @return true if EINTR should be returned by caller
|
||||
* @note called from main thread
|
||||
* @threadsafe
|
||||
*/
|
||||
textwindows bool __sig_check(bool restartable) {
|
||||
unsigned rva;
|
||||
bool delivered;
|
||||
struct Signal *sig;
|
||||
delivered = false;
|
||||
while ((sig = __sig_remove())) {
|
||||
switch ((rva = __sighandrvas[sig->sig])) {
|
||||
case (intptr_t)SIG_DFL:
|
||||
if (__sig_isfatal(sig->sig)) {
|
||||
STRACE("terminating on %s", strsignal(sig->sig));
|
||||
__restorewintty();
|
||||
_Exit(128 + sig->sig);
|
||||
}
|
||||
// fallthrough
|
||||
case (intptr_t)SIG_IGN:
|
||||
STRACE("ignoring %s", strsignal(sig->sig));
|
||||
break;
|
||||
default:
|
||||
delivered = __sig_deliver(restartable, sig, rva);
|
||||
break;
|
||||
}
|
||||
__sig_free(sig);
|
||||
}
|
||||
return delivered;
|
||||
}
|
||||
|
||||
/**
|
||||
* Changes signal mask for main thread.
|
||||
* @return old mask
|
||||
*/
|
||||
textwindows sigset_t __sig_mask(const sigset_t *neu) {
|
||||
sigset_t old;
|
||||
LOCK;
|
||||
old = __sig.mask;
|
||||
if (neu) __sig.mask = *neu;
|
||||
UNLOCK;
|
||||
return old;
|
||||
}
|
17
libc/calls/sig.internal.h
Normal file
17
libc/calls/sig.internal.h
Normal file
|
@ -0,0 +1,17 @@
|
|||
#ifndef COSMOPOLITAN_LIBC_CALLS_SIGNALS_INTERNAL_H_
|
||||
#define COSMOPOLITAN_LIBC_CALLS_SIGNALS_INTERNAL_H_
|
||||
#include "libc/calls/struct/sigset.h"
|
||||
|
||||
#define __SIG_QUEUE_LENGTH 8
|
||||
#define __SIG_POLLING_INTERVAL_MS 50
|
||||
|
||||
#if !(__ASSEMBLER__ + __LINKER__ + 0)
|
||||
COSMOPOLITAN_C_START_
|
||||
|
||||
bool __sig_check(bool) hidden;
|
||||
int __sig_add(int, int) hidden;
|
||||
sigset_t __sig_mask(const sigset_t *) hidden;
|
||||
|
||||
COSMOPOLITAN_C_END_
|
||||
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
|
||||
#endif /* COSMOPOLITAN_LIBC_CALLS_SIGNALS_INTERNAL_H_ */
|
|
@ -219,6 +219,7 @@ static int __sigaction(int sig, const struct sigaction *act,
|
|||
}
|
||||
if (act) {
|
||||
__sighandrvas[sig] = rva;
|
||||
__sighandflags[sig] = act->sa_flags;
|
||||
}
|
||||
}
|
||||
return rc;
|
||||
|
@ -232,6 +233,7 @@ static int __sigaction(int sig, const struct sigaction *act,
|
|||
* .sa_flags = SA_RESETHAND|SA_RESTART|SA_SIGINFO};
|
||||
* CHECK_NE(-1, sigaction(SIGINT, &sa, NULL));
|
||||
*
|
||||
* @return 0 on success or -1 w/ errno
|
||||
* @see xsigaction() for a much better api
|
||||
* @asyncsignalsafe
|
||||
* @vforksafe
|
||||
|
|
|
@ -16,40 +16,46 @@
|
|||
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/assert.h"
|
||||
#include "libc/calls/internal.h"
|
||||
#include "libc/calls/sig.internal.h"
|
||||
#include "libc/calls/strace.internal.h"
|
||||
#include "libc/calls/struct/siginfo.h"
|
||||
#include "libc/calls/typedef/sigaction_f.h"
|
||||
#include "libc/nt/enum/status.h"
|
||||
#include "libc/dce.h"
|
||||
#include "libc/nt/enum/wait.h"
|
||||
#include "libc/nt/runtime.h"
|
||||
#include "libc/nt/synchronization.h"
|
||||
#include "libc/runtime/runtime.h"
|
||||
#include "libc/sysv/consts/sa.h"
|
||||
#include "libc/sysv/consts/sicode.h"
|
||||
#include "libc/sysv/consts/sig.h"
|
||||
|
||||
/**
|
||||
* Checks to see if SIGCHLD should be raised on Windows.
|
||||
* @return true if a signal was raised
|
||||
* @note yoinked by fork-nt.c
|
||||
*/
|
||||
bool _check_sigchld(void) {
|
||||
void _check_sigchld(void) {
|
||||
siginfo_t si;
|
||||
int pids[64];
|
||||
uint32_t i, n;
|
||||
int64_t handles[64];
|
||||
if (__sighandrvas[SIGCHLD] < kSigactionMinRva) return false;
|
||||
if (!(n = __sample_pids(pids, handles))) return false;
|
||||
if (!(n = __sample_pids(pids, handles, true))) return;
|
||||
i = WaitForMultipleObjects(n, handles, false, 0);
|
||||
if (i == kNtWaitTimeout) return false;
|
||||
if (i == kNtWaitTimeout) return;
|
||||
if (i == kNtWaitFailed) {
|
||||
STRACE("%s failed %u", "WaitForMultipleObjects", GetLastError());
|
||||
return false;
|
||||
return;
|
||||
}
|
||||
STRACE("SIGCHLD fd=%d handle=%ld", pids[i], handles[i]);
|
||||
bzero(&si, sizeof(si));
|
||||
si.si_signo = SIGCHLD;
|
||||
si.si_code = CLD_EXITED;
|
||||
si.si_pid = pids[i];
|
||||
((sigaction_f)(_base + __sighandrvas[SIGCHLD]))(SIGCHLD, &si, 0);
|
||||
return true;
|
||||
if (__sighandrvas[SIGCHLD] == (intptr_t)SIG_IGN) {
|
||||
STRACE("killing zombie fd=%d handle=%ld", pids[i], handles[i]);
|
||||
CloseHandle(handles[i]);
|
||||
__releasefd(pids[i]);
|
||||
return;
|
||||
}
|
||||
if (__sighandflags[SIGCHLD] & SA_NOCLDWAIT) {
|
||||
STRACE("SIGCHILD SA_NOCLDWAIT fd=%d handle=%ld", pids[i], handles[i]);
|
||||
CloseHandle(handles[i]);
|
||||
__releasefd(pids[i]);
|
||||
}
|
||||
g_fds.p[pids[i]].zombie = true;
|
||||
__sig_add(SIGCHLD, CLD_EXITED);
|
||||
}
|
||||
|
|
|
@ -19,6 +19,8 @@
|
|||
#include "libc/bits/weaken.h"
|
||||
#include "libc/calls/calls.h"
|
||||
#include "libc/calls/internal.h"
|
||||
#include "libc/calls/sig.internal.h"
|
||||
#include "libc/calls/sigbits.h"
|
||||
#include "libc/calls/strace.internal.h"
|
||||
#include "libc/calls/struct/sigset.h"
|
||||
#include "libc/dce.h"
|
||||
|
@ -39,7 +41,7 @@ static const char *DescribeHow(char buf[12], int how) {
|
|||
}
|
||||
|
||||
/**
|
||||
* Changes program signal blocking state, e.g.:
|
||||
* Changes signal blocking state of calling thread, e.g.:
|
||||
*
|
||||
* sigset_t neu,old;
|
||||
* sigfillset(&neu);
|
||||
|
@ -51,56 +53,45 @@ static const char *DescribeHow(char buf[12], int how) {
|
|||
* @param oldset will receive the old mask (optional) and can't overlap
|
||||
* @return 0 on success, or -1 w/ errno
|
||||
* @asyncsignalsafe
|
||||
* @restartable
|
||||
* @vforksafe
|
||||
*/
|
||||
int sigprocmask(int how, const sigset_t *opt_set, sigset_t *opt_out_oldset) {
|
||||
int x, rc;
|
||||
sigset_t old;
|
||||
char howbuf[12];
|
||||
char buf[2][41];
|
||||
sigset_t old, *oldp;
|
||||
const sigset_t *arg;
|
||||
if (!(IsAsan() &&
|
||||
((opt_set && !__asan_is_valid(opt_set, sizeof(*opt_set))) ||
|
||||
(opt_out_oldset &&
|
||||
!__asan_is_valid(opt_out_oldset, sizeof(*opt_out_oldset)))))) {
|
||||
if (!IsWindows() && !IsOpenbsd()) {
|
||||
if (opt_out_oldset) {
|
||||
bzero(&old, sizeof(old));
|
||||
oldp = &old;
|
||||
} else {
|
||||
oldp = 0;
|
||||
}
|
||||
if (sys_sigprocmask(how, opt_set, oldp, 8) != -1) {
|
||||
if (opt_out_oldset) {
|
||||
memcpy(opt_out_oldset, &old, sizeof(old));
|
||||
}
|
||||
rc = 0;
|
||||
} else {
|
||||
rc = -1;
|
||||
}
|
||||
} else if (IsOpenbsd()) {
|
||||
if (opt_set) {
|
||||
/* openbsd only supports 32 signals so it passses them in a reg */
|
||||
arg = (sigset_t *)(uintptr_t)(*(uint32_t *)opt_set);
|
||||
} else {
|
||||
how = 1; /* SIG_BLOCK */
|
||||
arg = 0; /* changes nothing */
|
||||
}
|
||||
if ((x = sys_sigprocmask(how, arg, 0, 0)) != -1) {
|
||||
if (opt_out_oldset) {
|
||||
bzero(opt_out_oldset, sizeof(*opt_out_oldset));
|
||||
memcpy(opt_out_oldset, &x, sizeof(x));
|
||||
}
|
||||
rc = 0;
|
||||
} else {
|
||||
rc = -1;
|
||||
}
|
||||
} else {
|
||||
if (opt_out_oldset) bzero(opt_out_oldset, sizeof(*opt_out_oldset));
|
||||
rc = 0; /* TODO(jart): Implement me! */
|
||||
}
|
||||
} else {
|
||||
int res, rc, arg1;
|
||||
const sigset_t *arg2;
|
||||
sigemptyset(&old);
|
||||
if (IsAsan() &&
|
||||
((opt_set && !__asan_is_valid(opt_set, sizeof(*opt_set))) ||
|
||||
(opt_out_oldset &&
|
||||
!__asan_is_valid(opt_out_oldset, sizeof(*opt_out_oldset))))) {
|
||||
rc = efault();
|
||||
} else if (IsLinux() || IsXnu() || IsFreebsd() || IsNetbsd()) {
|
||||
rc = sys_sigprocmask(how, opt_set, opt_out_oldset ? &old : 0, 8);
|
||||
} else if (IsOpenbsd()) {
|
||||
if (opt_set) {
|
||||
// openbsd only supports 32 signals so it passses them in a reg
|
||||
arg1 = how;
|
||||
arg2 = (sigset_t *)(uintptr_t)(*(uint32_t *)opt_set);
|
||||
} else {
|
||||
arg1 = how; // SIG_BLOCK
|
||||
arg2 = 0; // changes nothing
|
||||
}
|
||||
if ((res = sys_sigprocmask(arg1, arg2, 0, 0)) != -1) {
|
||||
memcpy(&old, &res, sizeof(res));
|
||||
rc = 0;
|
||||
} else {
|
||||
rc = -1;
|
||||
}
|
||||
} else { // windows or metal
|
||||
old = __sig_mask(opt_set);
|
||||
_check_interrupts(false, 0);
|
||||
rc = 0;
|
||||
}
|
||||
if (rc != -1 && opt_out_oldset) {
|
||||
*opt_out_oldset = old;
|
||||
}
|
||||
STRACE("sigprocmask(%s, %s, [%s]) → %d% m", DescribeHow(howbuf, how),
|
||||
__strace_sigset(buf[0], sizeof(buf[0]), 0, opt_set),
|
||||
|
|
|
@ -18,32 +18,64 @@
|
|||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/calls/calls.h"
|
||||
#include "libc/calls/internal.h"
|
||||
#include "libc/calls/sig.internal.h"
|
||||
#include "libc/calls/sigbits.h"
|
||||
#include "libc/calls/strace.internal.h"
|
||||
#include "libc/calls/struct/sigset.h"
|
||||
#include "libc/dce.h"
|
||||
#include "libc/intrin/asan.internal.h"
|
||||
#include "libc/nt/synchronization.h"
|
||||
#include "libc/sysv/errfuns.h"
|
||||
|
||||
/**
|
||||
* Blocks until SIG ∉ MASK is delivered to process.
|
||||
*
|
||||
* @param ignore is a bitset of signals to block temporarily
|
||||
* @return -1 w/ EINTR
|
||||
* @return -1 w/ EINTR or possibly EFAULT
|
||||
* @asyncsignalsafe
|
||||
* @norestart
|
||||
*/
|
||||
int sigsuspend(const sigset_t *ignore) {
|
||||
int rc;
|
||||
char buf[41];
|
||||
if (!ignore || (IsAsan() && !__asan_is_valid(ignore, sizeof(*ignore)))) {
|
||||
sigset_t save, mask, *arg;
|
||||
STRACE("sigsuspend(%s) → [...]",
|
||||
__strace_sigset(buf, sizeof(buf), 0, ignore));
|
||||
if (IsAsan() && ignore && !__asan_is_valid(ignore, sizeof(*ignore))) {
|
||||
rc = efault();
|
||||
} else if (!IsWindows()) {
|
||||
STRACE("sigsuspend(%s)", __strace_sigset(buf, sizeof(buf), 0, ignore));
|
||||
if (IsOpenbsd()) ignore = (sigset_t *)(uintptr_t)(*(uint32_t *)ignore);
|
||||
return sys_sigsuspend(ignore, 8);
|
||||
} else if (IsXnu() || IsOpenbsd()) {
|
||||
// openbsd and xnu only support 32 signals
|
||||
// they use a register calling convention for sigsuspend
|
||||
if (ignore) {
|
||||
arg = (sigset_t *)(uintptr_t)(*(uint32_t *)ignore);
|
||||
} else {
|
||||
arg = 0;
|
||||
}
|
||||
rc = sys_sigsuspend(arg, 8);
|
||||
} else if (IsLinux() || IsFreebsd() || IsNetbsd() || IsWindows()) {
|
||||
if (ignore) {
|
||||
arg = ignore;
|
||||
} else {
|
||||
sigemptyset(&mask);
|
||||
arg = &mask;
|
||||
}
|
||||
if (!IsWindows()) {
|
||||
rc = sys_sigsuspend(arg, 8);
|
||||
} else {
|
||||
save = __sig_mask(arg);
|
||||
do {
|
||||
if (_check_interrupts(false, g_fds.p)) {
|
||||
rc = eintr();
|
||||
break;
|
||||
}
|
||||
SleepEx(__SIG_POLLING_INTERVAL_MS, true);
|
||||
} while (1);
|
||||
__sig_mask(&save);
|
||||
}
|
||||
} else {
|
||||
rc = enosys(); /* TODO(jart): Implement me! */
|
||||
// TODO(jart): sigsuspend metal support
|
||||
rc = enosys();
|
||||
}
|
||||
STRACE("sigsuspend(%s) → %d% m", __strace_sigset(buf, sizeof(buf), 0, ignore),
|
||||
rc);
|
||||
STRACE("[...] sigsuspend → %d% m", rc);
|
||||
return rc;
|
||||
}
|
||||
|
|
|
@ -16,18 +16,23 @@
|
|||
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/assert.h"
|
||||
#include "libc/calls/calls.h"
|
||||
#include "libc/calls/internal.h"
|
||||
#include "libc/calls/sig.internal.h"
|
||||
#include "libc/calls/strace.internal.h"
|
||||
#include "libc/calls/struct/sigaction.h"
|
||||
#include "libc/calls/struct/winsize.h"
|
||||
#include "libc/dce.h"
|
||||
#include "libc/errno.h"
|
||||
#include "libc/nt/struct/consolescreenbufferinfoex.h"
|
||||
#include "libc/str/str.h"
|
||||
#include "libc/sysv/consts/sicode.h"
|
||||
#include "libc/sysv/consts/sig.h"
|
||||
|
||||
static struct winsize __ws;
|
||||
|
||||
textwindows bool _check_sigwinch(struct Fd *fd) {
|
||||
textwindows void _check_sigwinch(struct Fd *fd) {
|
||||
int e;
|
||||
siginfo_t si;
|
||||
struct winsize ws, old;
|
||||
|
@ -39,14 +44,7 @@ textwindows bool _check_sigwinch(struct Fd *fd) {
|
|||
if (old.ws_col != ws.ws_col || old.ws_row != ws.ws_row) {
|
||||
__ws = ws;
|
||||
if (old.ws_col | old.ws_row) {
|
||||
STRACE("SIGWINCH %hhu×%hhu → %hhu×%hhu", old.ws_col, old.ws_row,
|
||||
ws.ws_col, ws.ws_row);
|
||||
if (__sighandrvas[SIGWINCH] >= kSigactionMinRva) {
|
||||
bzero(&si, sizeof(si));
|
||||
si.si_signo = SIGWINCH;
|
||||
((sigaction_f)(_base + __sighandrvas[SIGWINCH]))(SIGWINCH, &si, 0);
|
||||
return true;
|
||||
}
|
||||
__sig_add(SIGWINCH, SI_KERNEL);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
|
@ -56,5 +54,4 @@ textwindows bool _check_sigwinch(struct Fd *fd) {
|
|||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
|
|
@ -16,17 +16,17 @@
|
|||
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/calls/internal.h"
|
||||
#include "libc/calls/strace.internal.h"
|
||||
#include "libc/calls/struct/timespec.h"
|
||||
#include "libc/sysv/errfuns.h"
|
||||
#include "libc/time/time.h"
|
||||
|
||||
/**
|
||||
* Sleeps for a particular amount of time.
|
||||
* @asyncsignalsafe
|
||||
* @norestart
|
||||
*/
|
||||
int sleep(uint32_t seconds) {
|
||||
int rc;
|
||||
rc = nanosleep(&(struct timespec){seconds, 0}, NULL);
|
||||
STRACE("sleep(%u) → %d% m", seconds, rc);
|
||||
return rc;
|
||||
return nanosleep(&(struct timespec){seconds, 0}, NULL);
|
||||
}
|
||||
|
|
|
@ -28,6 +28,7 @@ const char *__strace_sigaction(char *, size_t, int, const struct sigaction *);
|
|||
const char *__strace_sigset(char[41], size_t, int, const sigset_t *);
|
||||
const char *__strace_rlimit_name(int);
|
||||
const char *__strace_rlimit(char[41], size_t, int, const struct rlimit *);
|
||||
const char *__strace_timespec(char[45], size_t, int, const struct timespec *);
|
||||
|
||||
COSMOPOLITAN_C_END_
|
||||
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
/*-*- 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 2020 Justine Alexandra Roberts Tunney │
|
||||
│ Copyright 2021 Justine Alexandra Roberts Tunney │
|
||||
│ │
|
||||
│ Permission to use, copy, modify, and/or distribute this software for │
|
||||
│ any purpose with or without fee is hereby granted, provided that the │
|
||||
|
@ -16,20 +16,14 @@
|
|||
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/calls/internal.h"
|
||||
#include "libc/calls/struct/siginfo.h"
|
||||
#include "libc/calls/typedef/sigaction_f.h"
|
||||
#include "libc/str/str.h"
|
||||
#include "libc/sysv/consts/sig.h"
|
||||
#include "libc/calls/strace.internal.h"
|
||||
#include "libc/calls/struct/timespec.h"
|
||||
#include "libc/intrin/kprintf.h"
|
||||
|
||||
void __winalarm(void *lpArgToCompletionRoutine, uint32_t dwTimerLowValue,
|
||||
uint32_t dwTimerHighValue) {
|
||||
int rva;
|
||||
siginfo_t info;
|
||||
bzero(&info, sizeof(info));
|
||||
info.si_signo = SIGALRM;
|
||||
rva = __sighandrvas[SIGALRM];
|
||||
if (rva >= kSigactionMinRva) {
|
||||
((sigaction_f)(_base + rva))(SIGALRM, &info, NULL);
|
||||
}
|
||||
privileged const char *__strace_timespec(char buf[45], size_t bufsize, int rc,
|
||||
const struct timespec *ts) {
|
||||
if (rc == -1) return "n/a";
|
||||
if (!ts) return "NULL";
|
||||
ksnprintf(buf, bufsize, "{%ld, %ld}", ts->tv_sec, ts->tv_nsec);
|
||||
return buf;
|
||||
}
|
|
@ -24,7 +24,7 @@ COSMOPOLITAN_C_START_
|
|||
|
||||
void _init_onntconsoleevent(void);
|
||||
void _init_wincrash(void);
|
||||
bool _check_sigwinch();
|
||||
void _check_sigwinch();
|
||||
|
||||
#ifndef __SIGACTION_YOINK
|
||||
#define __SIGACTION_YOINK(SIG) \
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
/*-*- 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 2021 Justine Alexandra Roberts Tunney │
|
||||
│ 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 │
|
||||
|
@ -18,4 +18,4 @@
|
|||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/calls/internal.h"
|
||||
|
||||
volatile bool __interrupted;
|
||||
bool __time_critical;
|
|
@ -56,17 +56,33 @@ int uname(struct utsname *lool) {
|
|||
} else {
|
||||
bzero(tmp, sizeof(tmp));
|
||||
if (!IsWindows()) {
|
||||
if ((rc = sys_uname(tmp)) != -1) {
|
||||
out = (char *)lool;
|
||||
for (i = j = 0;;) {
|
||||
len = strlen(&tmp[j]);
|
||||
if (len >= sizeof(struct utsname) - i) break;
|
||||
memcpy(&out[i], &tmp[j], len + 1);
|
||||
i += SYS_NMLN;
|
||||
j += len;
|
||||
while (j < sizeof(tmp) && tmp[j] == '\0') ++j;
|
||||
if (j == sizeof(tmp)) break;
|
||||
if (IsLinux() || IsFreebsd()) {
|
||||
if ((rc = sys_uname(tmp)) != -1) {
|
||||
out = (char *)lool;
|
||||
for (i = j = 0;;) {
|
||||
len = strlen(&tmp[j]);
|
||||
if (len >= sizeof(struct utsname) - i) break;
|
||||
memcpy(&out[i], &tmp[j], len + 1);
|
||||
i += SYS_NMLN;
|
||||
j += len;
|
||||
while (j < sizeof(tmp) && tmp[j] == '\0') ++j;
|
||||
if (j == sizeof(tmp)) break;
|
||||
}
|
||||
}
|
||||
} else if (IsXnu()) {
|
||||
strcpy(lool->sysname, "XNU's Not UNIX!");
|
||||
gethostname_bsd(lool->nodename, sizeof(lool->nodename));
|
||||
rc = 0;
|
||||
} else if (IsOpenbsd()) {
|
||||
strcpy(lool->sysname, "OpenBSD");
|
||||
gethostname_bsd(lool->nodename, sizeof(lool->nodename));
|
||||
rc = 0;
|
||||
} else if (IsNetbsd()) {
|
||||
strcpy(lool->sysname, "NetBSD");
|
||||
gethostname_bsd(lool->nodename, sizeof(lool->nodename));
|
||||
rc = 0;
|
||||
} else {
|
||||
rc = enosys();
|
||||
}
|
||||
} else {
|
||||
v = NtGetVersion();
|
||||
|
|
|
@ -16,18 +16,18 @@
|
|||
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/calls/internal.h"
|
||||
#include "libc/calls/strace.internal.h"
|
||||
#include "libc/calls/struct/timespec.h"
|
||||
#include "libc/sysv/errfuns.h"
|
||||
#include "libc/time/time.h"
|
||||
|
||||
/**
|
||||
* Sleeps for particular amount of microseconds.
|
||||
* @norestart
|
||||
*/
|
||||
int usleep(uint32_t microseconds) {
|
||||
int rc;
|
||||
rc = nanosleep(&(struct timespec){(uint64_t)microseconds / 1000000,
|
||||
(uint64_t)microseconds % 1000000 * 1000},
|
||||
NULL);
|
||||
STRACE("usleep(%'u) → %d% m", microseconds, rc);
|
||||
return rc;
|
||||
return nanosleep(&(struct timespec){(uint64_t)microseconds / 1000000,
|
||||
(uint64_t)microseconds % 1000000 * 1000},
|
||||
NULL);
|
||||
}
|
||||
|
|
|
@ -25,6 +25,7 @@
|
|||
* may be inspected using WEEXITSTATUS(), etc.
|
||||
* @return process id of terminated child or -1 w/ errno
|
||||
* @asyncsignalsafe
|
||||
* @restartable
|
||||
* @vforksafe
|
||||
*/
|
||||
int wait(int *opt_out_wstatus) {
|
||||
|
|
|
@ -30,6 +30,7 @@
|
|||
* @param opt_out_rusage optionally returns accounting data
|
||||
* @return process id of terminated child or -1 w/ errno
|
||||
* @asyncsignalsafe
|
||||
* @restartable
|
||||
*/
|
||||
int wait3(int *opt_out_wstatus, int options, struct rusage *opt_out_rusage) {
|
||||
return wait4(-1, opt_out_wstatus, options, opt_out_rusage);
|
||||
|
|
|
@ -19,6 +19,7 @@
|
|||
#include "libc/assert.h"
|
||||
#include "libc/calls/calls.h"
|
||||
#include "libc/calls/internal.h"
|
||||
#include "libc/calls/sigbits.h"
|
||||
#include "libc/calls/strace.internal.h"
|
||||
#include "libc/calls/struct/rusage.h"
|
||||
#include "libc/fmt/conv.h"
|
||||
|
@ -34,6 +35,7 @@
|
|||
#include "libc/nt/struct/processmemorycounters.h"
|
||||
#include "libc/nt/synchronization.h"
|
||||
#include "libc/rand/lcg.internal.h"
|
||||
#include "libc/runtime/ezmap.internal.h"
|
||||
#include "libc/runtime/runtime.h"
|
||||
#include "libc/str/str.h"
|
||||
#include "libc/sysv/consts/o.h"
|
||||
|
@ -46,9 +48,11 @@ textwindows int sys_wait4_nt(int pid, int *opt_out_wstatus, int options,
|
|||
int64_t handle;
|
||||
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 (pid != -1 && pid != 0) {
|
||||
if (pid < 0) {
|
||||
/* XXX: this is sloppy */
|
||||
|
@ -75,10 +79,11 @@ textwindows int sys_wait4_nt(int pid, int *opt_out_wstatus, int options,
|
|||
pids[0] = pid;
|
||||
count = 1;
|
||||
} else {
|
||||
count = __sample_pids(pids, handles);
|
||||
count = __sample_pids(pids, handles, false);
|
||||
if (!count) return echild();
|
||||
}
|
||||
for (;;) {
|
||||
if (_check_interrupts(true, 0)) return eintr();
|
||||
dwExitCode = kNtStillActive;
|
||||
if (options & WNOHANG) {
|
||||
i = WaitForMultipleObjects(count, handles, false, 0);
|
||||
|
|
|
@ -35,6 +35,7 @@
|
|||
* @param opt_out_rusage optionally returns accounting data
|
||||
* @return process id of terminated child or -1 w/ errno
|
||||
* @asyncsignalsafe
|
||||
* @restartable
|
||||
*/
|
||||
int wait4(int pid, int *opt_out_wstatus, int options,
|
||||
struct rusage *opt_out_rusage) {
|
||||
|
|
|
@ -28,6 +28,7 @@
|
|||
* @param options can have WNOHANG, WUNTRACED, WCONTINUED, etc.
|
||||
* @return process id of terminated child or -1 w/ errno
|
||||
* @asyncsignalsafe
|
||||
* @restartable
|
||||
*/
|
||||
int waitpid(int pid, int *opt_out_wstatus, int options) {
|
||||
return wait4(pid, opt_out_wstatus, options, NULL);
|
||||
|
|
|
@ -27,6 +27,7 @@
|
|||
#include "libc/nt/files.h"
|
||||
#include "libc/nt/runtime.h"
|
||||
#include "libc/nt/struct/overlapped.h"
|
||||
#include "libc/runtime/internal.h"
|
||||
#include "libc/str/str.h"
|
||||
#include "libc/sysv/consts/sig.h"
|
||||
#include "libc/sysv/errfuns.h"
|
||||
|
@ -35,6 +36,7 @@ static textwindows ssize_t sys_write_nt_epipe(int fd) {
|
|||
siginfo_t info;
|
||||
STRACE("WriteFile(%d:%p) → %m", fd, g_fds.p[fd].handle);
|
||||
if (!__sighandrvas[SIGPIPE]) {
|
||||
__restorewintty();
|
||||
_Exit(128 + SIGPIPE);
|
||||
} else if (__sighandrvas[SIGPIPE] >= kSigactionMinRva) {
|
||||
bzero(&info, sizeof(info));
|
||||
|
|
|
@ -36,6 +36,7 @@
|
|||
* impossible unless size was passed as zero to do an error check
|
||||
* @see read(), pwrite(), writev(), SIGPIPE
|
||||
* @asyncsignalsafe
|
||||
* @restartable
|
||||
*/
|
||||
ssize_t write(int fd, const void *buf, size_t size) {
|
||||
ssize_t rc;
|
||||
|
|
|
@ -34,6 +34,7 @@
|
|||
* call using write().
|
||||
*
|
||||
* @return number of bytes actually handed off, or -1 w/ errno
|
||||
* @restartable
|
||||
*/
|
||||
ssize_t writev(int fd, const struct iovec *iov, int iovlen) {
|
||||
ssize_t rc;
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue