Conversation
amy_event_to_deltas_queue() allocates the addressed osc (and a referenced chained/mod osc) on whatever thread sent the event, without the queue lock. FREE_OSC runs on the render thread inside flush_due_deltas(), which holds it. A patch load queues frees for the old voice's oscs and then allocates the same osc numbers for the new voice, so the render thread can free an osc while the sending thread is still in alloc_osc() / reset_osc() -- a store through NULL at reset_osc's synth[i]->osc = i, or writes into freed memory. Seen on a dual-core ESP32-P4 reloading a synth's patch from the application core while the render task runs on the other: a Store access fault in reset_osc on about one reload in six. With the lock, 30 reloads in a row ran clean. The ingest path never holds the lock on entry (it takes it again in add_delta_to_queue), so this cannot self-deadlock.
Contributor
🎛️ AMY HW CI (AMYboard bench)Flashed this PR's AMY (LoadTestChord: 6-voice Juno ✅ PASS — the bench ran the test to completion.
Full chord settled render μs: 2613 (was 2596, Δ +0.7%) (peak 2619, 39 samples) ⬇️ Artifacts: serial log · load trace · report Self-hosted bench (amyboardci). FAIL means only that the test could not run — the load values are informational, with no threshold and no audio compare. See |
This branch has not been deployed
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
`amy_event_to_deltas_queue()` allocates the osc an event addresses (and a chained/mod osc it references) on whatever thread sent the event, without the queue lock. `FREE_OSC` is executed on the render thread inside `flush_due_deltas()`, which does hold it.
A patch load queues frees for the old voice's oscs, then allocates the same osc numbers for the new voice. So the render thread can free an osc while the sending thread is still inside `alloc_osc()` / `reset_osc()`. The result is either a store through NULL at `synth[i]->osc = i` (amy.c
reset_osc), or writes into freed memory.Seen on: a dual-core ESP32-P4, where a synth's patch is reloaded from the application core while the render task runs on the other core. The failure was a Store access fault in
reset_osc(stack:amy_parse_message→patches_load_patch→parse_patch_string_to_queue→amy_event_to_deltas_queue→ensure_osc_allocd→alloc_osc→reset_osc), roughly once in every six reloads.The change: the two ingest-path allocations now go through
ensure_osc_allocd_ingest(), which takes the lock aroundensure_osc_allocd(). The ingest path never holds the lock on entry (it takes it again inadd_delta_to_queue()), so this can't self-deadlock. Render-thread callers are unchanged.Tested: after the change, 30 reloads in a row on the same board ran clean. Before it, the fault appeared by the 6th.
🤖 Generated with Claude Code