mirror of
https://github.com/jart/cosmopolitan.git
synced 2025-06-28 15:28:30 +00:00
Trim down MODE= linkage slightly
This commit is contained in:
parent
046c7ebd4a
commit
c95c9d9508
13 changed files with 315 additions and 283 deletions
|
@ -46,6 +46,6 @@ int kill(int pid, int sig) {
|
||||||
} else {
|
} else {
|
||||||
rc = sys_kill_nt(pid, sig);
|
rc = sys_kill_nt(pid, sig);
|
||||||
}
|
}
|
||||||
STRACE("kill(%d, %s) → %d% m", pid, strsignal(sig), rc);
|
STRACE("kill(%d, %G) → %d% m", pid, sig, rc);
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
|
@ -45,7 +45,7 @@ static textwindows inline bool HasWorkingConsole(void) {
|
||||||
*/
|
*/
|
||||||
int raise(int sig) {
|
int raise(int sig) {
|
||||||
int rc, event;
|
int rc, event;
|
||||||
STRACE("raise(%s) → [...]", strsignal(sig));
|
STRACE("raise(%G) → [...]", sig);
|
||||||
if (sig == SIGTRAP) {
|
if (sig == SIGTRAP) {
|
||||||
DebugBreak();
|
DebugBreak();
|
||||||
rc = 0;
|
rc = 0;
|
||||||
|
@ -75,6 +75,6 @@ int raise(int sig) {
|
||||||
rc = __sig_raise(sig, SI_USER);
|
rc = __sig_raise(sig, SI_USER);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
STRACE("[...] raise(%s) → %d% m", strsignal(sig), rc);
|
STRACE("[...] raise(%G) → %d% m", sig, rc);
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
248
libc/calls/sig.c
248
libc/calls/sig.c
|
@ -16,266 +16,20 @@
|
||||||
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
||||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||||
#include "libc/calls/calls.h"
|
|
||||||
#include "libc/calls/internal.h"
|
#include "libc/calls/internal.h"
|
||||||
#include "libc/calls/sig.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/intrin/cmpxchg.h"
|
|
||||||
#include "libc/intrin/lockcmpxchg.h"
|
|
||||||
#include "libc/intrin/spinlock.h"
|
#include "libc/intrin/spinlock.h"
|
||||||
#include "libc/macros.internal.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/consts/sig.h"
|
||||||
#include "libc/sysv/errfuns.h"
|
#include "libc/sysv/errfuns.h"
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @fileoverview UNIX signals for the New Technology.
|
* @fileoverview UNIX signals for the New Technology, Part 1.
|
||||||
* @threadsafe
|
* @threadsafe
|
||||||
*/
|
*/
|
||||||
|
|
||||||
struct Signal {
|
|
||||||
struct Signal *next;
|
|
||||||
bool used;
|
|
||||||
int sig;
|
|
||||||
int si_code;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct Signals {
|
|
||||||
sigset_t mask;
|
|
||||||
struct Signal *queue;
|
|
||||||
struct Signal mem[__SIG_QUEUE_LENGTH];
|
|
||||||
};
|
|
||||||
|
|
||||||
struct Signals __sig; // TODO(jart): Need TLS
|
struct Signals __sig; // TODO(jart): Need TLS
|
||||||
|
|
||||||
/**
|
|
||||||
* Allocates piece of memory for storing pending signal.
|
|
||||||
* @assume lock is held
|
|
||||||
*/
|
|
||||||
static textwindows struct Signal *__sig_alloc(void) {
|
|
||||||
int i;
|
|
||||||
struct Signal *res = 0;
|
|
||||||
for (i = 0; i < ARRAYLEN(__sig.mem); ++i) {
|
|
||||||
if (!__sig.mem[i].used) {
|
|
||||||
__sig.mem[i].used = true;
|
|
||||||
res = __sig.mem + i;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return res;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 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) {
|
|
||||||
cthread_spinlock(&__sig_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));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
cthread_spunlock(&__sig_lock);
|
|
||||||
} else {
|
|
||||||
res = 0;
|
|
||||||
}
|
|
||||||
return res;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Delivers signal to callback.
|
|
||||||
* @note called from main thread
|
|
||||||
* @return true if EINTR should be returned by caller
|
|
||||||
*/
|
|
||||||
static textwindows bool __sig_deliver(bool restartable, int sig, int si_code,
|
|
||||||
ucontext_t *ctx) {
|
|
||||||
unsigned rva, flags;
|
|
||||||
siginfo_t info, *infop;
|
|
||||||
STRACE("delivering %s", strsignal(sig));
|
|
||||||
|
|
||||||
// enter the signal
|
|
||||||
cthread_spinlock(&__sig_lock);
|
|
||||||
rva = __sighandrvas[sig];
|
|
||||||
flags = __sighandflags[sig];
|
|
||||||
if (~flags & SA_NODEFER) {
|
|
||||||
// by default we try to avoid reentering a signal handler. for
|
|
||||||
// example, if a sigsegv handler segfaults, then we'd want the
|
|
||||||
// second signal to just kill the process. doing this means we
|
|
||||||
// track state. that's bad if you want to longjmp() out of the
|
|
||||||
// signal handler. in that case you must use SA_NODEFER.
|
|
||||||
__sighandrvas[sig] = (int32_t)(intptr_t)SIG_DFL;
|
|
||||||
}
|
|
||||||
cthread_spunlock(&__sig_lock);
|
|
||||||
|
|
||||||
// setup the somewhat expensive information args
|
|
||||||
// only if they're requested by the user in sigaction()
|
|
||||||
if (flags & SA_SIGINFO) {
|
|
||||||
bzero(&info, sizeof(info));
|
|
||||||
info.si_signo = sig;
|
|
||||||
info.si_code = si_code;
|
|
||||||
infop = &info;
|
|
||||||
} else {
|
|
||||||
infop = 0;
|
|
||||||
ctx = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
// handover control to user
|
|
||||||
((sigaction_f)(_base + rva))(sig, infop, ctx);
|
|
||||||
|
|
||||||
// leave the signal
|
|
||||||
cthread_spinlock(&__sig_lock);
|
|
||||||
if (~flags & SA_NODEFER) {
|
|
||||||
_cmpxchg(__sighandrvas + sig, (int32_t)(intptr_t)SIG_DFL, rva);
|
|
||||||
}
|
|
||||||
if (flags & SA_RESETHAND) {
|
|
||||||
STRACE("resetting oneshot signal handler");
|
|
||||||
__sighandrvas[sig] = (int32_t)(intptr_t)SIG_DFL;
|
|
||||||
}
|
|
||||||
cthread_spunlock(&__sig_lock);
|
|
||||||
|
|
||||||
if (!restartable) {
|
|
||||||
return true; // always send EINTR for wait4(), poll(), etc.
|
|
||||||
} else if (flags & SA_RESTART) {
|
|
||||||
STRACE("restarting syscall on %s", strsignal(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;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Handles signal.
|
|
||||||
*
|
|
||||||
* @param restartable can be used to suppress true return if SA_RESTART
|
|
||||||
* @return true if signal was delivered
|
|
||||||
*/
|
|
||||||
textwindows bool __sig_handle(bool restartable, int sig, int si_code,
|
|
||||||
ucontext_t *ctx) {
|
|
||||||
bool delivered;
|
|
||||||
switch (__sighandrvas[sig]) {
|
|
||||||
case (intptr_t)SIG_DFL:
|
|
||||||
if (__sig_isfatal(sig)) {
|
|
||||||
STRACE("terminating on %s", strsignal(sig));
|
|
||||||
__restorewintty();
|
|
||||||
_Exit(128 + sig);
|
|
||||||
}
|
|
||||||
// fallthrough
|
|
||||||
case (intptr_t)SIG_IGN:
|
|
||||||
STRACE("ignoring %s", strsignal(sig));
|
|
||||||
delivered = false;
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
delivered = __sig_deliver(restartable, sig, si_code, ctx);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
return delivered;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Handles signal immediately if not blocked.
|
|
||||||
*
|
|
||||||
* @param restartable is for functions like read() but not poll()
|
|
||||||
* @return true if EINTR should be returned by caller
|
|
||||||
* @return 1 if delivered, 0 if enqueued, otherwise -1 w/ errno
|
|
||||||
* @note called from main thread
|
|
||||||
* @threadsafe
|
|
||||||
*/
|
|
||||||
textwindows int __sig_raise(int sig, int si_code) {
|
|
||||||
int rc;
|
|
||||||
int candeliver;
|
|
||||||
cthread_spinlock(&__sig_lock);
|
|
||||||
candeliver = !sigismember(&__sig.mask, sig);
|
|
||||||
cthread_spunlock(&__sig_lock);
|
|
||||||
switch (candeliver) {
|
|
||||||
case 1:
|
|
||||||
__sig_handle(false, sig, si_code, 0);
|
|
||||||
return 0;
|
|
||||||
case 0:
|
|
||||||
STRACE("%s is masked", strsignal(sig));
|
|
||||||
return __sig_add(sig, si_code);
|
|
||||||
default:
|
|
||||||
return -1; // sigismember() validates `sig`
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Enqueues generic signal for delivery on New Technology.
|
|
||||||
* @return 0 if enqueued, otherwise -1 w/ errno
|
|
||||||
* @threadsafe
|
|
||||||
*/
|
|
||||||
textwindows int __sig_add(int sig, int si_code) {
|
|
||||||
int rc;
|
|
||||||
struct Signal *mem;
|
|
||||||
if (1 <= sig && sig <= NSIG) {
|
|
||||||
STRACE("enqueuing %s", strsignal(sig));
|
|
||||||
cthread_spinlock(&__sig_lock);
|
|
||||||
if ((mem = __sig_alloc())) {
|
|
||||||
mem->sig = sig;
|
|
||||||
mem->si_code = si_code;
|
|
||||||
mem->next = __sig.queue;
|
|
||||||
__sig.queue = mem;
|
|
||||||
rc = 0;
|
|
||||||
} else {
|
|
||||||
rc = enomem();
|
|
||||||
}
|
|
||||||
cthread_spunlock(&__sig_lock);
|
|
||||||
} else {
|
|
||||||
rc = einval();
|
|
||||||
}
|
|
||||||
return rc;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 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())) {
|
|
||||||
delivered |= __sig_handle(restartable, sig->sig, sig->si_code, 0);
|
|
||||||
__sig_free(sig);
|
|
||||||
}
|
|
||||||
return delivered;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Changes signal mask for main thread.
|
* Changes signal mask for main thread.
|
||||||
* @return 0 on success, or -1 w/ errno
|
* @return 0 on success, or -1 w/ errno
|
||||||
|
|
|
@ -10,6 +10,21 @@
|
||||||
#if !(__ASSEMBLER__ + __LINKER__ + 0)
|
#if !(__ASSEMBLER__ + __LINKER__ + 0)
|
||||||
COSMOPOLITAN_C_START_
|
COSMOPOLITAN_C_START_
|
||||||
|
|
||||||
|
struct Signal {
|
||||||
|
struct Signal *next;
|
||||||
|
bool used;
|
||||||
|
int sig;
|
||||||
|
int si_code;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct Signals {
|
||||||
|
sigset_t mask;
|
||||||
|
struct Signal *queue;
|
||||||
|
struct Signal mem[__SIG_QUEUE_LENGTH];
|
||||||
|
};
|
||||||
|
|
||||||
|
extern struct Signals __sig; // TODO(jart): Need TLS
|
||||||
|
|
||||||
bool __sig_check(bool) hidden;
|
bool __sig_check(bool) hidden;
|
||||||
bool __sig_handle(bool, int, int, ucontext_t *) hidden;
|
bool __sig_handle(bool, int, int, ucontext_t *) hidden;
|
||||||
int __sig_add(int, int) hidden;
|
int __sig_add(int, int) hidden;
|
||||||
|
|
256
libc/calls/sig2.c
Normal file
256
libc/calls/sig2.c
Normal file
|
@ -0,0 +1,256 @@
|
||||||
|
/*-*- 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/calls/internal.h"
|
||||||
|
#include "libc/calls/sig.internal.h"
|
||||||
|
#include "libc/calls/sigbits.h"
|
||||||
|
#include "libc/calls/strace.internal.h"
|
||||||
|
#include "libc/intrin/cmpxchg.h"
|
||||||
|
#include "libc/intrin/spinlock.h"
|
||||||
|
#include "libc/macros.internal.h"
|
||||||
|
#include "libc/runtime/internal.h"
|
||||||
|
#include "libc/runtime/runtime.h"
|
||||||
|
#include "libc/sysv/consts/sa.h"
|
||||||
|
#include "libc/sysv/errfuns.h"
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @fileoverview UNIX signals for the New Technology, Part 2.
|
||||||
|
* @threadsafe
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Allocates piece of memory for storing pending signal.
|
||||||
|
* @assume lock is held
|
||||||
|
*/
|
||||||
|
static textwindows struct Signal *__sig_alloc(void) {
|
||||||
|
int i;
|
||||||
|
struct Signal *res = 0;
|
||||||
|
for (i = 0; i < ARRAYLEN(__sig.mem); ++i) {
|
||||||
|
if (!__sig.mem[i].used) {
|
||||||
|
__sig.mem[i].used = true;
|
||||||
|
res = __sig.mem + i;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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) {
|
||||||
|
cthread_spinlock(&__sig_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("%G is masked", res->sig);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
cthread_spunlock(&__sig_lock);
|
||||||
|
} else {
|
||||||
|
res = 0;
|
||||||
|
}
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Delivers signal to callback.
|
||||||
|
* @note called from main thread
|
||||||
|
* @return true if EINTR should be returned by caller
|
||||||
|
*/
|
||||||
|
static textwindows bool __sig_deliver(bool restartable, int sig, int si_code,
|
||||||
|
ucontext_t *ctx) {
|
||||||
|
unsigned rva, flags;
|
||||||
|
siginfo_t info, *infop;
|
||||||
|
STRACE("delivering %G", sig);
|
||||||
|
|
||||||
|
// enter the signal
|
||||||
|
cthread_spinlock(&__sig_lock);
|
||||||
|
rva = __sighandrvas[sig];
|
||||||
|
flags = __sighandflags[sig];
|
||||||
|
if (~flags & SA_NODEFER) {
|
||||||
|
// by default we try to avoid reentering a signal handler. for
|
||||||
|
// example, if a sigsegv handler segfaults, then we'd want the
|
||||||
|
// second signal to just kill the process. doing this means we
|
||||||
|
// track state. that's bad if you want to longjmp() out of the
|
||||||
|
// signal handler. in that case you must use SA_NODEFER.
|
||||||
|
__sighandrvas[sig] = (int32_t)(intptr_t)SIG_DFL;
|
||||||
|
}
|
||||||
|
cthread_spunlock(&__sig_lock);
|
||||||
|
|
||||||
|
// setup the somewhat expensive information args
|
||||||
|
// only if they're requested by the user in sigaction()
|
||||||
|
if (flags & SA_SIGINFO) {
|
||||||
|
bzero(&info, sizeof(info));
|
||||||
|
info.si_signo = sig;
|
||||||
|
info.si_code = si_code;
|
||||||
|
infop = &info;
|
||||||
|
} else {
|
||||||
|
infop = 0;
|
||||||
|
ctx = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// handover control to user
|
||||||
|
((sigaction_f)(_base + rva))(sig, infop, ctx);
|
||||||
|
|
||||||
|
// leave the signal
|
||||||
|
cthread_spinlock(&__sig_lock);
|
||||||
|
if (~flags & SA_NODEFER) {
|
||||||
|
_cmpxchg(__sighandrvas + sig, (int32_t)(intptr_t)SIG_DFL, rva);
|
||||||
|
}
|
||||||
|
if (flags & SA_RESETHAND) {
|
||||||
|
STRACE("resetting oneshot signal handler");
|
||||||
|
__sighandrvas[sig] = (int32_t)(intptr_t)SIG_DFL;
|
||||||
|
}
|
||||||
|
cthread_spunlock(&__sig_lock);
|
||||||
|
|
||||||
|
if (!restartable) {
|
||||||
|
return true; // always send EINTR for wait4(), poll(), etc.
|
||||||
|
} else if (flags & SA_RESTART) {
|
||||||
|
STRACE("restarting syscall on %G", 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;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handles signal.
|
||||||
|
*
|
||||||
|
* @param restartable can be used to suppress true return if SA_RESTART
|
||||||
|
* @return true if signal was delivered
|
||||||
|
*/
|
||||||
|
textwindows bool __sig_handle(bool restartable, int sig, int si_code,
|
||||||
|
ucontext_t *ctx) {
|
||||||
|
bool delivered;
|
||||||
|
switch (__sighandrvas[sig]) {
|
||||||
|
case (intptr_t)SIG_DFL:
|
||||||
|
if (__sig_isfatal(sig)) {
|
||||||
|
STRACE("terminating on %G", sig);
|
||||||
|
__restorewintty();
|
||||||
|
_Exit(128 + sig);
|
||||||
|
}
|
||||||
|
// fallthrough
|
||||||
|
case (intptr_t)SIG_IGN:
|
||||||
|
STRACE("ignoring %G", sig);
|
||||||
|
delivered = false;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
delivered = __sig_deliver(restartable, sig, si_code, ctx);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return delivered;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handles signal immediately if not blocked.
|
||||||
|
*
|
||||||
|
* @param restartable is for functions like read() but not poll()
|
||||||
|
* @return true if EINTR should be returned by caller
|
||||||
|
* @return 1 if delivered, 0 if enqueued, otherwise -1 w/ errno
|
||||||
|
* @note called from main thread
|
||||||
|
* @threadsafe
|
||||||
|
*/
|
||||||
|
textwindows int __sig_raise(int sig, int si_code) {
|
||||||
|
int rc;
|
||||||
|
int candeliver;
|
||||||
|
cthread_spinlock(&__sig_lock);
|
||||||
|
candeliver = !sigismember(&__sig.mask, sig);
|
||||||
|
cthread_spunlock(&__sig_lock);
|
||||||
|
switch (candeliver) {
|
||||||
|
case 1:
|
||||||
|
__sig_handle(false, sig, si_code, 0);
|
||||||
|
return 0;
|
||||||
|
case 0:
|
||||||
|
STRACE("%G is masked", sig);
|
||||||
|
return __sig_add(sig, si_code);
|
||||||
|
default:
|
||||||
|
return -1; // sigismember() validates `sig`
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Enqueues generic signal for delivery on New Technology.
|
||||||
|
* @return 0 if enqueued, otherwise -1 w/ errno
|
||||||
|
* @threadsafe
|
||||||
|
*/
|
||||||
|
textwindows int __sig_add(int sig, int si_code) {
|
||||||
|
int rc;
|
||||||
|
struct Signal *mem;
|
||||||
|
if (1 <= sig && sig <= NSIG) {
|
||||||
|
STRACE("enqueuing %G", sig);
|
||||||
|
cthread_spinlock(&__sig_lock);
|
||||||
|
if ((mem = __sig_alloc())) {
|
||||||
|
mem->sig = sig;
|
||||||
|
mem->si_code = si_code;
|
||||||
|
mem->next = __sig.queue;
|
||||||
|
__sig.queue = mem;
|
||||||
|
rc = 0;
|
||||||
|
} else {
|
||||||
|
rc = enomem();
|
||||||
|
}
|
||||||
|
cthread_spunlock(&__sig_lock);
|
||||||
|
} else {
|
||||||
|
rc = einval();
|
||||||
|
}
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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())) {
|
||||||
|
delivered |= __sig_handle(restartable, sig->sig, sig->si_code, 0);
|
||||||
|
__sig_free(sig);
|
||||||
|
}
|
||||||
|
return delivered;
|
||||||
|
}
|
|
@ -301,7 +301,7 @@ int(sigaction)(int sig, const struct sigaction *act, struct sigaction *oldact) {
|
||||||
} else {
|
} else {
|
||||||
rc = __sigaction(sig, act, oldact);
|
rc = __sigaction(sig, act, oldact);
|
||||||
}
|
}
|
||||||
STRACE("sigaction(%s, %s, [%s]) → %d% m", strsignal(sig),
|
STRACE("sigaction(%G, %s, [%s]) → %d% m", sig,
|
||||||
__strace_sigaction(buf[0], sizeof(buf[0]), 0, act),
|
__strace_sigaction(buf[0], sizeof(buf[0]), 0, act),
|
||||||
__strace_sigaction(buf[1], sizeof(buf[1]), rc, oldact), rc);
|
__strace_sigaction(buf[1], sizeof(buf[1]), rc, oldact), rc);
|
||||||
return rc;
|
return rc;
|
||||||
|
|
|
@ -498,6 +498,21 @@ privileged static size_t kformat(char *b, size_t n, const char *fmt, va_list va,
|
||||||
goto FormatDecimal;
|
goto FormatDecimal;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
case 'G':
|
||||||
|
x = va_arg(va, int);
|
||||||
|
if (weaken(strsignal)) {
|
||||||
|
s = weaken(strsignal)(x);
|
||||||
|
goto FormatString;
|
||||||
|
} else {
|
||||||
|
if (p + 3 <= e) {
|
||||||
|
p[0] = 'S';
|
||||||
|
p[1] = 'I';
|
||||||
|
p[2] = 'G';
|
||||||
|
}
|
||||||
|
p += 3;
|
||||||
|
goto FormatDecimal;
|
||||||
|
}
|
||||||
|
|
||||||
case 'n':
|
case 'n':
|
||||||
// nonstandard %n specifier
|
// nonstandard %n specifier
|
||||||
// used to print newlines that work in raw terminal modes
|
// used to print newlines that work in raw terminal modes
|
||||||
|
@ -823,6 +838,7 @@ privileged void kvprintf(const char *fmt, va_list v) {
|
||||||
* - `u` unsigned
|
* - `u` unsigned
|
||||||
* - `r` carriage
|
* - `r` carriage
|
||||||
* - `m` strerror
|
* - `m` strerror
|
||||||
|
* - `G` strsignal
|
||||||
* - `X` uppercase
|
* - `X` uppercase
|
||||||
* - `T` timestamp
|
* - `T` timestamp
|
||||||
* - `x` hexadecimal
|
* - `x` hexadecimal
|
||||||
|
|
|
@ -41,6 +41,7 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
STATIC_YOINK("strerror_r"); /* for kprintf %m */
|
STATIC_YOINK("strerror_r"); /* for kprintf %m */
|
||||||
|
STATIC_YOINK("strsignal"); /* for kprintf %G */
|
||||||
|
|
||||||
static const char kGregOrder[17] forcealign(1) = {
|
static const char kGregOrder[17] forcealign(1) = {
|
||||||
13, 11, 8, 14, 12, 9, 10, 15, 16, 0, 1, 2, 3, 4, 5, 6, 7,
|
13, 11, 8, 14, 12, 9, 10, 15, 16, 0, 1, 2, 3, 4, 5, 6, 7,
|
||||||
|
@ -54,29 +55,8 @@ static const char kGregNames[17][4] forcealign(1) = {
|
||||||
static const char kCpuFlags[12] forcealign(1) = "CVPRAKZSTIDO";
|
static const char kCpuFlags[12] forcealign(1) = "CVPRAKZSTIDO";
|
||||||
static const char kFpuExceptions[6] forcealign(1) = "IDZOUP";
|
static const char kFpuExceptions[6] forcealign(1) = "IDZOUP";
|
||||||
|
|
||||||
/* <SYNC-LIST>: showcrashreports.c, oncrashthunks.S, oncrash.c */
|
|
||||||
int kCrashSigs[7];
|
int kCrashSigs[7];
|
||||||
struct sigaction g_oldcrashacts[7];
|
struct sigaction g_oldcrashacts[7];
|
||||||
static const char kCrashSigNames[7][5] forcealign(1) = {
|
|
||||||
"QUIT", //
|
|
||||||
"FPE", //
|
|
||||||
"ILL", //
|
|
||||||
"SEGV", //
|
|
||||||
"TRAP", //
|
|
||||||
"ABRT", //
|
|
||||||
"BUS", //
|
|
||||||
};
|
|
||||||
/* </SYNC-LIST>: showcrashreports.c, oncrashthunks.S, oncrash.c */
|
|
||||||
|
|
||||||
static relegated noinstrument const char *TinyStrSignal(int sig) {
|
|
||||||
size_t i;
|
|
||||||
for (i = 0; i < ARRAYLEN(kCrashSigs); ++i) {
|
|
||||||
if (kCrashSigs[i] && sig == kCrashSigs[i]) {
|
|
||||||
return kCrashSigNames[i];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return "???";
|
|
||||||
}
|
|
||||||
|
|
||||||
relegated static void ShowFunctionCalls(ucontext_t *ctx) {
|
relegated static void ShowFunctionCalls(ucontext_t *ctx) {
|
||||||
struct StackFrame *bp;
|
struct StackFrame *bp;
|
||||||
|
@ -222,12 +202,11 @@ relegated void ShowCrashReport(int err, int sig, struct siginfo *si,
|
||||||
uname(&names);
|
uname(&names);
|
||||||
p = buf;
|
p = buf;
|
||||||
errno = err;
|
errno = err;
|
||||||
kprintf("%n%serror%s: Uncaught SIG%s (%s) on %s pid %d%n"
|
kprintf("%n%serror%s: Uncaught %G (%s) on %s pid %d%n"
|
||||||
" %s%n"
|
" %s%n"
|
||||||
" %m%n"
|
" %m%n"
|
||||||
" %s %s %s %s%n",
|
" %s %s %s %s%n",
|
||||||
!__nocolor ? "\e[30;101m" : "", !__nocolor ? "\e[0m" : "",
|
!__nocolor ? "\e[30;101m" : "", !__nocolor ? "\e[0m" : "", sig,
|
||||||
TinyStrSignal(sig),
|
|
||||||
(ctx && (ctx->uc_mcontext.rsp >= GetStaticStackAddr(0) &&
|
(ctx && (ctx->uc_mcontext.rsp >= GetStaticStackAddr(0) &&
|
||||||
ctx->uc_mcontext.rsp <= GetStaticStackAddr(0) + PAGESIZE))
|
ctx->uc_mcontext.rsp <= GetStaticStackAddr(0) + PAGESIZE))
|
||||||
? "Stack Overflow"
|
? "Stack Overflow"
|
||||||
|
@ -269,13 +248,13 @@ static wontreturn relegated noinstrument void __minicrash(int sig,
|
||||||
const char *kind) {
|
const char *kind) {
|
||||||
kprintf("%n"
|
kprintf("%n"
|
||||||
"%n"
|
"%n"
|
||||||
"CRASHED %s WITH SIG%s%n"
|
"CRASHED %s WITH %G%n"
|
||||||
"%s%n"
|
"%s%n"
|
||||||
"RIP %x%n"
|
"RIP %x%n"
|
||||||
"RSP %x%n"
|
"RSP %x%n"
|
||||||
"RBP %x%n"
|
"RBP %x%n"
|
||||||
"%n",
|
"%n",
|
||||||
kind, TinyStrSignal(sig), __argv[0], ctx ? ctx->uc_mcontext.rip : 0,
|
kind, sig, __argv[0], ctx ? ctx->uc_mcontext.rip : 0,
|
||||||
ctx ? ctx->uc_mcontext.rsp : 0, ctx ? ctx->uc_mcontext.rbp : 0);
|
ctx ? ctx->uc_mcontext.rsp : 0, ctx ? ctx->uc_mcontext.rbp : 0);
|
||||||
__restorewintty();
|
__restorewintty();
|
||||||
_Exit(119);
|
_Exit(119);
|
||||||
|
|
|
@ -1,2 +1,15 @@
|
||||||
.include "o/libc/nt/codegen.inc"
|
.include "o/libc/nt/codegen.inc"
|
||||||
.imp kernel32,__imp_SetDefaultDllDirectories,SetDefaultDllDirectories,0
|
.imp kernel32,__imp_SetDefaultDllDirectories,SetDefaultDllDirectories,0
|
||||||
|
|
||||||
|
.text.windows
|
||||||
|
SetDefaultDllDirectories:
|
||||||
|
push %rbp
|
||||||
|
mov %rsp,%rbp
|
||||||
|
.profilable
|
||||||
|
mov %rdi,%rcx
|
||||||
|
sub $32,%rsp
|
||||||
|
call *__imp_SetDefaultDllDirectories(%rip)
|
||||||
|
leave
|
||||||
|
ret
|
||||||
|
.endfn SetDefaultDllDirectories,globl
|
||||||
|
.previous
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
.include "o/libc/nt/codegen.inc"
|
.include "o/libc/nt/codegen.inc"
|
||||||
.imp kernel32,__imp_SetLastError,SetLastError,1336
|
.imp kernel32,__imp_SetLastError,SetLastError,0
|
||||||
|
|
||||||
.text.windows
|
.text.windows
|
||||||
SetLastError:
|
SetLastError:
|
||||||
|
|
|
@ -1103,7 +1103,7 @@ imp 'SetCurrentDirectory' SetCurrentDirectoryW kernel32 0 1
|
||||||
imp 'SetCurrentDirectoryA' SetCurrentDirectoryA kernel32 0 1
|
imp 'SetCurrentDirectoryA' SetCurrentDirectoryA kernel32 0 1
|
||||||
imp 'SetDefaultCommConfig' SetDefaultCommConfigW kernel32 1298
|
imp 'SetDefaultCommConfig' SetDefaultCommConfigW kernel32 1298
|
||||||
imp 'SetDefaultCommConfigA' SetDefaultCommConfigA kernel32 1297
|
imp 'SetDefaultCommConfigA' SetDefaultCommConfigA kernel32 1297
|
||||||
imp 'SetDefaultDllDirectories' SetDefaultDllDirectories kernel32 0 1, Windows 8+, KB2533623 on Windows 7
|
imp 'SetDefaultDllDirectories' SetDefaultDllDirectories kernel32 0 1 # Windows 8+, KB2533623 on Windows 7
|
||||||
imp 'SetDllDirectory' SetDllDirectoryW kernel32 1301
|
imp 'SetDllDirectory' SetDllDirectoryW kernel32 1301
|
||||||
imp 'SetDllDirectoryA' SetDllDirectoryA kernel32 1300
|
imp 'SetDllDirectoryA' SetDllDirectoryA kernel32 1300
|
||||||
imp 'SetDynamicTimeZoneInformation' SetDynamicTimeZoneInformation kernel32 0
|
imp 'SetDynamicTimeZoneInformation' SetDynamicTimeZoneInformation kernel32 0
|
||||||
|
@ -1137,7 +1137,7 @@ imp 'SetHandleCount' SetHandleCount kernel32 0 1
|
||||||
imp 'SetHandleInformation' SetHandleInformation kernel32 0 3
|
imp 'SetHandleInformation' SetHandleInformation kernel32 0 3
|
||||||
imp 'SetInformationJobObject' SetInformationJobObject kernel32 1333
|
imp 'SetInformationJobObject' SetInformationJobObject kernel32 1333
|
||||||
imp 'SetIoRateControlInformationJobObject' SetIoRateControlInformationJobObject kernel32 1334
|
imp 'SetIoRateControlInformationJobObject' SetIoRateControlInformationJobObject kernel32 1334
|
||||||
imp 'SetLastError' SetLastError kernel32 1336 1
|
imp 'SetLastError' SetLastError kernel32 0 1
|
||||||
imp 'SetLocalPrimaryComputerName' SetLocalPrimaryComputerNameW kernel32 1338
|
imp 'SetLocalPrimaryComputerName' SetLocalPrimaryComputerNameW kernel32 1338
|
||||||
imp 'SetLocalPrimaryComputerNameA' SetLocalPrimaryComputerNameA kernel32 1337
|
imp 'SetLocalPrimaryComputerNameA' SetLocalPrimaryComputerNameA kernel32 1337
|
||||||
imp 'SetLocalTime' SetLocalTime kernel32 0
|
imp 'SetLocalTime' SetLocalTime kernel32 0
|
||||||
|
|
|
@ -109,7 +109,6 @@ noasan int munmap(void *v, size_t n) {
|
||||||
} else {
|
} else {
|
||||||
rc = -1;
|
rc = -1;
|
||||||
}
|
}
|
||||||
STRACE("munmap(%.12p, %'zu) → %d %s", p, n, rc,
|
STRACE("munmap(%.12p, %'zu) → %d% m", p, n, rc);
|
||||||
rc == -1 ? strerror(errno) : "");
|
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
|
@ -151,7 +151,7 @@ textstartup void __printargs(void) {
|
||||||
PRINT("BLOCKED SIGNALS {%#lx, %#lx}", ss.__bits[0], ss.__bits[1]);
|
PRINT("BLOCKED SIGNALS {%#lx, %#lx}", ss.__bits[0], ss.__bits[1]);
|
||||||
for (i = 0; i < 32; ++i) {
|
for (i = 0; i < 32; ++i) {
|
||||||
if (ss.__bits[0] & (1u << i)) {
|
if (ss.__bits[0] & (1u << i)) {
|
||||||
PRINT(" ☼ %s (%d)", strsignal(i + 1), i + 1);
|
PRINT(" ☼ %G (%d)", i + 1, i + 1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue