Skip to content
  • Phil Dennis-Jordan's avatar
    f5ab12ca
    ui & main loop: Redesign of system-specific main thread event handling · f5ab12ca
    Phil Dennis-Jordan authored and Philippe Mathieu-Daudé's avatar Philippe Mathieu-Daudé committed
    
    
    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: default avatarPhil Dennis-Jordan <phil@philjordan.eu>
    Reviewed-by: default avatarAkihiko Odaki <akihiko.odaki@daynix.com>
    Tested-by: default avatarAkihiko 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: default avatarPhilippe Mathieu-Daudé <philmd@linaro.org>
    f5ab12ca
    ui & main loop: Redesign of system-specific main thread event handling
    Phil Dennis-Jordan authored and Philippe Mathieu-Daudé's avatar Philippe Mathieu-Daudé committed
    
    
    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: default avatarPhil Dennis-Jordan <phil@philjordan.eu>
    Reviewed-by: default avatarAkihiko Odaki <akihiko.odaki@daynix.com>
    Tested-by: default avatarAkihiko 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: default avatarPhilippe Mathieu-Daudé <philmd@linaro.org>
Loading