mirror of
https://github.com/Motorhead1991/qemu.git
synced 2025-07-26 20:03:54 -06:00
linux-user: Allow custom rt signal mappings
Some applications want to use low priority realtime signals (e.g., SIGRTMAX). Currently QEMU cannot map all target realtime signals to host realtime signals, and chooses to sacrifice the end of the target realtime signal range. Allow users to choose how to map target realtime signals to host realtime signals using the new -t option, the new QEMU_RTSIG_MAP environment variable, and the new -Drtsig_map=\"...\" meson flag. To simplify things, the meson flag is not per-target, because the intended use case is app-specific qemu-user builds. The mapping is specified using the "tsig hsig count[,...]" syntax. Target realtime signals [tsig,tsig+count) are mapped to host realtime signals [hsig,hsig+count). Care is taken to avoid double and out-of-range mappings. Signed-off-by: Ilya Leoshkevich <iii@linux.ibm.com> Reviewed-by: Richard Henderson <richard.henderson@linaro.org> Message-ID: <20241029232211.206766-2-iii@linux.ibm.com> Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
This commit is contained in:
parent
6e9dcfb906
commit
c107521e0e
6 changed files with 106 additions and 23 deletions
|
@ -18,6 +18,7 @@
|
|||
*/
|
||||
#include "qemu/osdep.h"
|
||||
#include "qemu/bitops.h"
|
||||
#include "qemu/cutils.h"
|
||||
#include "gdbstub/user.h"
|
||||
#include "exec/page-protection.h"
|
||||
#include "hw/core/tcg-cpu-ops.h"
|
||||
|
@ -513,20 +514,81 @@ static int core_dump_signal(int sig)
|
|||
}
|
||||
}
|
||||
|
||||
static void signal_table_init(void)
|
||||
static void signal_table_init(const char *rtsig_map)
|
||||
{
|
||||
int hsig, tsig, count;
|
||||
|
||||
if (rtsig_map) {
|
||||
/*
|
||||
* Map host RT signals to target RT signals according to the
|
||||
* user-provided specification.
|
||||
*/
|
||||
const char *s = rtsig_map;
|
||||
|
||||
while (true) {
|
||||
int i;
|
||||
|
||||
if (qemu_strtoi(s, &s, 10, &tsig) || *s++ != ' ') {
|
||||
fprintf(stderr, "Malformed target signal in QEMU_RTSIG_MAP\n");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
if (qemu_strtoi(s, &s, 10, &hsig) || *s++ != ' ') {
|
||||
fprintf(stderr, "Malformed host signal in QEMU_RTSIG_MAP\n");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
if (qemu_strtoi(s, &s, 10, &count) || (*s && *s != ',')) {
|
||||
fprintf(stderr, "Malformed signal count in QEMU_RTSIG_MAP\n");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
for (i = 0; i < count; i++, tsig++, hsig++) {
|
||||
if (tsig < TARGET_SIGRTMIN || tsig > TARGET_NSIG) {
|
||||
fprintf(stderr, "%d is not a target rt signal\n", tsig);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
if (hsig < SIGRTMIN || hsig > SIGRTMAX) {
|
||||
fprintf(stderr, "%d is not a host rt signal\n", hsig);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
if (host_to_target_signal_table[hsig]) {
|
||||
fprintf(stderr, "%d already maps %d\n",
|
||||
hsig, host_to_target_signal_table[hsig]);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
host_to_target_signal_table[hsig] = tsig;
|
||||
}
|
||||
|
||||
if (*s) {
|
||||
s++;
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
/*
|
||||
* Default host-to-target RT signal mapping.
|
||||
*
|
||||
* Signals are supported starting from TARGET_SIGRTMIN and going up
|
||||
* until we run out of host realtime signals. Glibc uses the lower 2
|
||||
* RT signals and (hopefully) nobody uses the upper ones.
|
||||
* This is why SIGRTMIN (34) is generally greater than __SIGRTMIN (32).
|
||||
* To fix this properly we would need to do manual signal delivery
|
||||
* multiplexed over a single host signal.
|
||||
* Attempts for configure "missing" signals via sigaction will be
|
||||
* silently ignored.
|
||||
*
|
||||
* Reserve one signal for internal usage (see below).
|
||||
*/
|
||||
|
||||
hsig = SIGRTMIN + 1;
|
||||
for (tsig = TARGET_SIGRTMIN;
|
||||
hsig <= SIGRTMAX && tsig <= TARGET_NSIG;
|
||||
hsig++, tsig++) {
|
||||
host_to_target_signal_table[hsig] = tsig;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Signals are supported starting from TARGET_SIGRTMIN and going up
|
||||
* until we run out of host realtime signals. Glibc uses the lower 2
|
||||
* RT signals and (hopefully) nobody uses the upper ones.
|
||||
* This is why SIGRTMIN (34) is generally greater than __SIGRTMIN (32).
|
||||
* To fix this properly we would need to do manual signal delivery
|
||||
* multiplexed over a single host signal.
|
||||
* Attempts for configure "missing" signals via sigaction will be
|
||||
* silently ignored.
|
||||
*
|
||||
* Remap the target SIGABRT, so that we can distinguish host abort
|
||||
* from guest abort. When the guest registers a signal handler or
|
||||
* calls raise(SIGABRT), the host will raise SIG_RTn. If the guest
|
||||
|
@ -536,21 +598,27 @@ static void signal_table_init(void)
|
|||
* parent sees the correct mapping from wait status.
|
||||
*/
|
||||
|
||||
hsig = SIGRTMIN;
|
||||
host_to_target_signal_table[SIGABRT] = 0;
|
||||
host_to_target_signal_table[hsig++] = TARGET_SIGABRT;
|
||||
|
||||
for (tsig = TARGET_SIGRTMIN;
|
||||
hsig <= SIGRTMAX && tsig <= TARGET_NSIG;
|
||||
hsig++, tsig++) {
|
||||
host_to_target_signal_table[hsig] = tsig;
|
||||
for (hsig = SIGRTMIN; hsig <= SIGRTMAX; hsig++) {
|
||||
if (!host_to_target_signal_table[hsig]) {
|
||||
host_to_target_signal_table[hsig] = TARGET_SIGABRT;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (hsig > SIGRTMAX) {
|
||||
fprintf(stderr, "No rt signals left for SIGABRT mapping\n");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
/* Invert the mapping that has already been assigned. */
|
||||
for (hsig = 1; hsig < _NSIG; hsig++) {
|
||||
tsig = host_to_target_signal_table[hsig];
|
||||
if (tsig) {
|
||||
assert(target_to_host_signal_table[tsig] == 0);
|
||||
if (target_to_host_signal_table[tsig]) {
|
||||
fprintf(stderr, "%d is already mapped to %d\n",
|
||||
tsig, target_to_host_signal_table[tsig]);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
target_to_host_signal_table[tsig] = hsig;
|
||||
}
|
||||
}
|
||||
|
@ -573,13 +641,13 @@ static void signal_table_init(void)
|
|||
trace_signal_table_init(count);
|
||||
}
|
||||
|
||||
void signal_init(void)
|
||||
void signal_init(const char *rtsig_map)
|
||||
{
|
||||
TaskState *ts = get_task_state(thread_cpu);
|
||||
struct sigaction act, oact;
|
||||
|
||||
/* initialize signal conversion tables */
|
||||
signal_table_init();
|
||||
signal_table_init(rtsig_map);
|
||||
|
||||
/* Set the signal mask from the host mask. */
|
||||
sigprocmask(0, 0, &ts->signal_mask);
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue