mirror of
https://github.com/jart/cosmopolitan.git
synced 2025-05-28 08:12:28 +00:00
Improve quality of raise(), abort(), and tkill()
This change fixes a nasty bug where SIG_IGN and SIG_DFL weren't working as advertised on BSDs. This change also fixes the tkill() definition on MacOS so it maps to __pthread_kill().
This commit is contained in:
parent
c5659b93f8
commit
c5c4dfcd21
12 changed files with 293 additions and 63 deletions
|
@ -17,32 +17,45 @@
|
|||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/calls/calls.h"
|
||||
#include "libc/calls/getconsolectrlevent.internal.h"
|
||||
#include "libc/calls/sig.internal.h"
|
||||
#include "libc/calls/strace.internal.h"
|
||||
#include "libc/calls/struct/sigset.h"
|
||||
#include "libc/calls/syscall-sysv.internal.h"
|
||||
#include "libc/calls/syscall_support-nt.internal.h"
|
||||
#include "libc/nt/console.h"
|
||||
#include "libc/nt/errors.h"
|
||||
#include "libc/nt/process.h"
|
||||
#include "libc/nt/runtime.h"
|
||||
#include "libc/nt/synchronization.h"
|
||||
#include "libc/dce.h"
|
||||
#include "libc/nexgen32e/threaded.h"
|
||||
#include "libc/runtime/internal.h"
|
||||
#include "libc/runtime/runtime.h"
|
||||
#include "libc/str/str.h"
|
||||
#include "libc/sysv/consts/sicode.h"
|
||||
#include "libc/sysv/consts/sig.h"
|
||||
#include "libc/thread/xnu.internal.h"
|
||||
|
||||
static textwindows inline bool HasWorkingConsole(void) {
|
||||
return !!(__ntconsolemode[0] | __ntconsolemode[1] | __ntconsolemode[2]);
|
||||
}
|
||||
|
||||
static noubsan void RaiseSigFpe(void) {
|
||||
volatile int x = 0;
|
||||
x = 1 / x;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sends signal to this thread.
|
||||
* Sends signal to self.
|
||||
*
|
||||
* This is basically the same as:
|
||||
*
|
||||
* tkill(gettid(), sig);
|
||||
*
|
||||
* Note `SIG_DFL` still results in process death for most signals.
|
||||
*
|
||||
* This function is not entirely equivalent to kill() or tkill(). For
|
||||
* example, we raise `SIGTRAP` and `SIGFPE` the natural way, since that
|
||||
* helps us support Windows. So if the raised signal has a signal
|
||||
* handler, then the reported `si_code` might not be `SI_TKILL`.
|
||||
*
|
||||
* On Windows, if a signal results in the termination of the process
|
||||
* then we use the convention `_Exit(128 + sig)` to notify the parent of
|
||||
* the signal number.
|
||||
*
|
||||
* @param sig can be SIGALRM, SIGINT, SIGTERM, SIGKILL, etc.
|
||||
* @return 0 on success or -1 w/ errno
|
||||
* @return 0 if signal was delivered and returned, or -1 w/ errno
|
||||
* @asyncsignalsafe
|
||||
*/
|
||||
int raise(int sig) {
|
||||
|
@ -52,28 +65,12 @@ int raise(int sig) {
|
|||
DebugBreak();
|
||||
rc = 0;
|
||||
} else if (sig == SIGFPE) {
|
||||
volatile int x = 0;
|
||||
x = 1 / x;
|
||||
RaiseSigFpe();
|
||||
rc = 0;
|
||||
} else if (!IsWindows()) {
|
||||
rc = sys_tkill(gettid(), sig, 0);
|
||||
} else {
|
||||
if (HasWorkingConsole() && (event = GetConsoleCtrlEvent(sig)) != -1) {
|
||||
// XXX: MSDN says "If this parameter is zero, the signal is
|
||||
// generated in all processes that share the console of the
|
||||
// calling process." which seems to imply multiple process
|
||||
// groups potentially. We just shouldn't use this because it
|
||||
// doesn't make any sense and it's so evil.
|
||||
if (GenerateConsoleCtrlEvent(event, 0)) {
|
||||
SleepEx(100, true);
|
||||
__sig_check(false);
|
||||
rc = 0;
|
||||
} else {
|
||||
rc = __winerr();
|
||||
}
|
||||
} else {
|
||||
rc = __sig_raise(sig, SI_USER);
|
||||
}
|
||||
rc = __sig_raise(sig, SI_TKILL);
|
||||
}
|
||||
STRACE("...raise(%G) → %d% m", sig, rc);
|
||||
return rc;
|
||||
|
|
|
@ -182,8 +182,11 @@ static int __sigaction(int sig, const struct sigaction *act,
|
|||
ap = ©
|
||||
if (IsXnu()) {
|
||||
ap->sa_restorer = (void *)&__sigenter_xnu;
|
||||
ap->sa_handler = (void *)&__sigenter_xnu;
|
||||
|
||||
if (rva < kSigactionMinRva) {
|
||||
ap->sa_sigaction = (void *)(intptr_t)rva;
|
||||
} else {
|
||||
ap->sa_sigaction = (void *)&__sigenter_xnu;
|
||||
}
|
||||
// mitigate Rosetta signal handling strangeness
|
||||
// https://github.com/jart/cosmopolitan/issues/455
|
||||
ap->sa_flags |= SA_SIGINFO;
|
||||
|
@ -193,11 +196,23 @@ static int __sigaction(int sig, const struct sigaction *act,
|
|||
ap->sa_restorer = &__restore_rt;
|
||||
}
|
||||
} else if (IsNetbsd()) {
|
||||
ap->sa_sigaction = (sigaction_f)__sigenter_netbsd;
|
||||
if (rva < kSigactionMinRva) {
|
||||
ap->sa_sigaction = (void *)(intptr_t)rva;
|
||||
} else {
|
||||
ap->sa_sigaction = (sigaction_f)__sigenter_netbsd;
|
||||
}
|
||||
} else if (IsFreebsd()) {
|
||||
ap->sa_sigaction = (sigaction_f)__sigenter_freebsd;
|
||||
if (rva < kSigactionMinRva) {
|
||||
ap->sa_sigaction = (void *)(intptr_t)rva;
|
||||
} else {
|
||||
ap->sa_sigaction = (sigaction_f)__sigenter_freebsd;
|
||||
}
|
||||
} else if (IsOpenbsd()) {
|
||||
ap->sa_sigaction = (sigaction_f)__sigenter_openbsd;
|
||||
if (rva < kSigactionMinRva) {
|
||||
ap->sa_sigaction = (void *)(intptr_t)rva;
|
||||
} else {
|
||||
ap->sa_sigaction = (sigaction_f)__sigenter_openbsd;
|
||||
}
|
||||
} else {
|
||||
return enosys();
|
||||
}
|
||||
|
|
|
@ -17,30 +17,29 @@
|
|||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/calls/calls.h"
|
||||
#include "libc/calls/sig.internal.h"
|
||||
#include "libc/calls/struct/sigaction.h"
|
||||
#include "libc/calls/struct/sigset.h"
|
||||
#include "libc/dce.h"
|
||||
#include "libc/runtime/internal.h"
|
||||
#include "libc/runtime/runtime.h"
|
||||
#include "libc/sysv/consts/sig.h"
|
||||
|
||||
/**
|
||||
* Terminates program abnormally.
|
||||
*
|
||||
* This function first tries to trigger your SIGABRT handler. If
|
||||
* there isn't one or execution resumes, then abort() terminates
|
||||
* the program using an escalating variety methods of increasing
|
||||
* brutality.
|
||||
* This function first tries to trigger your SIGABRT handler. If the
|
||||
* signal handler returns, then `signal(SIGABRT, SIG_DFL)` is called
|
||||
* before SIGABRT is raised again.
|
||||
*
|
||||
* @asyncsignalsafe
|
||||
* @noreturn
|
||||
*/
|
||||
privileged void abort(void) {
|
||||
sigset_t sm;
|
||||
sigfillset(&sm);
|
||||
sigdelset(&sm, SIGABRT);
|
||||
sigprocmask(SIG_SETMASK, &sm, 0);
|
||||
wontreturn void abort(void) {
|
||||
sigset_t m;
|
||||
sigemptyset(&m);
|
||||
sigaddset(&m, SIGABRT);
|
||||
sigprocmask(SIG_UNBLOCK, &m, 0);
|
||||
raise(SIGABRT);
|
||||
__restorewintty();
|
||||
_Exit(128 + SIGABRT);
|
||||
signal(SIGABRT, SIG_DFL);
|
||||
raise(SIGABRT);
|
||||
asm("hlt");
|
||||
unreachable;
|
||||
}
|
|
@ -65,7 +65,7 @@ void _exit(int) libcesque wontreturn;
|
|||
void _Exit(int) libcesque wontreturn;
|
||||
void _Exit1(int) libcesque wontreturn;
|
||||
void quick_exit(int) wontreturn;
|
||||
void abort(void) wontreturn noinstrument;
|
||||
void abort(void) wontreturn;
|
||||
int __cxa_atexit(void *, void *, void *) libcesque;
|
||||
int atfork(void *, void *) libcesque;
|
||||
int atexit(void (*)(void)) libcesque;
|
||||
|
|
|
@ -1,2 +1,2 @@
|
|||
.include "o/libc/sysv/macros.internal.inc"
|
||||
.scall sys_tkill,0x13e0771b121690c8,globl,hidden
|
||||
.scall sys_tkill,0x13e0771b121480c8,globl,hidden
|
||||
|
|
|
@ -533,7 +533,7 @@ syscon sicode SI_TKILL -6 0x80000000 0x010007 -1 -5 -6 # sent by tk
|
|||
syscon sicode SI_MESGQ -3 0x010005 0x010005 0x80000000 -4 -3 # sent by mq_notify(2); lool
|
||||
syscon sicode SI_ASYNCIO -4 0x010004 0x010004 0x80000000 -3 -4 # aio completion; no thank you
|
||||
syscon sicode SI_ASYNCNL -60 0x80000000 0x80000000 0x80000000 0x80000000 0x80000000 # aio completion for dns; the horror
|
||||
syscon sicode SI_KERNEL 0x80 0x80000000 0x010006 0x80000000 0x80000000 0x80 # wut; openbsd defines as si_code>0
|
||||
syscon sicode SI_KERNEL 128 0x80000000 0x010006 0x80000000 0x80000000 0x80 # wut; openbsd defines as si_code>0
|
||||
syscon sicode SI_NOINFO 32767 0x80000000 0 32767 32767 32767 # no signal specific info available
|
||||
syscon sicode CLD_EXITED 1 1 1 1 1 1 # SIGCHLD; child exited; unix consensus
|
||||
syscon sicode CLD_KILLED 2 2 2 2 2 2 # SIGCHLD; child terminated w/o core; unix consensus
|
||||
|
|
|
@ -98,7 +98,7 @@ scall __sys_wait4 0x1c100b007200703d 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
|
||||
scall sys_tkill 0x13e0771b121690c8 globl hidden # thr_kill() on freebsd; _lwp_kill() on netbsd; thrkill() on openbsd where arg3 should be 0; bsdthread_terminate() on XNU which only has 1 arg
|
||||
scall sys_tkill 0x13e0771b121480c8 globl hidden # thr_kill() on freebsd; _lwp_kill() on netbsd; thrkill() on openbsd where arg3 should be 0; __pthread_kill() on XNU
|
||||
scall sys_futex 0x0a6053fffffff0ca globl hidden # raises SIGSYS on NetBSD
|
||||
scall set_robust_list 0x0a7ffffffffff111 globl
|
||||
scall get_robust_list 0x0a8ffffffffff112 globl
|
||||
|
|
|
@ -12,6 +12,7 @@ int bsdthread_create(void *func, void *func_arg, void *stack, void *pthread,
|
|||
uint32_t flags);
|
||||
int bsdthread_terminate(void *stackaddr, size_t freesize, uint32_t port,
|
||||
uint32_t sem);
|
||||
int __pthread_kill(uint32_t port, int sig);
|
||||
int bsdthread_register(
|
||||
void (*threadstart)(void *pthread, int machport, void *(*func)(void *),
|
||||
void *arg, intptr_t *, unsigned),
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue