Skip to content

Fix macOS InstanceStorage upload wait hang in Gothic2Notr#943

Draft
Crissorl wants to merge 1 commit into
Try:masterfrom
Crissorl:codex/fix-instancestorage-upload-wait
Draft

Fix macOS InstanceStorage upload wait hang in Gothic2Notr#943
Crissorl wants to merge 1 commit into
Try:masterfrom
Crissorl:codex/fix-instancestorage-upload-wait

Conversation

@Crissorl
Copy link
Copy Markdown

@Crissorl Crissorl commented May 31, 2026

Summary

This fixes a reproducible macOS hang seen with Gothic2Notr / Gothic II: Night of the Raven by replacing the busy-wait in InstanceStorage::join() with a condition-variable wait, and by notifying the waiting render thread when the upload thread finishes a frame upload.

The reproduction was done with Gothic II: Night of the Raven data. The changed InstanceStorage path is part of the shared renderer, so this is not intentionally Gothic II script/content-specific.

The patch also changes Cpu32::popString() to return an empty std::string instead of 0 for an empty stack, which is required for a clean build with the current macOS clang/libc++ toolchain.

Root cause

On macOS arm64, the app could become unresponsive while rendering. A spindump taken during the hang showed the main thread stuck in:

MainWindow::render() -> Renderer::draw() -> InstanceStorage::join()

The old implementation repeatedly acquired and released sync until uploadFId < 0. At the same time, the upload worker could wait on uploadCnd without a predicate and did not notify after setting uploadFId = -1. In practice this could leave the main render path spinning around the mutex while the app was already marked "Application Not Responding" by macOS.

This patch makes both sides use explicit condition predicates:

  • join() sleeps until uploadFId < 0
  • uploadMain() sleeps until upload work is available
  • uploadMain() notifies after completing the upload and resetting uploadFId

Reproduction details

Observed with the macOS arm64 Gothic2Notr release build using Gothic II: Night of the Raven data on:

  • macOS 26.4.1, build 25E253
  • MacBook Pro, Mac16,8
  • Apple M4 Pro, 14 cores
  • 24 GB RAM
  • OpenGothic macOS arm64 Gothic2Notr build based on the current release

Symptoms:

  • the game did not crash
  • macOS reported the app as unresponsive
  • the process had to be terminated manually
  • spindump reported the process as unresponsive for 555 seconds before sampling
  • the sampled main thread repeatedly pointed at InstanceStorage::join()

After applying this patch, the same Gothic II: Night of the Raven save/load path ran without the recurring freeze during manual gameplay testing on the same machine. I did not observe further hangs or crashes during the remaining play session, and the game was noticeably more stable on this Mac.

Validation

  • Built successfully on macOS arm64:
    cmake --build build-ko --target Gothic2Notr -j 8
  • Manual runtime test with an existing Gothic II: Night of the Raven save that previously reproduced the hang.

@Crissorl Crissorl changed the title Fix InstanceStorage upload wait hang Fix macOS InstanceStorage upload wait hang in Gothic2Notr May 31, 2026
@Try
Copy link
Copy Markdown
Owner

Try commented May 31, 2026

Hi, @Crissorl and thanks for pr!

Lets take it into 2 parts: Cpu32::popString() and InstanceStorage.
Since popString blocks build on newer macos (and typo overall) - let me push it separately.

This patch makes both sides use explicit condition predicates

OK (maybe 2 conditional variables then), but symptoms are strange. Nither main-thread or InstanceStorage hold long to the mutex. For InstanceStorage - just to complete memcpy, before sleep on cond-var. For main - just to poke uploadFId status.
Basically, you saying that apple broke the scheduler on new MacOS :(

Try added a commit that referenced this pull request May 31, 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