From: Pierrick Bouvier <pierrick.bouvier@linaro.org>
To: "Nicholas Piggin" <npiggin@gmail.com>,
"Philippe Mathieu-Daudé" <philmd@linaro.org>,
qemu-devel@nongnu.org
Cc: "Stefan Hajnoczi" <stefanha@redhat.com>,
"Alex Bennée" <alex.bennee@linaro.org>,
"Paolo Bonzini" <pbonzini@redhat.com>,
"Phil Dennis-Jordan" <phil@philjordan.eu>
Subject: Re: [PATCH 1/2] system/main: transfer replay mutex ownership from main thread to main loop thread
Date: Tue, 15 Apr 2025 11:31:54 -0700 [thread overview]
Message-ID: <f8a90e7b-daa7-4c87-9702-e80e9d5b162e@linaro.org> (raw)
In-Reply-To: <D96V6HTTNOF1.3DDO2NQ0AUEA0@gmail.com>
On 4/14/25 19:41, Nicholas Piggin wrote:
> On Tue Apr 15, 2025 at 1:24 AM AEST, Pierrick Bouvier wrote:
>> On 4/14/25 03:25, Philippe Mathieu-Daudé wrote:
>>> On 12/4/25 19:24, Pierrick Bouvier wrote:
>>>> On 4/11/25 22:30, Nicholas Piggin wrote:
>>>>> On Fri Apr 11, 2025 at 8:55 AM AEST, Pierrick Bouvier wrote:
>>>>>> On MacOS, UI event loop has to be ran in the main thread of a process.
>>>>>> Because of that restriction, on this platform, qemu main event loop is
>>>>>> ran on another thread [1].
>>>>>>
>>>>>> This breaks record/replay feature, which expects thread running
>>>>>> qemu_init
>>>>>> to initialize hold this lock, breaking associated functional tests on
>>>>>> MacOS.
>>>>>>
>>>>>> Thus, as a generalization, and similar to how BQL is handled, we release
>>>>>> it after init, and reacquire the lock before entering main event loop,
>>>>>> avoiding a special case if a separate thread is used.
>>>>>>
>>>>>> Tested on MacOS with:
>>>>>> $ meson test -C build --setup thorough --print-errorlogs \
>>>>>> func-x86_64-x86_64_replay func-arm-arm_replay func-aarch64-
>>>>>> aarch64_replay
>>>>>> $ ./build/qemu-system-x86_64 -nographic -icount
>>>>>> shift=auto,rr=record,rrfile=replay.log
>>>>>> $ ./build/qemu-system-x86_64 -nographic -icount
>>>>>> shift=auto,rr=replay,rrfile=replay.log
>>>>>>
>>>>>> [1] https://gitlab.com/qemu-project/qemu/-/commit/
>>>>>> f5ab12caba4f1656479c1feb5248beac1c833243
>>>>>>
>>>>>> Fixes: https://gitlab.com/qemu-project/qemu/-/issues/2907
>>>>>> Signed-off-by: Pierrick Bouvier <pierrick.bouvier@linaro.org>
>>>>>> ---
>>>>>> system/main.c | 4 ++++
>>>>>> 1 file changed, 4 insertions(+)
>>>>>>
>>>>>> diff --git a/system/main.c b/system/main.c
>>>>>> index ecb12fd397c..1c022067349 100644
>>>>>> --- a/system/main.c
>>>>>> +++ b/system/main.c
>>>>>> @@ -25,6 +25,7 @@
>>>>>> #include "qemu/osdep.h"
>>>>>> #include "qemu-main.h"
>>>>>> #include "qemu/main-loop.h"
>>>>>> +#include "system/replay.h"
>>>>>> #include "system/system.h"
>>>>>> #ifdef CONFIG_SDL
>>>>>> @@ -44,10 +45,12 @@ static void *qemu_default_main(void *opaque)
>>>>>> {
>>>>>> int status;
>>>>>> + replay_mutex_lock();
>>>>>> bql_lock();
>>>>>> status = qemu_main_loop();
>>>>>> qemu_cleanup(status);
>>>>>> bql_unlock();
>>>>>> + replay_mutex_unlock();
>>>>>> exit(status);
>>>>>> }
>>>>>> @@ -67,6 +70,7 @@ int main(int argc, char **argv)
>>>>>> {
>>>>>> qemu_init(argc, argv);
>>>>>> bql_unlock();
>>>>>> + replay_mutex_unlock();
>>>>>> if (qemu_main) {
>>>>>> QemuThread main_loop_thread;
>>>>>> qemu_thread_create(&main_loop_thread, "qemu_main",
>>>>>
>>>>> Do we actually need to hold replay mutex (or even bql) over qemu_init()?
>>>>> Both should get dropped before we return here. But as a simple fix, I
>>>>> guess this is okay.
>>>>>
>>>>
>>>> For the bql, I don't know the exact reason.
>>>> For replay lock, we need to hold it as clock gets saved as soon as the
>>>> devices are initialized, which happens before end of qemu_init.
>>>
>>> Could be worth adding a comment with that information.
>>>
>>
>> In case someone is curious about it, changing default state of lock can
>> answer why it's needed, as it crashes immediately on an assert.
>
> That all sounds reasonable enough and good info. I'm not suggesting to
> remove the lock from qemu_init() by assuming we are in init and init is
> single threaded (I agree it's good practice to keep locking consistent).
>
> My question was more that we should move the locks tighter around
> the operations that require them. Move the unlock into qemu_init().
>
> Commit f5ab12caba4f1 didn't introduce this problem, cocoa_main()
> already immediatey called bql_unlock() so effectively the issue is
> still there. The original design before cocoa I guess was that qemu_init
> would init things under the same critical section as qemu_main_loop() is
> then called, which is reasonable and conservative. It would have been
> good to see this bql split get a specific patch to epxlain why it's not
> needed across qemu_init and qemu_main_loop, but no big deal now.
>
Looking more closely, bql_lock ensure vcpus don't start executing
anything before init is completed. So we really want to hold the lock
through all qemu_init().
Concerning replay_lock, during init, icount_configure calls
qemu_clock_get_ns, that calls replay_save_clock, which expects to have
the lock. Thus, we should hold the lock, at least during icount
configuration.
> The patch is fine for a fix, could I suggest another patch that
> moves the lock narrower and perhaps adds a few words of comment?
>
We would still need to acquire locks in qemu_default_main() anyway.
For bql, we definitely want to hold it anytime through init, so the
scope is end of init.
For replay_lock, it could be moved around parts that expect it during
initialization, but what would be the benefit, considering only one
thread is running during init?
Moving locks narrower is usually made to allow more concurrency, at the
price of increased complexity. In init phase, only one thread runs
anyway, so there is no benefit to do anything around here.
What we could eventually do is move those unlock at the end of
qemu_init, but IMHO, it's more readable to see the lock/unlock scheme in
a single place, in system/main.c.
As well, I think it's better to have a single code path for lock/unlock,
whether we use a background thread or not (vs adding a bool parameter to
qemu_default_main() saying if we are in the same thread, or a different
one).
> Thanks,
> Nick
next prev parent reply other threads:[~2025-04-15 18:32 UTC|newest]
Thread overview: 15+ messages / expand[flat|nested] mbox.gz Atom feed top
2025-04-10 22:55 [PATCH 0/2] fix record/replay on MacOS Pierrick Bouvier
2025-04-10 22:55 ` [PATCH 1/2] system/main: transfer replay mutex ownership from main thread to main loop thread Pierrick Bouvier
2025-04-12 5:30 ` Nicholas Piggin
2025-04-12 17:24 ` Pierrick Bouvier
2025-04-14 10:25 ` Philippe Mathieu-Daudé
2025-04-14 15:24 ` Pierrick Bouvier
2025-04-15 2:41 ` Nicholas Piggin
2025-04-15 18:31 ` Pierrick Bouvier [this message]
2025-04-16 3:16 ` Nicholas Piggin
2025-04-16 18:54 ` Pierrick Bouvier
2025-04-14 10:57 ` Paolo Bonzini
2025-04-10 22:55 ` [PATCH 2/2] tests/functional/test_aarch64_replay: reenable on macos Pierrick Bouvier
2025-04-11 13:42 ` [PATCH 0/2] fix record/replay on MacOS Philippe Mathieu-Daudé
2025-04-14 15:14 ` Stefan Hajnoczi
2025-04-14 15:25 ` Pierrick Bouvier
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=f8a90e7b-daa7-4c87-9702-e80e9d5b162e@linaro.org \
--to=pierrick.bouvier@linaro.org \
--cc=alex.bennee@linaro.org \
--cc=npiggin@gmail.com \
--cc=pbonzini@redhat.com \
--cc=phil@philjordan.eu \
--cc=philmd@linaro.org \
--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 a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).