mirror of
https://github.com/Motorhead1991/qemu.git
synced 2025-07-27 04:13:53 -06:00
linux-user: Split out die_with_signal
Because we trap so many signals for use by the guest, we have to take extra steps to exit properly. Acked-by: Helge Deller <deller@gmx.de> Reviewed-by: Philippe Mathieu-Daudé <philmd@linaro.org> Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
This commit is contained in:
parent
912ff698ca
commit
b8b50f1e9a
1 changed files with 28 additions and 24 deletions
|
@ -689,13 +689,39 @@ void cpu_loop_exit_sigbus(CPUState *cpu, target_ulong addr,
|
||||||
}
|
}
|
||||||
|
|
||||||
/* abort execution with signal */
|
/* abort execution with signal */
|
||||||
|
static G_NORETURN
|
||||||
|
void die_with_signal(int host_sig)
|
||||||
|
{
|
||||||
|
struct sigaction act = {
|
||||||
|
.sa_handler = SIG_DFL,
|
||||||
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
* The proper exit code for dying from an uncaught signal is -<signal>.
|
||||||
|
* The kernel doesn't allow exit() or _exit() to pass a negative value.
|
||||||
|
* To get the proper exit code we need to actually die from an uncaught
|
||||||
|
* signal. Here the default signal handler is installed, we send
|
||||||
|
* the signal and we wait for it to arrive.
|
||||||
|
*/
|
||||||
|
sigfillset(&act.sa_mask);
|
||||||
|
sigaction(host_sig, &act, NULL);
|
||||||
|
|
||||||
|
kill(getpid(), host_sig);
|
||||||
|
|
||||||
|
/* Make sure the signal isn't masked (reusing the mask inside of act). */
|
||||||
|
sigdelset(&act.sa_mask, host_sig);
|
||||||
|
sigsuspend(&act.sa_mask);
|
||||||
|
|
||||||
|
/* unreachable */
|
||||||
|
abort();
|
||||||
|
}
|
||||||
|
|
||||||
static G_NORETURN
|
static G_NORETURN
|
||||||
void dump_core_and_abort(CPUArchState *env, int target_sig)
|
void dump_core_and_abort(CPUArchState *env, int target_sig)
|
||||||
{
|
{
|
||||||
CPUState *cpu = env_cpu(env);
|
CPUState *cpu = env_cpu(env);
|
||||||
TaskState *ts = (TaskState *)cpu->opaque;
|
TaskState *ts = (TaskState *)cpu->opaque;
|
||||||
int host_sig, core_dumped = 0;
|
int host_sig, core_dumped = 0;
|
||||||
struct sigaction act;
|
|
||||||
|
|
||||||
host_sig = target_to_host_signal(target_sig);
|
host_sig = target_to_host_signal(target_sig);
|
||||||
trace_user_dump_core_and_abort(env, target_sig, host_sig);
|
trace_user_dump_core_and_abort(env, target_sig, host_sig);
|
||||||
|
@ -719,29 +745,7 @@ void dump_core_and_abort(CPUArchState *env, int target_sig)
|
||||||
}
|
}
|
||||||
|
|
||||||
preexit_cleanup(env, 128 + target_sig);
|
preexit_cleanup(env, 128 + target_sig);
|
||||||
|
die_with_signal(host_sig);
|
||||||
/* The proper exit code for dying from an uncaught signal is
|
|
||||||
* -<signal>. The kernel doesn't allow exit() or _exit() to pass
|
|
||||||
* a negative value. To get the proper exit code we need to
|
|
||||||
* actually die from an uncaught signal. Here the default signal
|
|
||||||
* handler is installed, we send ourself a signal and we wait for
|
|
||||||
* it to arrive. */
|
|
||||||
sigfillset(&act.sa_mask);
|
|
||||||
act.sa_handler = SIG_DFL;
|
|
||||||
act.sa_flags = 0;
|
|
||||||
sigaction(host_sig, &act, NULL);
|
|
||||||
|
|
||||||
/* For some reason raise(host_sig) doesn't send the signal when
|
|
||||||
* statically linked on x86-64. */
|
|
||||||
kill(getpid(), host_sig);
|
|
||||||
|
|
||||||
/* Make sure the signal isn't masked (just reuse the mask inside
|
|
||||||
of act) */
|
|
||||||
sigdelset(&act.sa_mask, host_sig);
|
|
||||||
sigsuspend(&act.sa_mask);
|
|
||||||
|
|
||||||
/* unreachable */
|
|
||||||
abort();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* queue a signal so that it will be send to the virtual CPU as soon
|
/* queue a signal so that it will be send to the virtual CPU as soon
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue