162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * Copyright (C) 2015 Anton Ivanov (aivanov@{brocade.com,kot-begemot.co.uk})
462306a36Sopenharmony_ci * Copyright (C) 2015 Thomas Meyer (thomas@m3y3r.de)
562306a36Sopenharmony_ci * Copyright (C) 2004 PathScale, Inc
662306a36Sopenharmony_ci * Copyright (C) 2004 - 2007 Jeff Dike (jdike@{addtoit,linux.intel}.com)
762306a36Sopenharmony_ci */
862306a36Sopenharmony_ci
962306a36Sopenharmony_ci#include <stdlib.h>
1062306a36Sopenharmony_ci#include <stdarg.h>
1162306a36Sopenharmony_ci#include <errno.h>
1262306a36Sopenharmony_ci#include <signal.h>
1362306a36Sopenharmony_ci#include <string.h>
1462306a36Sopenharmony_ci#include <strings.h>
1562306a36Sopenharmony_ci#include <as-layout.h>
1662306a36Sopenharmony_ci#include <kern_util.h>
1762306a36Sopenharmony_ci#include <os.h>
1862306a36Sopenharmony_ci#include <sysdep/mcontext.h>
1962306a36Sopenharmony_ci#include <um_malloc.h>
2062306a36Sopenharmony_ci#include <sys/ucontext.h>
2162306a36Sopenharmony_ci#include <timetravel.h>
2262306a36Sopenharmony_ci
2362306a36Sopenharmony_civoid (*sig_info[NSIG])(int, struct siginfo *, struct uml_pt_regs *) = {
2462306a36Sopenharmony_ci	[SIGTRAP]	= relay_signal,
2562306a36Sopenharmony_ci	[SIGFPE]	= relay_signal,
2662306a36Sopenharmony_ci	[SIGILL]	= relay_signal,
2762306a36Sopenharmony_ci	[SIGWINCH]	= winch,
2862306a36Sopenharmony_ci	[SIGBUS]	= bus_handler,
2962306a36Sopenharmony_ci	[SIGSEGV]	= segv_handler,
3062306a36Sopenharmony_ci	[SIGIO]		= sigio_handler,
3162306a36Sopenharmony_ci};
3262306a36Sopenharmony_ci
3362306a36Sopenharmony_cistatic void sig_handler_common(int sig, struct siginfo *si, mcontext_t *mc)
3462306a36Sopenharmony_ci{
3562306a36Sopenharmony_ci	struct uml_pt_regs r;
3662306a36Sopenharmony_ci	int save_errno = errno;
3762306a36Sopenharmony_ci
3862306a36Sopenharmony_ci	r.is_user = 0;
3962306a36Sopenharmony_ci	if (sig == SIGSEGV) {
4062306a36Sopenharmony_ci		/* For segfaults, we want the data from the sigcontext. */
4162306a36Sopenharmony_ci		get_regs_from_mc(&r, mc);
4262306a36Sopenharmony_ci		GET_FAULTINFO_FROM_MC(r.faultinfo, mc);
4362306a36Sopenharmony_ci	}
4462306a36Sopenharmony_ci
4562306a36Sopenharmony_ci	/* enable signals if sig isn't IRQ signal */
4662306a36Sopenharmony_ci	if ((sig != SIGIO) && (sig != SIGWINCH))
4762306a36Sopenharmony_ci		unblock_signals_trace();
4862306a36Sopenharmony_ci
4962306a36Sopenharmony_ci	(*sig_info[sig])(sig, si, &r);
5062306a36Sopenharmony_ci
5162306a36Sopenharmony_ci	errno = save_errno;
5262306a36Sopenharmony_ci}
5362306a36Sopenharmony_ci
5462306a36Sopenharmony_ci/*
5562306a36Sopenharmony_ci * These are the asynchronous signals.  SIGPROF is excluded because we want to
5662306a36Sopenharmony_ci * be able to profile all of UML, not just the non-critical sections.  If
5762306a36Sopenharmony_ci * profiling is not thread-safe, then that is not my problem.  We can disable
5862306a36Sopenharmony_ci * profiling when SMP is enabled in that case.
5962306a36Sopenharmony_ci */
6062306a36Sopenharmony_ci#define SIGIO_BIT 0
6162306a36Sopenharmony_ci#define SIGIO_MASK (1 << SIGIO_BIT)
6262306a36Sopenharmony_ci
6362306a36Sopenharmony_ci#define SIGALRM_BIT 1
6462306a36Sopenharmony_ci#define SIGALRM_MASK (1 << SIGALRM_BIT)
6562306a36Sopenharmony_ci
6662306a36Sopenharmony_ciint signals_enabled;
6762306a36Sopenharmony_ci#ifdef UML_CONFIG_UML_TIME_TRAVEL_SUPPORT
6862306a36Sopenharmony_cistatic int signals_blocked;
6962306a36Sopenharmony_ci#else
7062306a36Sopenharmony_ci#define signals_blocked 0
7162306a36Sopenharmony_ci#endif
7262306a36Sopenharmony_cistatic unsigned int signals_pending;
7362306a36Sopenharmony_cistatic unsigned int signals_active = 0;
7462306a36Sopenharmony_ci
7562306a36Sopenharmony_civoid sig_handler(int sig, struct siginfo *si, mcontext_t *mc)
7662306a36Sopenharmony_ci{
7762306a36Sopenharmony_ci	int enabled = signals_enabled;
7862306a36Sopenharmony_ci
7962306a36Sopenharmony_ci	if ((signals_blocked || !enabled) && (sig == SIGIO)) {
8062306a36Sopenharmony_ci		/*
8162306a36Sopenharmony_ci		 * In TT_MODE_EXTERNAL, need to still call time-travel
8262306a36Sopenharmony_ci		 * handlers unless signals are also blocked for the
8362306a36Sopenharmony_ci		 * external time message processing. This will mark
8462306a36Sopenharmony_ci		 * signals_pending by itself (only if necessary.)
8562306a36Sopenharmony_ci		 */
8662306a36Sopenharmony_ci		if (!signals_blocked && time_travel_mode == TT_MODE_EXTERNAL)
8762306a36Sopenharmony_ci			sigio_run_timetravel_handlers();
8862306a36Sopenharmony_ci		else
8962306a36Sopenharmony_ci			signals_pending |= SIGIO_MASK;
9062306a36Sopenharmony_ci		return;
9162306a36Sopenharmony_ci	}
9262306a36Sopenharmony_ci
9362306a36Sopenharmony_ci	block_signals_trace();
9462306a36Sopenharmony_ci
9562306a36Sopenharmony_ci	sig_handler_common(sig, si, mc);
9662306a36Sopenharmony_ci
9762306a36Sopenharmony_ci	um_set_signals_trace(enabled);
9862306a36Sopenharmony_ci}
9962306a36Sopenharmony_ci
10062306a36Sopenharmony_cistatic void timer_real_alarm_handler(mcontext_t *mc)
10162306a36Sopenharmony_ci{
10262306a36Sopenharmony_ci	struct uml_pt_regs regs;
10362306a36Sopenharmony_ci
10462306a36Sopenharmony_ci	if (mc != NULL)
10562306a36Sopenharmony_ci		get_regs_from_mc(&regs, mc);
10662306a36Sopenharmony_ci	else
10762306a36Sopenharmony_ci		memset(&regs, 0, sizeof(regs));
10862306a36Sopenharmony_ci	timer_handler(SIGALRM, NULL, &regs);
10962306a36Sopenharmony_ci}
11062306a36Sopenharmony_ci
11162306a36Sopenharmony_civoid timer_alarm_handler(int sig, struct siginfo *unused_si, mcontext_t *mc)
11262306a36Sopenharmony_ci{
11362306a36Sopenharmony_ci	int enabled;
11462306a36Sopenharmony_ci
11562306a36Sopenharmony_ci	enabled = signals_enabled;
11662306a36Sopenharmony_ci	if (!signals_enabled) {
11762306a36Sopenharmony_ci		signals_pending |= SIGALRM_MASK;
11862306a36Sopenharmony_ci		return;
11962306a36Sopenharmony_ci	}
12062306a36Sopenharmony_ci
12162306a36Sopenharmony_ci	block_signals_trace();
12262306a36Sopenharmony_ci
12362306a36Sopenharmony_ci	signals_active |= SIGALRM_MASK;
12462306a36Sopenharmony_ci
12562306a36Sopenharmony_ci	timer_real_alarm_handler(mc);
12662306a36Sopenharmony_ci
12762306a36Sopenharmony_ci	signals_active &= ~SIGALRM_MASK;
12862306a36Sopenharmony_ci
12962306a36Sopenharmony_ci	um_set_signals_trace(enabled);
13062306a36Sopenharmony_ci}
13162306a36Sopenharmony_ci
13262306a36Sopenharmony_civoid deliver_alarm(void) {
13362306a36Sopenharmony_ci    timer_alarm_handler(SIGALRM, NULL, NULL);
13462306a36Sopenharmony_ci}
13562306a36Sopenharmony_ci
13662306a36Sopenharmony_civoid timer_set_signal_handler(void)
13762306a36Sopenharmony_ci{
13862306a36Sopenharmony_ci	set_handler(SIGALRM);
13962306a36Sopenharmony_ci}
14062306a36Sopenharmony_ci
14162306a36Sopenharmony_civoid set_sigstack(void *sig_stack, int size)
14262306a36Sopenharmony_ci{
14362306a36Sopenharmony_ci	stack_t stack = {
14462306a36Sopenharmony_ci		.ss_flags = 0,
14562306a36Sopenharmony_ci		.ss_sp = sig_stack,
14662306a36Sopenharmony_ci		.ss_size = size
14762306a36Sopenharmony_ci	};
14862306a36Sopenharmony_ci
14962306a36Sopenharmony_ci	if (sigaltstack(&stack, NULL) != 0)
15062306a36Sopenharmony_ci		panic("enabling signal stack failed, errno = %d\n", errno);
15162306a36Sopenharmony_ci}
15262306a36Sopenharmony_ci
15362306a36Sopenharmony_cistatic void sigusr1_handler(int sig, struct siginfo *unused_si, mcontext_t *mc)
15462306a36Sopenharmony_ci{
15562306a36Sopenharmony_ci	uml_pm_wake();
15662306a36Sopenharmony_ci}
15762306a36Sopenharmony_ci
15862306a36Sopenharmony_civoid register_pm_wake_signal(void)
15962306a36Sopenharmony_ci{
16062306a36Sopenharmony_ci	set_handler(SIGUSR1);
16162306a36Sopenharmony_ci}
16262306a36Sopenharmony_ci
16362306a36Sopenharmony_cistatic void (*handlers[_NSIG])(int sig, struct siginfo *si, mcontext_t *mc) = {
16462306a36Sopenharmony_ci	[SIGSEGV] = sig_handler,
16562306a36Sopenharmony_ci	[SIGBUS] = sig_handler,
16662306a36Sopenharmony_ci	[SIGILL] = sig_handler,
16762306a36Sopenharmony_ci	[SIGFPE] = sig_handler,
16862306a36Sopenharmony_ci	[SIGTRAP] = sig_handler,
16962306a36Sopenharmony_ci
17062306a36Sopenharmony_ci	[SIGIO] = sig_handler,
17162306a36Sopenharmony_ci	[SIGWINCH] = sig_handler,
17262306a36Sopenharmony_ci	[SIGALRM] = timer_alarm_handler,
17362306a36Sopenharmony_ci
17462306a36Sopenharmony_ci	[SIGUSR1] = sigusr1_handler,
17562306a36Sopenharmony_ci};
17662306a36Sopenharmony_ci
17762306a36Sopenharmony_cistatic void hard_handler(int sig, siginfo_t *si, void *p)
17862306a36Sopenharmony_ci{
17962306a36Sopenharmony_ci	ucontext_t *uc = p;
18062306a36Sopenharmony_ci	mcontext_t *mc = &uc->uc_mcontext;
18162306a36Sopenharmony_ci	unsigned long pending = 1UL << sig;
18262306a36Sopenharmony_ci
18362306a36Sopenharmony_ci	do {
18462306a36Sopenharmony_ci		int nested, bail;
18562306a36Sopenharmony_ci
18662306a36Sopenharmony_ci		/*
18762306a36Sopenharmony_ci		 * pending comes back with one bit set for each
18862306a36Sopenharmony_ci		 * interrupt that arrived while setting up the stack,
18962306a36Sopenharmony_ci		 * plus a bit for this interrupt, plus the zero bit is
19062306a36Sopenharmony_ci		 * set if this is a nested interrupt.
19162306a36Sopenharmony_ci		 * If bail is true, then we interrupted another
19262306a36Sopenharmony_ci		 * handler setting up the stack.  In this case, we
19362306a36Sopenharmony_ci		 * have to return, and the upper handler will deal
19462306a36Sopenharmony_ci		 * with this interrupt.
19562306a36Sopenharmony_ci		 */
19662306a36Sopenharmony_ci		bail = to_irq_stack(&pending);
19762306a36Sopenharmony_ci		if (bail)
19862306a36Sopenharmony_ci			return;
19962306a36Sopenharmony_ci
20062306a36Sopenharmony_ci		nested = pending & 1;
20162306a36Sopenharmony_ci		pending &= ~1;
20262306a36Sopenharmony_ci
20362306a36Sopenharmony_ci		while ((sig = ffs(pending)) != 0){
20462306a36Sopenharmony_ci			sig--;
20562306a36Sopenharmony_ci			pending &= ~(1 << sig);
20662306a36Sopenharmony_ci			(*handlers[sig])(sig, (struct siginfo *)si, mc);
20762306a36Sopenharmony_ci		}
20862306a36Sopenharmony_ci
20962306a36Sopenharmony_ci		/*
21062306a36Sopenharmony_ci		 * Again, pending comes back with a mask of signals
21162306a36Sopenharmony_ci		 * that arrived while tearing down the stack.  If this
21262306a36Sopenharmony_ci		 * is non-zero, we just go back, set up the stack
21362306a36Sopenharmony_ci		 * again, and handle the new interrupts.
21462306a36Sopenharmony_ci		 */
21562306a36Sopenharmony_ci		if (!nested)
21662306a36Sopenharmony_ci			pending = from_irq_stack(nested);
21762306a36Sopenharmony_ci	} while (pending);
21862306a36Sopenharmony_ci}
21962306a36Sopenharmony_ci
22062306a36Sopenharmony_civoid set_handler(int sig)
22162306a36Sopenharmony_ci{
22262306a36Sopenharmony_ci	struct sigaction action;
22362306a36Sopenharmony_ci	int flags = SA_SIGINFO | SA_ONSTACK;
22462306a36Sopenharmony_ci	sigset_t sig_mask;
22562306a36Sopenharmony_ci
22662306a36Sopenharmony_ci	action.sa_sigaction = hard_handler;
22762306a36Sopenharmony_ci
22862306a36Sopenharmony_ci	/* block irq ones */
22962306a36Sopenharmony_ci	sigemptyset(&action.sa_mask);
23062306a36Sopenharmony_ci	sigaddset(&action.sa_mask, SIGIO);
23162306a36Sopenharmony_ci	sigaddset(&action.sa_mask, SIGWINCH);
23262306a36Sopenharmony_ci	sigaddset(&action.sa_mask, SIGALRM);
23362306a36Sopenharmony_ci
23462306a36Sopenharmony_ci	if (sig == SIGSEGV)
23562306a36Sopenharmony_ci		flags |= SA_NODEFER;
23662306a36Sopenharmony_ci
23762306a36Sopenharmony_ci	if (sigismember(&action.sa_mask, sig))
23862306a36Sopenharmony_ci		flags |= SA_RESTART; /* if it's an irq signal */
23962306a36Sopenharmony_ci
24062306a36Sopenharmony_ci	action.sa_flags = flags;
24162306a36Sopenharmony_ci	action.sa_restorer = NULL;
24262306a36Sopenharmony_ci	if (sigaction(sig, &action, NULL) < 0)
24362306a36Sopenharmony_ci		panic("sigaction failed - errno = %d\n", errno);
24462306a36Sopenharmony_ci
24562306a36Sopenharmony_ci	sigemptyset(&sig_mask);
24662306a36Sopenharmony_ci	sigaddset(&sig_mask, sig);
24762306a36Sopenharmony_ci	if (sigprocmask(SIG_UNBLOCK, &sig_mask, NULL) < 0)
24862306a36Sopenharmony_ci		panic("sigprocmask failed - errno = %d\n", errno);
24962306a36Sopenharmony_ci}
25062306a36Sopenharmony_ci
25162306a36Sopenharmony_civoid send_sigio_to_self(void)
25262306a36Sopenharmony_ci{
25362306a36Sopenharmony_ci	kill(os_getpid(), SIGIO);
25462306a36Sopenharmony_ci}
25562306a36Sopenharmony_ci
25662306a36Sopenharmony_ciint change_sig(int signal, int on)
25762306a36Sopenharmony_ci{
25862306a36Sopenharmony_ci	sigset_t sigset;
25962306a36Sopenharmony_ci
26062306a36Sopenharmony_ci	sigemptyset(&sigset);
26162306a36Sopenharmony_ci	sigaddset(&sigset, signal);
26262306a36Sopenharmony_ci	if (sigprocmask(on ? SIG_UNBLOCK : SIG_BLOCK, &sigset, NULL) < 0)
26362306a36Sopenharmony_ci		return -errno;
26462306a36Sopenharmony_ci
26562306a36Sopenharmony_ci	return 0;
26662306a36Sopenharmony_ci}
26762306a36Sopenharmony_ci
26862306a36Sopenharmony_civoid block_signals(void)
26962306a36Sopenharmony_ci{
27062306a36Sopenharmony_ci	signals_enabled = 0;
27162306a36Sopenharmony_ci	/*
27262306a36Sopenharmony_ci	 * This must return with signals disabled, so this barrier
27362306a36Sopenharmony_ci	 * ensures that writes are flushed out before the return.
27462306a36Sopenharmony_ci	 * This might matter if gcc figures out how to inline this and
27562306a36Sopenharmony_ci	 * decides to shuffle this code into the caller.
27662306a36Sopenharmony_ci	 */
27762306a36Sopenharmony_ci	barrier();
27862306a36Sopenharmony_ci}
27962306a36Sopenharmony_ci
28062306a36Sopenharmony_civoid unblock_signals(void)
28162306a36Sopenharmony_ci{
28262306a36Sopenharmony_ci	int save_pending;
28362306a36Sopenharmony_ci
28462306a36Sopenharmony_ci	if (signals_enabled == 1)
28562306a36Sopenharmony_ci		return;
28662306a36Sopenharmony_ci
28762306a36Sopenharmony_ci	signals_enabled = 1;
28862306a36Sopenharmony_ci#ifdef UML_CONFIG_UML_TIME_TRAVEL_SUPPORT
28962306a36Sopenharmony_ci	deliver_time_travel_irqs();
29062306a36Sopenharmony_ci#endif
29162306a36Sopenharmony_ci
29262306a36Sopenharmony_ci	/*
29362306a36Sopenharmony_ci	 * We loop because the IRQ handler returns with interrupts off.  So,
29462306a36Sopenharmony_ci	 * interrupts may have arrived and we need to re-enable them and
29562306a36Sopenharmony_ci	 * recheck signals_pending.
29662306a36Sopenharmony_ci	 */
29762306a36Sopenharmony_ci	while (1) {
29862306a36Sopenharmony_ci		/*
29962306a36Sopenharmony_ci		 * Save and reset save_pending after enabling signals.  This
30062306a36Sopenharmony_ci		 * way, signals_pending won't be changed while we're reading it.
30162306a36Sopenharmony_ci		 *
30262306a36Sopenharmony_ci		 * Setting signals_enabled and reading signals_pending must
30362306a36Sopenharmony_ci		 * happen in this order, so have the barrier here.
30462306a36Sopenharmony_ci		 */
30562306a36Sopenharmony_ci		barrier();
30662306a36Sopenharmony_ci
30762306a36Sopenharmony_ci		save_pending = signals_pending;
30862306a36Sopenharmony_ci		if (save_pending == 0)
30962306a36Sopenharmony_ci			return;
31062306a36Sopenharmony_ci
31162306a36Sopenharmony_ci		signals_pending = 0;
31262306a36Sopenharmony_ci
31362306a36Sopenharmony_ci		/*
31462306a36Sopenharmony_ci		 * We have pending interrupts, so disable signals, as the
31562306a36Sopenharmony_ci		 * handlers expect them off when they are called.  They will
31662306a36Sopenharmony_ci		 * be enabled again above. We need to trace this, as we're
31762306a36Sopenharmony_ci		 * expected to be enabling interrupts already, but any more
31862306a36Sopenharmony_ci		 * tracing that happens inside the handlers we call for the
31962306a36Sopenharmony_ci		 * pending signals will mess up the tracing state.
32062306a36Sopenharmony_ci		 */
32162306a36Sopenharmony_ci		signals_enabled = 0;
32262306a36Sopenharmony_ci		um_trace_signals_off();
32362306a36Sopenharmony_ci
32462306a36Sopenharmony_ci		/*
32562306a36Sopenharmony_ci		 * Deal with SIGIO first because the alarm handler might
32662306a36Sopenharmony_ci		 * schedule, leaving the pending SIGIO stranded until we come
32762306a36Sopenharmony_ci		 * back here.
32862306a36Sopenharmony_ci		 *
32962306a36Sopenharmony_ci		 * SIGIO's handler doesn't use siginfo or mcontext,
33062306a36Sopenharmony_ci		 * so they can be NULL.
33162306a36Sopenharmony_ci		 */
33262306a36Sopenharmony_ci		if (save_pending & SIGIO_MASK)
33362306a36Sopenharmony_ci			sig_handler_common(SIGIO, NULL, NULL);
33462306a36Sopenharmony_ci
33562306a36Sopenharmony_ci		/* Do not reenter the handler */
33662306a36Sopenharmony_ci
33762306a36Sopenharmony_ci		if ((save_pending & SIGALRM_MASK) && (!(signals_active & SIGALRM_MASK)))
33862306a36Sopenharmony_ci			timer_real_alarm_handler(NULL);
33962306a36Sopenharmony_ci
34062306a36Sopenharmony_ci		/* Rerun the loop only if there is still pending SIGIO and not in TIMER handler */
34162306a36Sopenharmony_ci
34262306a36Sopenharmony_ci		if (!(signals_pending & SIGIO_MASK) && (signals_active & SIGALRM_MASK))
34362306a36Sopenharmony_ci			return;
34462306a36Sopenharmony_ci
34562306a36Sopenharmony_ci		/* Re-enable signals and trace that we're doing so. */
34662306a36Sopenharmony_ci		um_trace_signals_on();
34762306a36Sopenharmony_ci		signals_enabled = 1;
34862306a36Sopenharmony_ci	}
34962306a36Sopenharmony_ci}
35062306a36Sopenharmony_ci
35162306a36Sopenharmony_ciint um_set_signals(int enable)
35262306a36Sopenharmony_ci{
35362306a36Sopenharmony_ci	int ret;
35462306a36Sopenharmony_ci	if (signals_enabled == enable)
35562306a36Sopenharmony_ci		return enable;
35662306a36Sopenharmony_ci
35762306a36Sopenharmony_ci	ret = signals_enabled;
35862306a36Sopenharmony_ci	if (enable)
35962306a36Sopenharmony_ci		unblock_signals();
36062306a36Sopenharmony_ci	else block_signals();
36162306a36Sopenharmony_ci
36262306a36Sopenharmony_ci	return ret;
36362306a36Sopenharmony_ci}
36462306a36Sopenharmony_ci
36562306a36Sopenharmony_ciint um_set_signals_trace(int enable)
36662306a36Sopenharmony_ci{
36762306a36Sopenharmony_ci	int ret;
36862306a36Sopenharmony_ci	if (signals_enabled == enable)
36962306a36Sopenharmony_ci		return enable;
37062306a36Sopenharmony_ci
37162306a36Sopenharmony_ci	ret = signals_enabled;
37262306a36Sopenharmony_ci	if (enable)
37362306a36Sopenharmony_ci		unblock_signals_trace();
37462306a36Sopenharmony_ci	else
37562306a36Sopenharmony_ci		block_signals_trace();
37662306a36Sopenharmony_ci
37762306a36Sopenharmony_ci	return ret;
37862306a36Sopenharmony_ci}
37962306a36Sopenharmony_ci
38062306a36Sopenharmony_ci#ifdef UML_CONFIG_UML_TIME_TRAVEL_SUPPORT
38162306a36Sopenharmony_civoid mark_sigio_pending(void)
38262306a36Sopenharmony_ci{
38362306a36Sopenharmony_ci	signals_pending |= SIGIO_MASK;
38462306a36Sopenharmony_ci}
38562306a36Sopenharmony_ci
38662306a36Sopenharmony_civoid block_signals_hard(void)
38762306a36Sopenharmony_ci{
38862306a36Sopenharmony_ci	if (signals_blocked)
38962306a36Sopenharmony_ci		return;
39062306a36Sopenharmony_ci	signals_blocked = 1;
39162306a36Sopenharmony_ci	barrier();
39262306a36Sopenharmony_ci}
39362306a36Sopenharmony_ci
39462306a36Sopenharmony_civoid unblock_signals_hard(void)
39562306a36Sopenharmony_ci{
39662306a36Sopenharmony_ci	if (!signals_blocked)
39762306a36Sopenharmony_ci		return;
39862306a36Sopenharmony_ci	/* Must be set to 0 before we check the pending bits etc. */
39962306a36Sopenharmony_ci	signals_blocked = 0;
40062306a36Sopenharmony_ci	barrier();
40162306a36Sopenharmony_ci
40262306a36Sopenharmony_ci	if (signals_pending && signals_enabled) {
40362306a36Sopenharmony_ci		/* this is a bit inefficient, but that's not really important */
40462306a36Sopenharmony_ci		block_signals();
40562306a36Sopenharmony_ci		unblock_signals();
40662306a36Sopenharmony_ci	} else if (signals_pending & SIGIO_MASK) {
40762306a36Sopenharmony_ci		/* we need to run time-travel handlers even if not enabled */
40862306a36Sopenharmony_ci		sigio_run_timetravel_handlers();
40962306a36Sopenharmony_ci	}
41062306a36Sopenharmony_ci}
41162306a36Sopenharmony_ci#endif
41262306a36Sopenharmony_ci
41362306a36Sopenharmony_ciint os_is_signal_stack(void)
41462306a36Sopenharmony_ci{
41562306a36Sopenharmony_ci	stack_t ss;
41662306a36Sopenharmony_ci	sigaltstack(NULL, &ss);
41762306a36Sopenharmony_ci
41862306a36Sopenharmony_ci	return ss.ss_flags & SS_ONSTACK;
41962306a36Sopenharmony_ci}
420