Skip to content

Fix Mac OS 9 boot hang when host sound output cannot be started - #215

Closed
probonopd wants to merge 6 commits into
dingusdev:masterfrom
probonopd:fix-macos9-boot-hang
Closed

Fix Mac OS 9 boot hang when host sound output cannot be started#215
probonopd wants to merge 6 commits into
dingusdev:masterfrom
probonopd:fix-macos9-boot-hang

Conversation

@probonopd

Copy link
Copy Markdown
Contributor

Summary

Fix a Mac OS 9 boot hang that occurs when the host audio stream cannot be started, and clean up the CUDA shutdown-watchdog handling that the guest drives via TIMER_TICKLE.

Background / diagnosis

Booting Mac OS 9.2.2 (from a Mac OS X Developer Preview 3 install CD) on the Power Mac G3 in realtime mode hung reliably ~18 s into the boot, right after:

Screamer: could not start sound output stream: -1

The guest sat at 100 % CPU forever, cycling between the ROM timebase delay loop and software floating-point helpers in low RAM (the 68k emulator's FP routines), with the last log event always being the failed sound stream start.

Root cause: the guest sound DMA is only advanced by DmaOutChannel::pull_data(), which in realtime mode is only ever called from the cubeb sound_out_callback. When cubeb_stream_start() fails (e.g. no working ALSA/PulseAudio output device on the host), the callback never fires, so the guest's Screamer driver never sees DMA progress and spins forever waiting for DMA interrupts. Notably, booting with --deterministic reached the desktop: deterministic mode already drains the DMA via a cyclic timer instead of relying on the host stream, confirming the mechanism.

Fix

soundserver_cubeb.cpp: set up the same cyclic-timer DMA drain used in deterministic mode unconditionally, and register it as a fallback whenever cubeb_stream_start() returns an error. The guest then sees its sound DMA advance (silence, since there is no working host output) and the boot proceeds. close_out_stream() now always cancels the fallback timer.

Also included

viacuda.cpp / viacuda.h: TIMER_TICKLE and SET_POWER_MESSAGES are handled instead of being logged as unsupported at WARNING level. The shutdown-watchdog count the guest arms via TIMER_TICKLE is tracked and logged at INFO, and the emulator never acts on watchdog expiry, so a guest that stops tickling cannot be powered off spuriously.

Testing

  • Mac OS 9.2.2 (DP3 CD) on Power Mac G3, realtime mode: boots all the way to the desktop without hanging. Previously it hung at ~18 s at 100 % CPU.
  • Host with no usable audio output device: sound stream start fails as before, but the guest boots instead of hanging.
  • --deterministic mode still reaches the desktop.

When the guest OS draws a hardware cursor into the framebuffer, the SDL
host pointer was still shown on top, so the user saw two cursors that did
not track each other. Hide the host pointer while a guest cursor is drawn
and show it again otherwise, so the user can aim the mouse at the window
when no guest cursor is present.
While a guest cursor is drawn, the host mouse is now grabbed automatically
so the guest cursor can reach every screen area and the host pointer cannot
wander off the window. The grab is released again when the guest cursor
disappears, and re-established when the window regains focus, because SDL
may drop the grab on focus loss. A manual grab with Ctrl+G is sticky and
overrides the automatic behavior.
The window title now reflects whether the mouse is grabbed and how to toggle
it, so the user knows how to release the automatic grab and move the pointer
to other windows, or how to re-grab it.
Log both commands at INFO instead of WARNING. Track the shutdown watchdog
count from TIMER_TICKLE and never act on expiry so the guest cannot be
powered off spuriously when it stops tickling.
…fails to start

If the host audio stream cannot be started (e.g. no working output device),
the guest sound DMA never advances because the cubeb callback that pulls
data is never invoked. The guest sound driver then stalls forever waiting
for DMA interrupts and the system hangs during boot. Fall back to draining
the DMA via a cyclic timer, as is already done in deterministic mode, so
the guest sees DMA progress even though there is no audible output.
@dingusdev

Copy link
Copy Markdown
Owner

The mouse grabbing stuff should be its own pull request. Please do not mix it in with bug fixes. I'll be merging in the VIA Cuda and Sound Server fixes.

@probonopd

probonopd commented Aug 17, 2026

Copy link
Copy Markdown
Contributor Author

Sorry. My bad. Will be more careful next time. I meant to only submit the last 2 commits.

With these fixes, i can boot Mac OS X DP3 without --deterministic, which was not possible before.

@dingusdev

Copy link
Copy Markdown
Owner

I've merged in the two last commits. It's all good now.

@dingusdev dingusdev closed this Aug 17, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants