mirror of
https://github.com/Motorhead1991/qemu.git
synced 2025-07-27 04:13:53 -06:00

macOS's Cocoa event handling must be done on the initial (main) thread of the process. Furthermore, if library or application code uses libdispatch, the main dispatch queue must be handling events on the main thread as well. So far, this has affected Qemu in both the Cocoa and SDL UIs, although in different ways: the Cocoa UI replaces the default qemu_main function with one that spins Qemu's internal main event loop off onto a background thread. SDL (which uses Cocoa internally) on the other hand uses a polling approach within Qemu's main event loop. Events are polled during the SDL UI's dpy_refresh callback, which happens to run on the main thread by default. As UIs are mutually exclusive, this works OK as long as nothing else needs platform-native event handling. In the next patch, a new device is introduced based on the ParavirtualizedGraphics.framework in macOS. This uses libdispatch internally, and only works when events are being handled on the main runloop. With the current system, it works when using either the Cocoa or the SDL UI. However, it does not when running headless. Moreover, any attempt to install a similar scheme to the Cocoa UI's main thread replacement fails when combined with the SDL UI. This change tidies up main thread management to be more flexible. * The qemu_main global function pointer is a custom function for the main thread, and it may now be NULL. When it is, the main thread runs the main Qemu loop. This represents the traditional setup. * When non-null, spawning the main Qemu event loop on a separate thread is now done centrally rather than inside the Cocoa UI code. * For most platforms, qemu_main is indeed NULL by default, but on Darwin, it defaults to a function that runs the CFRunLoop. * The Cocoa UI sets qemu_main to a function which runs the NSApplication event handling runloop, as is usual for a Cocoa app. * The SDL UI overrides the qemu_main function to NULL, thus specifying that Qemu's main loop must run on the main thread. * The GTK UI also overrides the qemu_main function to NULL. * For other UIs, or in the absence of UIs, the platform's default behaviour is followed. This means that on macOS, the platform's runloop events are always handled, regardless of chosen UI. The new PV graphics device will thus work in all configurations. There is no functional change on other operating systems. Implementing this via a global function pointer variable is a bit ugly, but it's probably worth investigating the existing UI thread rule violations in the SDL (e.g. #2537) and GTK+ back-ends. Fixing those issues might precipitate requirements similar but not identical to those of the Cocoa UI; hopefully we'll see some kind of pattern emerge, which can then be used as a basis for an overhaul. (In fact, it may turn out to be simplest to split the UI/native platform event thread from the QEMU main event loop on all platforms, with any UI or even none at all.) Signed-off-by: Phil Dennis-Jordan <phil@philjordan.eu> Reviewed-by: Akihiko Odaki <akihiko.odaki@daynix.com> Tested-by: Akihiko Odaki <akihiko.odaki@daynix.com> Message-ID: <20241223221645.29911-2-phil@philjordan.eu> [PMD: Declare 'qemu_main' symbol in tests/qtest/fuzz/fuzz.c, add missing g_assert_not_reached() call in main()] Signed-off-by: Philippe Mathieu-Daudé <philmd@linaro.org>
79 lines
2.3 KiB
C
79 lines
2.3 KiB
C
/*
|
|
* QEMU System Emulator
|
|
*
|
|
* Copyright (c) 2003-2020 Fabrice Bellard
|
|
*
|
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
* of this software and associated documentation files (the "Software"), to deal
|
|
* in the Software without restriction, including without limitation the rights
|
|
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
* copies of the Software, and to permit persons to whom the Software is
|
|
* furnished to do so, subject to the following conditions:
|
|
*
|
|
* The above copyright notice and this permission notice shall be included in
|
|
* all copies or substantial portions of the Software.
|
|
*
|
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
|
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
|
* THE SOFTWARE.
|
|
*/
|
|
|
|
#include "qemu/osdep.h"
|
|
#include "qemu-main.h"
|
|
#include "qemu/main-loop.h"
|
|
#include "system/system.h"
|
|
|
|
#ifdef CONFIG_SDL
|
|
/*
|
|
* SDL insists on wrapping the main() function with its own implementation on
|
|
* some platforms; it does so via a macro that renames our main function, so
|
|
* <SDL.h> must be #included here even with no SDL code called from this file.
|
|
*/
|
|
#include <SDL.h>
|
|
#endif
|
|
|
|
#ifdef CONFIG_DARWIN
|
|
#include <CoreFoundation/CoreFoundation.h>
|
|
#endif
|
|
|
|
static void *qemu_default_main(void *opaque)
|
|
{
|
|
int status;
|
|
|
|
bql_lock();
|
|
status = qemu_main_loop();
|
|
qemu_cleanup(status);
|
|
bql_unlock();
|
|
|
|
exit(status);
|
|
}
|
|
|
|
int (*qemu_main)(void);
|
|
|
|
#ifdef CONFIG_DARWIN
|
|
static int os_darwin_cfrunloop_main(void)
|
|
{
|
|
CFRunLoopRun();
|
|
g_assert_not_reached();
|
|
}
|
|
int (*qemu_main)(void) = os_darwin_cfrunloop_main;
|
|
#endif
|
|
|
|
int main(int argc, char **argv)
|
|
{
|
|
qemu_init(argc, argv);
|
|
bql_unlock();
|
|
if (qemu_main) {
|
|
QemuThread main_loop_thread;
|
|
qemu_thread_create(&main_loop_thread, "qemu_main",
|
|
qemu_default_main, NULL, QEMU_THREAD_DETACHED);
|
|
return qemu_main();
|
|
} else {
|
|
qemu_default_main(NULL);
|
|
g_assert_not_reached();
|
|
}
|
|
}
|