qemu-devel
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[PATCH 22/30] bsd-user/signal.c: Fill in queue_signal


From: Warner Losh
Subject: [PATCH 22/30] bsd-user/signal.c: Fill in queue_signal
Date: Sun, 9 Jan 2022 09:19:15 -0700

Fill in queue signal implementation, as well as routines allocate and
delete elements of the signal queue.

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/signal.c | 72 ++++++++++++++++++++++++++++++++++++++++++++++-
 1 file changed, 71 insertions(+), 1 deletion(-)

diff --git a/bsd-user/signal.c b/bsd-user/signal.c
index 97f42f9c45e..93c3b3c5033 100644
--- a/bsd-user/signal.c
+++ b/bsd-user/signal.c
@@ -109,6 +109,29 @@ static int core_dump_signal(int sig)
     }
 }
 
+/* Signal queue handling. */
+static inline struct qemu_sigqueue *alloc_sigqueue(CPUArchState *env)
+{
+    CPUState *cpu = env_cpu(env);
+    TaskState *ts = cpu->opaque;
+    struct qemu_sigqueue *q = ts->first_free;
+
+    if (!q) {
+        return NULL;
+    }
+    ts->first_free = q->next;
+    return q;
+}
+
+static inline void free_sigqueue(CPUArchState *env, struct qemu_sigqueue *q)
+{
+
+    CPUState *cpu = env_cpu(env);
+    TaskState *ts = cpu->opaque;
+    q->next = ts->first_free;
+    ts->first_free = q;
+}
+
 /* Abort execution with signal. */
 void QEMU_NORETURN force_sig(int target_sig)
 {
@@ -174,7 +197,54 @@ void QEMU_NORETURN force_sig(int target_sig)
  */
 void queue_signal(CPUArchState *env, int sig, target_siginfo_t *info)
 {
-    qemu_log_mask(LOG_UNIMP, "No signal queueing, dropping signal %d\n", sig);
+    CPUState *cpu = env_cpu(env);
+    TaskState *ts = cpu->opaque;
+    struct emulated_sigtable *k;
+    struct qemu_sigqueue *q, **pq;
+
+    k = &ts->sigtab[sig - 1];
+    trace_user_queue_signal(env, sig); /* We called this in the caller? XXX */
+    /*
+     * XXX does the segv changes make this go away? -- I think so
+     */
+    if (sig == TARGET_SIGSEGV && sigismember(&ts->signal_mask, SIGSEGV)) {
+        /*
+         * Guest has blocked SIGSEGV but we got one anyway. Assume this is a
+         * forced SIGSEGV (ie one the kernel handles via force_sig_info because
+         * it got a real MMU fault). A blocked SIGSEGV in that situation is
+         * treated as if using the default handler. This is not correct if some
+         * other process has randomly sent us a SIGSEGV via kill(), but that is
+         * not easy to distinguish at this point, so we assume it doesn't
+         * happen.
+         */
+        force_sig(sig);
+    }
+
+    pq = &k->first;
+
+    /*
+     * FreeBSD signals are always queued.  Linux only queues real time signals.
+     * XXX this code is not thread safe.  "What lock protects ts->sigtab?"
+     */
+    if (!k->pending) {
+        /* first signal */
+        q = &k->info;
+    } else {
+        q = alloc_sigqueue(env);
+        if (!q) {
+            return; /* XXX WHAT TO DO */
+        }
+        while (*pq != NULL) {
+            pq = &(*pq)->next;
+        }
+    }
+    *pq = q;
+    q->info = *info;
+    q->next = NULL;
+    k->pending = 1;
+    /* Signal that a new signal is pending. */
+    ts->signal_pending = 1;
+    return;
 }
 
 static int fatal_signal(int sig)
-- 
2.33.1




reply via email to

[Prev in Thread] Current Thread [Next in Thread]