diff mbox series

[10/30] bsd-user/signal.c: Implement signal_init()

Message ID 20220109161923.85683-11-imp@bsdimp.com (mailing list archive)
State New, archived
Headers show
Series bsd-user: upstream our signal implementation | expand

Commit Message

Warner Losh Jan. 9, 2022, 4:19 p.m. UTC
Initialize the signal state for the emulator. Setup a set of sane
default signal handlers, mirroring the host's signals. For fatal signals
(those that exit by default), establish our own set of signal
handlers. Stub out the actual signal handler we use for the moment.

Signed-off-by: Stacey Son <sson@FreeBSD.org>
Signed-off-by: Kyle Evans <kevans@freebsd.org>
Signed-off-by: Warner Losh <imp@bsdimp.com>
---
 bsd-user/qemu.h   |  1 +
 bsd-user/signal.c | 68 +++++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 69 insertions(+)

Comments

Peter Maydell Jan. 13, 2022, 7:28 p.m. UTC | #1
On Sun, 9 Jan 2022 at 16:29, Warner Losh <imp@bsdimp.com> wrote:
>
> Initialize the signal state for the emulator. Setup a set of sane
> default signal handlers, mirroring the host's signals. For fatal signals
> (those that exit by default), establish our own set of signal
> handlers. Stub out the actual signal handler we use for the moment.
>
> Signed-off-by: Stacey Son <sson@FreeBSD.org>
> Signed-off-by: Kyle Evans <kevans@freebsd.org>
> Signed-off-by: Warner Losh <imp@bsdimp.com>
> ---
>  bsd-user/qemu.h   |  1 +
>  bsd-user/signal.c | 68 +++++++++++++++++++++++++++++++++++++++++++++++
>  2 files changed, 69 insertions(+)

> +static struct target_sigaction sigact_table[TARGET_NSIG];




>  void signal_init(void)
>  {
> +    TaskState *ts = (TaskState *)thread_cpu->opaque;
> +    struct sigaction act;
> +    struct sigaction oact;
> +    int i;
> +    int host_sig;
> +
> +    /* Set the signal mask from the host mask. */
> +    sigprocmask(0, 0, &ts->signal_mask);
> +
> +    /*
> +     * Set all host signal handlers. ALL signals are blocked during the
> +     * handlers to serialize them.
> +     */
> +    memset(sigact_table, 0, sizeof(sigact_table));

Do you need this memset()? sigact_table is a global, so it's
zero-initialized on startup, and this function is only called once.
The (otherwise basically identical) Linux version of this function
doesn't have it.

> +
> +    sigfillset(&act.sa_mask);
> +    act.sa_sigaction = host_signal_handler;
> +    act.sa_flags = SA_SIGINFO;
> +
> +    for (i = 1; i <= TARGET_NSIG; i++) {
> +        host_sig = target_to_host_signal(i);
> +        sigaction(host_sig, NULL, &oact);
> +        if (oact.sa_sigaction == (void *)SIG_IGN) {
> +            sigact_table[i - 1]._sa_handler = TARGET_SIG_IGN;
> +        } else if (oact.sa_sigaction == (void *)SIG_DFL) {
> +            sigact_table[i - 1]._sa_handler = TARGET_SIG_DFL;
> +        }
> +        /*
> +         * If there's already a handler installed then something has
> +         * gone horribly wrong, so don't even try to handle that case.
> +         * Install some handlers for our own use.  We need at least
> +         * SIGSEGV and SIGBUS, to detect exceptions.  We can not just
> +         * trap all signals because it affects syscall interrupt
> +         * behavior.  But do trap all default-fatal signals.
> +         */
> +        if (fatal_signal(i)) {
> +            sigaction(host_sig, &act, NULL);
> +        }
> +    }
>  }

Otherwise

Reviewed-by: Peter Maydell <peter.maydell@linaro.org>

thanks
-- PMM
Warner Losh Jan. 14, 2022, 6:51 p.m. UTC | #2
On Thu, Jan 13, 2022 at 12:28 PM Peter Maydell <peter.maydell@linaro.org>
wrote:

> On Sun, 9 Jan 2022 at 16:29, Warner Losh <imp@bsdimp.com> wrote:
> >
> > Initialize the signal state for the emulator. Setup a set of sane
> > default signal handlers, mirroring the host's signals. For fatal signals
> > (those that exit by default), establish our own set of signal
> > handlers. Stub out the actual signal handler we use for the moment.
> >
> > Signed-off-by: Stacey Son <sson@FreeBSD.org>
> > Signed-off-by: Kyle Evans <kevans@freebsd.org>
> > Signed-off-by: Warner Losh <imp@bsdimp.com>
> > ---
> >  bsd-user/qemu.h   |  1 +
> >  bsd-user/signal.c | 68 +++++++++++++++++++++++++++++++++++++++++++++++
> >  2 files changed, 69 insertions(+)
>
> > +static struct target_sigaction sigact_table[TARGET_NSIG];
>
>
>
>
> >  void signal_init(void)
> >  {
> > +    TaskState *ts = (TaskState *)thread_cpu->opaque;
> > +    struct sigaction act;
> > +    struct sigaction oact;
> > +    int i;
> > +    int host_sig;
> > +
> > +    /* Set the signal mask from the host mask. */
> > +    sigprocmask(0, 0, &ts->signal_mask);
> > +
> > +    /*
> > +     * Set all host signal handlers. ALL signals are blocked during the
> > +     * handlers to serialize them.
> > +     */
> > +    memset(sigact_table, 0, sizeof(sigact_table));
>
> Do you need this memset()? sigact_table is a global, so it's
> zero-initialized on startup, and this function is only called once.
> The (otherwise basically identical) Linux version of this function
> doesn't have it.
>

Yea, that looks bogus. I'll remove it.


> > +
> > +    sigfillset(&act.sa_mask);
> > +    act.sa_sigaction = host_signal_handler;
> > +    act.sa_flags = SA_SIGINFO;
> > +
> > +    for (i = 1; i <= TARGET_NSIG; i++) {
> > +        host_sig = target_to_host_signal(i);
> > +        sigaction(host_sig, NULL, &oact);
> > +        if (oact.sa_sigaction == (void *)SIG_IGN) {
> > +            sigact_table[i - 1]._sa_handler = TARGET_SIG_IGN;
> > +        } else if (oact.sa_sigaction == (void *)SIG_DFL) {
> > +            sigact_table[i - 1]._sa_handler = TARGET_SIG_DFL;
> > +        }
> > +        /*
> > +         * If there's already a handler installed then something has
> > +         * gone horribly wrong, so don't even try to handle that case.
> > +         * Install some handlers for our own use.  We need at least
> > +         * SIGSEGV and SIGBUS, to detect exceptions.  We can not just
> > +         * trap all signals because it affects syscall interrupt
> > +         * behavior.  But do trap all default-fatal signals.
> > +         */
> > +        if (fatal_signal(i)) {
> > +            sigaction(host_sig, &act, NULL);
> > +        }
> > +    }
> >  }
>
> Otherwise
>
> Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
>

thanks!

Warner
Richard Henderson Jan. 24, 2022, 1:38 a.m. UTC | #3
On 1/10/22 3:19 AM, Warner Losh wrote:
> Initialize the signal state for the emulator. Setup a set of sane
> default signal handlers, mirroring the host's signals. For fatal signals
> (those that exit by default), establish our own set of signal
> handlers. Stub out the actual signal handler we use for the moment.
> 
> Signed-off-by: Stacey Son <sson@FreeBSD.org>
> Signed-off-by: Kyle Evans <kevans@freebsd.org>
> Signed-off-by: Warner Losh <imp@bsdimp.com>
> ---
>   bsd-user/qemu.h   |  1 +
>   bsd-user/signal.c | 68 +++++++++++++++++++++++++++++++++++++++++++++++
>   2 files changed, 69 insertions(+)
> 
> diff --git a/bsd-user/qemu.h b/bsd-user/qemu.h
> index 334f8b1d715..0e0b8db708b 100644
> --- a/bsd-user/qemu.h
> +++ b/bsd-user/qemu.h
> @@ -97,6 +97,7 @@ typedef struct TaskState {
>       struct qemu_sigqueue sigqueue_table[MAX_SIGQUEUE_SIZE]; /* siginfo queue */
>       struct qemu_sigqueue *first_free; /* first free siginfo queue entry */
>       int signal_pending; /* non zero if a signal may be pending */
> +    sigset_t signal_mask;
>   
>       uint8_t stack[];
>   } __attribute__((aligned(16))) TaskState;
> diff --git a/bsd-user/signal.c b/bsd-user/signal.c
> index 7ea86149981..b2c91c39379 100644
> --- a/bsd-user/signal.c
> +++ b/bsd-user/signal.c
> @@ -28,6 +28,9 @@
>    * fork.
>    */
>   
> +static struct target_sigaction sigact_table[TARGET_NSIG];
> +static void host_signal_handler(int host_sig, siginfo_t *info, void *puc);
> +
>   int host_to_target_signal(int sig)
>   {
>       return sig;
> @@ -47,6 +50,28 @@ void queue_signal(CPUArchState *env, int sig, target_siginfo_t *info)
>       qemu_log_mask(LOG_UNIMP, "No signal queueing, dropping signal %d\n", sig);
>   }
>   
> +static int fatal_signal(int sig)
> +{
> +
> +    switch (sig) {
> +    case TARGET_SIGCHLD:
> +    case TARGET_SIGURG:
> +    case TARGET_SIGWINCH:
> +    case TARGET_SIGINFO:
> +        /* Ignored by default. */
> +        return 0;
> +    case TARGET_SIGCONT:
> +    case TARGET_SIGSTOP:
> +    case TARGET_SIGTSTP:
> +    case TARGET_SIGTTIN:
> +    case TARGET_SIGTTOU:
> +        /* Job control signals.  */
> +        return 0;
> +    default:
> +        return 1;
> +    }
> +}
> +
>   /*
>    * Force a synchronously taken QEMU_SI_FAULT signal. For QEMU the
>    * 'force' part is handled in process_pending_signals().
> @@ -64,8 +89,51 @@ void force_sig_fault(int sig, int code, abi_ulong addr)
>       queue_signal(env, sig, &info);
>   }
>   
> +static void host_signal_handler(int host_sig, siginfo_t *info, void *puc)
> +{
> +}
> +
>   void signal_init(void)
>   {
> +    TaskState *ts = (TaskState *)thread_cpu->opaque;
> +    struct sigaction act;
> +    struct sigaction oact;
> +    int i;
> +    int host_sig;
> +
> +    /* Set the signal mask from the host mask. */
> +    sigprocmask(0, 0, &ts->signal_mask);
> +
> +    /*
> +     * Set all host signal handlers. ALL signals are blocked during the
> +     * handlers to serialize them.
> +     */
> +    memset(sigact_table, 0, sizeof(sigact_table));
> +
> +    sigfillset(&act.sa_mask);
> +    act.sa_sigaction = host_signal_handler;
> +    act.sa_flags = SA_SIGINFO;
> +
> +    for (i = 1; i <= TARGET_NSIG; i++) {
> +        host_sig = target_to_host_signal(i);
> +        sigaction(host_sig, NULL, &oact);

Missing test for CONFIG_GPROF + SIGPROF.  Otherwise,

Reviewed-by: Richard Henderson <richard.henderson@linaro.org>

r~
Warner Losh Jan. 24, 2022, 9:35 p.m. UTC | #4
On Sun, Jan 23, 2022 at 6:38 PM Richard Henderson <
richard.henderson@linaro.org> wrote:

> On 1/10/22 3:19 AM, Warner Losh wrote:
> > Initialize the signal state for the emulator. Setup a set of sane
> > default signal handlers, mirroring the host's signals. For fatal signals
> > (those that exit by default), establish our own set of signal
> > handlers. Stub out the actual signal handler we use for the moment.
> >
> > Signed-off-by: Stacey Son <sson@FreeBSD.org>
> > Signed-off-by: Kyle Evans <kevans@freebsd.org>
> > Signed-off-by: Warner Losh <imp@bsdimp.com>
> > ---
> >   bsd-user/qemu.h   |  1 +
> >   bsd-user/signal.c | 68 +++++++++++++++++++++++++++++++++++++++++++++++
> >   2 files changed, 69 insertions(+)
> >
> > diff --git a/bsd-user/qemu.h b/bsd-user/qemu.h
> > index 334f8b1d715..0e0b8db708b 100644
> > --- a/bsd-user/qemu.h
> > +++ b/bsd-user/qemu.h
> > @@ -97,6 +97,7 @@ typedef struct TaskState {
> >       struct qemu_sigqueue sigqueue_table[MAX_SIGQUEUE_SIZE]; /* siginfo
> queue */
> >       struct qemu_sigqueue *first_free; /* first free siginfo queue
> entry */
> >       int signal_pending; /* non zero if a signal may be pending */
> > +    sigset_t signal_mask;
> >
> >       uint8_t stack[];
> >   } __attribute__((aligned(16))) TaskState;
> > diff --git a/bsd-user/signal.c b/bsd-user/signal.c
> > index 7ea86149981..b2c91c39379 100644
> > --- a/bsd-user/signal.c
> > +++ b/bsd-user/signal.c
> > @@ -28,6 +28,9 @@
> >    * fork.
> >    */
> >
> > +static struct target_sigaction sigact_table[TARGET_NSIG];
> > +static void host_signal_handler(int host_sig, siginfo_t *info, void
> *puc);
> > +
> >   int host_to_target_signal(int sig)
> >   {
> >       return sig;
> > @@ -47,6 +50,28 @@ void queue_signal(CPUArchState *env, int sig,
> target_siginfo_t *info)
> >       qemu_log_mask(LOG_UNIMP, "No signal queueing, dropping signal
> %d\n", sig);
> >   }
> >
> > +static int fatal_signal(int sig)
> > +{
> > +
> > +    switch (sig) {
> > +    case TARGET_SIGCHLD:
> > +    case TARGET_SIGURG:
> > +    case TARGET_SIGWINCH:
> > +    case TARGET_SIGINFO:
> > +        /* Ignored by default. */
> > +        return 0;
> > +    case TARGET_SIGCONT:
> > +    case TARGET_SIGSTOP:
> > +    case TARGET_SIGTSTP:
> > +    case TARGET_SIGTTIN:
> > +    case TARGET_SIGTTOU:
> > +        /* Job control signals.  */
> > +        return 0;
> > +    default:
> > +        return 1;
> > +    }
> > +}
> > +
> >   /*
> >    * Force a synchronously taken QEMU_SI_FAULT signal. For QEMU the
> >    * 'force' part is handled in process_pending_signals().
> > @@ -64,8 +89,51 @@ void force_sig_fault(int sig, int code, abi_ulong
> addr)
> >       queue_signal(env, sig, &info);
> >   }
> >
> > +static void host_signal_handler(int host_sig, siginfo_t *info, void
> *puc)
> > +{
> > +}
> > +
> >   void signal_init(void)
> >   {
> > +    TaskState *ts = (TaskState *)thread_cpu->opaque;
> > +    struct sigaction act;
> > +    struct sigaction oact;
> > +    int i;
> > +    int host_sig;
> > +
> > +    /* Set the signal mask from the host mask. */
> > +    sigprocmask(0, 0, &ts->signal_mask);
> > +
> > +    /*
> > +     * Set all host signal handlers. ALL signals are blocked during the
> > +     * handlers to serialize them.
> > +     */
> > +    memset(sigact_table, 0, sizeof(sigact_table));
> > +
> > +    sigfillset(&act.sa_mask);
> > +    act.sa_sigaction = host_signal_handler;
> > +    act.sa_flags = SA_SIGINFO;
> > +
> > +    for (i = 1; i <= TARGET_NSIG; i++) {
> > +        host_sig = target_to_host_signal(i);
> > +        sigaction(host_sig, NULL, &oact);
>
> Missing test for CONFIG_GPROF + SIGPROF.  Otherwise,
>
> Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
>

Gotcha. Will add.

Warner
diff mbox series

Patch

diff --git a/bsd-user/qemu.h b/bsd-user/qemu.h
index 334f8b1d715..0e0b8db708b 100644
--- a/bsd-user/qemu.h
+++ b/bsd-user/qemu.h
@@ -97,6 +97,7 @@  typedef struct TaskState {
     struct qemu_sigqueue sigqueue_table[MAX_SIGQUEUE_SIZE]; /* siginfo queue */
     struct qemu_sigqueue *first_free; /* first free siginfo queue entry */
     int signal_pending; /* non zero if a signal may be pending */
+    sigset_t signal_mask;
 
     uint8_t stack[];
 } __attribute__((aligned(16))) TaskState;
diff --git a/bsd-user/signal.c b/bsd-user/signal.c
index 7ea86149981..b2c91c39379 100644
--- a/bsd-user/signal.c
+++ b/bsd-user/signal.c
@@ -28,6 +28,9 @@ 
  * fork.
  */
 
+static struct target_sigaction sigact_table[TARGET_NSIG];
+static void host_signal_handler(int host_sig, siginfo_t *info, void *puc);
+
 int host_to_target_signal(int sig)
 {
     return sig;
@@ -47,6 +50,28 @@  void queue_signal(CPUArchState *env, int sig, target_siginfo_t *info)
     qemu_log_mask(LOG_UNIMP, "No signal queueing, dropping signal %d\n", sig);
 }
 
+static int fatal_signal(int sig)
+{
+
+    switch (sig) {
+    case TARGET_SIGCHLD:
+    case TARGET_SIGURG:
+    case TARGET_SIGWINCH:
+    case TARGET_SIGINFO:
+        /* Ignored by default. */
+        return 0;
+    case TARGET_SIGCONT:
+    case TARGET_SIGSTOP:
+    case TARGET_SIGTSTP:
+    case TARGET_SIGTTIN:
+    case TARGET_SIGTTOU:
+        /* Job control signals.  */
+        return 0;
+    default:
+        return 1;
+    }
+}
+
 /*
  * Force a synchronously taken QEMU_SI_FAULT signal. For QEMU the
  * 'force' part is handled in process_pending_signals().
@@ -64,8 +89,51 @@  void force_sig_fault(int sig, int code, abi_ulong addr)
     queue_signal(env, sig, &info);
 }
 
+static void host_signal_handler(int host_sig, siginfo_t *info, void *puc)
+{
+}
+
 void signal_init(void)
 {
+    TaskState *ts = (TaskState *)thread_cpu->opaque;
+    struct sigaction act;
+    struct sigaction oact;
+    int i;
+    int host_sig;
+
+    /* Set the signal mask from the host mask. */
+    sigprocmask(0, 0, &ts->signal_mask);
+
+    /*
+     * Set all host signal handlers. ALL signals are blocked during the
+     * handlers to serialize them.
+     */
+    memset(sigact_table, 0, sizeof(sigact_table));
+
+    sigfillset(&act.sa_mask);
+    act.sa_sigaction = host_signal_handler;
+    act.sa_flags = SA_SIGINFO;
+
+    for (i = 1; i <= TARGET_NSIG; i++) {
+        host_sig = target_to_host_signal(i);
+        sigaction(host_sig, NULL, &oact);
+        if (oact.sa_sigaction == (void *)SIG_IGN) {
+            sigact_table[i - 1]._sa_handler = TARGET_SIG_IGN;
+        } else if (oact.sa_sigaction == (void *)SIG_DFL) {
+            sigact_table[i - 1]._sa_handler = TARGET_SIG_DFL;
+        }
+        /*
+         * If there's already a handler installed then something has
+         * gone horribly wrong, so don't even try to handle that case.
+         * Install some handlers for our own use.  We need at least
+         * SIGSEGV and SIGBUS, to detect exceptions.  We can not just
+         * trap all signals because it affects syscall interrupt
+         * behavior.  But do trap all default-fatal signals.
+         */
+        if (fatal_signal(i)) {
+            sigaction(host_sig, &act, NULL);
+        }
+    }
 }
 
 void process_pending_signals(CPUArchState *cpu_env)