All of lore.kernel.org
 help / color / mirror / Atom feed
From: "Alex Bennée" <alex.bennee@linaro.org>
To: peter.maydell@linaro.org
Cc: "Kyle Evans" <kevans@freebsd.org>,
	qemu-devel@nongnu.org, "Laurent Vivier" <laurent@vivier.eu>,
	"Alexandre Iooss" <erdnaxe@crans.org>,
	"Mahmoud Mandour" <ma.mandourr@gmail.com>,
	"Alex Bennée" <alex.bennee@linaro.org>,
	"Warner Losh" <imp@bsdimp.com>
Subject: [PULL 20/28] tcg/plugins: implement a qemu_plugin_user_exit helper
Date: Fri, 23 Jul 2021 18:03:46 +0100	[thread overview]
Message-ID: <20210723170354.18975-21-alex.bennee@linaro.org> (raw)
In-Reply-To: <20210723170354.18975-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: <20210720232703.10650-21-alex.bennee@linaro.org>

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 474db287cb..6b2490f973 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.20.1



  parent reply	other threads:[~2021-07-23 17:10 UTC|newest]

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

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=20210723170354.18975-21-alex.bennee@linaro.org \
    --to=alex.bennee@linaro.org \
    --cc=erdnaxe@crans.org \
    --cc=imp@bsdimp.com \
    --cc=kevans@freebsd.org \
    --cc=laurent@vivier.eu \
    --cc=ma.mandourr@gmail.com \
    --cc=peter.maydell@linaro.org \
    --cc=qemu-devel@nongnu.org \
    /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.