plugins: add [pre|post]fork helpers to linux-user

Special care needs to be taken in ensuring locks are in a consistent
state across fork events. Add helpers so the plugin system can ensure
that.

Signed-off-by: Alex Bennée <alex.bennee@linaro.org>
Fixes: https://gitlab.com/qemu-project/qemu/-/issues/358
Reviewed-by: Daniel P. Berrangé <berrange@redhat.com>
Tested-by: Daniel P. Berrangé <berrange@redhat.com>
Message-Id: <20221004115221.2174499-1-alex.bennee@linaro.org>
This commit is contained in:
Alex Bennée 2022-10-04 12:52:21 +01:00
parent 37e62694e4
commit f7e15affa8
3 changed files with 46 additions and 0 deletions

View File

@ -224,6 +224,23 @@ void qemu_plugin_disable_mem_helpers(CPUState *cpu);
*/ */
void qemu_plugin_user_exit(void); void qemu_plugin_user_exit(void);
/**
* qemu_plugin_user_prefork_lock(): take plugin lock before forking
*
* This is a user-mode only helper to take the internal plugin lock
* before a fork event. This is ensure a consistent lock state
*/
void qemu_plugin_user_prefork_lock(void);
/**
* qemu_plugin_user_postfork(): reset the plugin lock
* @is_child: is this thread the child
*
* This user-mode only helper resets the lock state after a fork so we
* can continue using the plugin interface.
*/
void qemu_plugin_user_postfork(bool is_child);
#else /* !CONFIG_PLUGIN */ #else /* !CONFIG_PLUGIN */
static inline void qemu_plugin_add_opts(void) static inline void qemu_plugin_add_opts(void)
@ -287,6 +304,13 @@ static inline void qemu_plugin_disable_mem_helpers(CPUState *cpu)
static inline void qemu_plugin_user_exit(void) static inline void qemu_plugin_user_exit(void)
{ } { }
static inline void qemu_plugin_user_prefork_lock(void)
{ }
static inline void qemu_plugin_user_postfork(bool is_child)
{ }
#endif /* !CONFIG_PLUGIN */ #endif /* !CONFIG_PLUGIN */
#endif /* QEMU_PLUGIN_H */ #endif /* QEMU_PLUGIN_H */

View File

@ -142,10 +142,12 @@ void fork_start(void)
start_exclusive(); start_exclusive();
mmap_fork_start(); mmap_fork_start();
cpu_list_lock(); cpu_list_lock();
qemu_plugin_user_prefork_lock();
} }
void fork_end(int child) void fork_end(int child)
{ {
qemu_plugin_user_postfork(child);
mmap_fork_end(child); mmap_fork_end(child);
if (child) { if (child) {
CPUState *cpu, *next_cpu; CPUState *cpu, *next_cpu;

View File

@ -526,6 +526,26 @@ void qemu_plugin_user_exit(void)
qemu_plugin_atexit_cb(); qemu_plugin_atexit_cb();
} }
/*
* Helpers for *-user to ensure locks are sane across fork() events.
*/
void qemu_plugin_user_prefork_lock(void)
{
qemu_rec_mutex_lock(&plugin.lock);
}
void qemu_plugin_user_postfork(bool is_child)
{
if (is_child) {
/* should we just reset via plugin_init? */
qemu_rec_mutex_init(&plugin.lock);
} else {
qemu_rec_mutex_unlock(&plugin.lock);
}
}
/* /*
* Call this function after longjmp'ing to the main loop. It's possible that the * 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 * last instruction of a TB might have used helpers, and therefore the