All of lore.kernel.org
 help / color / mirror / Atom feed
From: "Alex Bennée" <alex.bennee@linaro.org>
To: qemu-devel@nongnu.org
Cc: fam@euphon.net, berrange@redhat.com,
	"Kyle Evans" <kevans@freebsd.org>,
	f4bug@amsat.org, "Laurent Vivier" <laurent@vivier.eu>,
	"Warner Losh" <imp@bsdimp.com>,
	stefanha@redhat.com, crosa@redhat.com, pbonzini@redhat.com,
	"Mahmoud Mandour" <ma.mandourr@gmail.com>,
	"Alexandre Iooss" <erdnaxe@crans.org>,
	"Alex Bennée" <alex.bennee@linaro.org>,
	aurelien@aurel32.net
Subject: [PATCH v1 20/29] tcg/plugins: implement a qemu_plugin_user_exit helper
Date: Wed, 21 Jul 2021 00:26:54 +0100	[thread overview]
Message-ID: <20210720232703.10650-21-alex.bennee@linaro.org> (raw)
In-Reply-To: <20210720232703.10650-1-alex.bennee@linaro.org>

In user-mode emulation there is a small race between preexit_cleanup
and exit_group() which means we may end up calling instrumented
instructions before the kernel reaps child threads. To solve this we
implement a new helper which ensures the callbacks are flushed along
with any translations before we let the host do it's a thing.

While we are at it make the documentation of
qemu_plugin_register_atexit_cb clearer as to what the user can expect.

Signed-off-by: Alex Bennée <alex.bennee@linaro.org>
Reviewed-by: Mahmoud Mandour <ma.mandourr@gmail.com>
Acked-by: Warner Losh <imp@bsdimp.com>
Message-Id: <20210719123732.24457-1-alex.bennee@linaro.org>

---
v2
  - included qemu_plugin_disable_mem_helpers
---
 include/qemu/plugin.h      | 12 ++++++++++++
 include/qemu/qemu-plugin.h | 13 +++++++++++++
 bsd-user/syscall.c         |  6 +++---
 linux-user/exit.c          |  2 +-
 plugins/core.c             | 39 ++++++++++++++++++++++++++++++++++++++
 5 files changed, 68 insertions(+), 4 deletions(-)

diff --git a/include/qemu/plugin.h b/include/qemu/plugin.h
index 0fefbc6084..9a8438f683 100644
--- a/include/qemu/plugin.h
+++ b/include/qemu/plugin.h
@@ -190,6 +190,16 @@ void qemu_plugin_add_dyn_cb_arr(GArray *arr);
 
 void qemu_plugin_disable_mem_helpers(CPUState *cpu);
 
+/**
+ * qemu_plugin_user_exit(): clean-up callbacks before calling exit callbacks
+ *
+ * This is a user-mode only helper that ensure we have fully cleared
+ * callbacks from all threads before calling the exit callbacks. This
+ * is so the plugins themselves don't have to jump through hoops to
+ * guard against race conditions.
+ */
+void qemu_plugin_user_exit(void);
+
 #else /* !CONFIG_PLUGIN */
 
 static inline void qemu_plugin_add_opts(void)
@@ -250,6 +260,8 @@ void qemu_plugin_add_dyn_cb_arr(GArray *arr)
 static inline void qemu_plugin_disable_mem_helpers(CPUState *cpu)
 { }
 
+static inline void qemu_plugin_user_exit(void)
+{ }
 #endif /* !CONFIG_PLUGIN */
 
 #endif /* QEMU_PLUGIN_H */
diff --git a/include/qemu/qemu-plugin.h b/include/qemu/qemu-plugin.h
index dc3496f36c..e6e815abc5 100644
--- a/include/qemu/qemu-plugin.h
+++ b/include/qemu/qemu-plugin.h
@@ -549,6 +549,19 @@ void qemu_plugin_vcpu_for_each(qemu_plugin_id_t id,
 void qemu_plugin_register_flush_cb(qemu_plugin_id_t id,
                                    qemu_plugin_simple_cb_t cb);
 
+/**
+ * qemu_plugin_register_atexit_cb() - register exit callback
+ * @id: plugin ID
+ * @cb: callback
+ * @userdata: user data for callback
+ *
+ * The @cb function is called once execution has finished. Plugins
+ * should be able to free all their resources at this point much like
+ * after a reset/uninstall callback is called.
+ *
+ * In user-mode it is possible a few un-instrumented instructions from
+ * child threads may run before the host kernel reaps the threads.
+ */
 void qemu_plugin_register_atexit_cb(qemu_plugin_id_t id,
                                     qemu_plugin_udata_cb_t cb, void *userdata);
 
diff --git a/bsd-user/syscall.c b/bsd-user/syscall.c
index 7d986e9700..3f44311396 100644
--- a/bsd-user/syscall.c
+++ b/bsd-user/syscall.c
@@ -335,7 +335,7 @@ abi_long do_freebsd_syscall(void *cpu_env, int num, abi_long arg1,
         _mcleanup();
 #endif
         gdb_exit(arg1);
-        qemu_plugin_atexit_cb();
+        qemu_plugin_user_exit();
         /* XXX: should free thread stack and CPU env */
         _exit(arg1);
         ret = 0; /* avoid warning */
@@ -437,7 +437,7 @@ abi_long do_netbsd_syscall(void *cpu_env, int num, abi_long arg1,
         _mcleanup();
 #endif
         gdb_exit(arg1);
-        qemu_plugin_atexit_cb();
+        qemu_plugin_user_exit();
         /* XXX: should free thread stack and CPU env */
         _exit(arg1);
         ret = 0; /* avoid warning */
@@ -516,7 +516,7 @@ abi_long do_openbsd_syscall(void *cpu_env, int num, abi_long arg1,
         _mcleanup();
 #endif
         gdb_exit(arg1);
-        qemu_plugin_atexit_cb();
+        qemu_plugin_user_exit();
         /* XXX: should free thread stack and CPU env */
         _exit(arg1);
         ret = 0; /* avoid warning */
diff --git a/linux-user/exit.c b/linux-user/exit.c
index 70b344048c..527e29cbc1 100644
--- a/linux-user/exit.c
+++ b/linux-user/exit.c
@@ -35,5 +35,5 @@ void preexit_cleanup(CPUArchState *env, int code)
         __gcov_dump();
 #endif
         gdb_exit(code);
-        qemu_plugin_atexit_cb();
+        qemu_plugin_user_exit();
 }
diff --git a/plugins/core.c b/plugins/core.c
index e1bcdb570d..7cf4f87e18 100644
--- a/plugins/core.c
+++ b/plugins/core.c
@@ -487,6 +487,45 @@ void qemu_plugin_register_atexit_cb(qemu_plugin_id_t id,
     plugin_register_cb_udata(id, QEMU_PLUGIN_EV_ATEXIT, cb, udata);
 }
 
+/*
+ * Handle exit from linux-user. Unlike the normal atexit() mechanism
+ * we need to handle the clean-up manually as it's possible threads
+ * are still running. We need to remove all callbacks from code
+ * generation, flush the current translations and then we can safely
+ * trigger the exit callbacks.
+ */
+
+void qemu_plugin_user_exit(void)
+{
+    enum qemu_plugin_event ev;
+    CPUState *cpu;
+
+    QEMU_LOCK_GUARD(&plugin.lock);
+
+    start_exclusive();
+
+    /* un-register all callbacks except the final AT_EXIT one */
+    for (ev = 0; ev < QEMU_PLUGIN_EV_MAX; ev++) {
+        if (ev != QEMU_PLUGIN_EV_ATEXIT) {
+            struct qemu_plugin_ctx *ctx;
+            QTAILQ_FOREACH(ctx, &plugin.ctxs, entry) {
+                plugin_unregister_cb__locked(ctx, ev);
+            }
+        }
+    }
+
+    tb_flush(current_cpu);
+
+    CPU_FOREACH(cpu) {
+        qemu_plugin_disable_mem_helpers(cpu);
+    }
+
+    end_exclusive();
+
+    /* now it's safe to handle the exit case */
+    qemu_plugin_atexit_cb();
+}
+
 /*
  * Call this function after longjmp'ing to the main loop. It's possible that the
  * last instruction of a TB might have used helpers, and therefore the
-- 
2.32.0.264.g75ae10bc75



  parent reply	other threads:[~2021-07-20 23:53 UTC|newest]

Thread overview: 36+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2021-07-20 23:26 [PATCH for 6.1-rc1 v1 00/29] various fixes pre-PR (metadata, docs, plugins, testing) Alex Bennée
2021-07-20 23:26 ` [PATCH v1 01/29] gitignore: Update with some filetypes Alex Bennée
2021-07-20 23:26 ` [PATCH v1 02/29] docs: collect the disparate device emulation docs into one section Alex Bennée
2021-07-21 13:25   ` Markus Armbruster
2021-07-20 23:26 ` [PATCH v1 03/29] docs: add a section on the generalities of vhost-user Alex Bennée
2021-07-20 23:26 ` [PATCH v1 04/29] configure: remove needless if leg Alex Bennée
2021-07-20 23:26 ` [PATCH v1 05/29] contrib/gitdm: add some new aliases to fix up commits Alex Bennée
2021-07-20 23:26 ` [PATCH v1 06/29] .mailmap: fix up some broken commit authors Alex Bennée
2021-07-20 23:26 ` [PATCH v1 07/29] contrib/gitdm: add domain-map for MontaVista Alex Bennée
2021-07-20 23:26 ` [PATCH v1 08/29] contrib/gitdm: add a group mapping for robot scanners Alex Bennée
2021-07-20 23:26 ` [PATCH v1 09/29] gitdm.config: sort the corporate GroupMap entries Alex Bennée
2021-07-21  8:06   ` Philippe Mathieu-Daudé
2021-07-20 23:26 ` [PATCH v1 10/29] contrib/gitdm: add domain-map/group-map mappings for Samsung Alex Bennée
2021-07-20 23:26 ` [PATCH v1 11/29] contrib/gitdm: add domain-map for Eldorado Alex Bennée
2021-07-20 23:26 ` [PATCH v1 12/29] contrib/gitdm: add domain-map/group-map for Wind River Alex Bennée
2021-07-20 23:26 ` [PATCH v1 13/29] contrib/gitdm: un-ironically add a mapping for LWN Alex Bennée
2021-07-20 23:26 ` [PATCH v1 14/29] contrib/gitdm: add domain-map for Crudebyte Alex Bennée
2021-07-20 23:26 ` [PATCH v1 15/29] contrib/gitdm: add domain-map for NVIDIA Alex Bennée
2021-07-20 23:26 ` [PATCH v1 16/29] contrib/gitdm: add group-map for Netflix Alex Bennée
2021-07-20 23:26 ` [PATCH v1 17/29] contrib/gitdm: add an explicit academic entry for BU Alex Bennée
2021-07-20 23:26 ` [PATCH v1 18/29] contrib/gitdm: add a new interns group-map for GSoC/Outreachy work Alex Bennée
2021-07-20 23:26 ` [PATCH v1 19/29] contrib/gitdm: add more individual contributor entries Alex Bennée
2021-07-20 23:26 ` Alex Bennée [this message]
2021-07-20 23:26 ` [PATCH v1 21/29] plugins/cache: Fixed a bug with destroying FIFO metadata Alex Bennée
2021-07-20 23:26 ` [PATCH v1 22/29] plugins/cache: limited the scope of a mutex lock Alex Bennée
2021-07-20 23:26 ` [PATCH v1 23/29] plugins/cache: Fixed "function decl. is not a prototype" warnings Alex Bennée
2021-07-21  8:09   ` Philippe Mathieu-Daudé
2021-07-20 23:26 ` [PATCH v1 24/29] plugins: Fix physical address calculation for IO regions Alex Bennée
2021-07-20 23:26 ` [PATCH v1 25/29] hw/tricore: fix inclusion of tricore_testboard Alex Bennée
2021-08-02 16:07   ` Bastian Koppelmann
2021-07-20 23:27 ` [PATCH v1 26/29] tests/tcg/configure.sh: add handling for assembler only builds Alex Bennée
2021-07-20 23:27 ` [PATCH v1 27/29] gitlab: enable a very minimal build with the tricore container Alex Bennée
2021-07-21  7:05   ` Thomas Huth
2021-07-21 15:00   ` Willian Rampazzo
2021-07-20 23:27 ` [PATCH v1 28/29] gitlab-ci: Remove the second superfluous macos task Alex Bennée
2021-07-20 23:27 ` [PATCH v1 29/29] gitlab-ci: Extract OpenSBI job rules to reusable section Alex Bennée

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20210720232703.10650-21-alex.bennee@linaro.org \
    --to=alex.bennee@linaro.org \
    --cc=aurelien@aurel32.net \
    --cc=berrange@redhat.com \
    --cc=crosa@redhat.com \
    --cc=erdnaxe@crans.org \
    --cc=f4bug@amsat.org \
    --cc=fam@euphon.net \
    --cc=imp@bsdimp.com \
    --cc=kevans@freebsd.org \
    --cc=laurent@vivier.eu \
    --cc=ma.mandourr@gmail.com \
    --cc=pbonzini@redhat.com \
    --cc=qemu-devel@nongnu.org \
    --cc=stefanha@redhat.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.