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:
Justine Tunney 2022-09-03 18:12:01 -07:00
parent c5659b93f8
commit c5c4dfcd21
12 changed files with 293 additions and 63 deletions

View file

@ -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;