runtime: add fast path for non-blocking single-state select#5500
Open
rdon-key wants to merge 1 commit into
Open
runtime: add fast path for non-blocking single-state select#5500rdon-key wants to merge 1 commit into
rdon-key wants to merge 1 commit into
Conversation
Contributor
Author
|
Additional stability test: a #4975-style workload ran successfully with this PR applied. Setup: pico, -scheduler=cores, SSD1306 OLED over I2C at 400kHz, SDA=GP12, SCL=GP13, address 0x3c, 128x32 display. After adjusting the reproducer for the current ssd1306.NewI2C API (*ssd1306.Device), it completed two 30-minute runs without freezin |
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.
Fixes #4974.
This PR adds a fast path in
chanSelectfor non-blocking single-state selects.For example:
This form can lock at most one channel, so it does not need the global
chanSelectLock, which is used to avoid deadlocks when multiple channels may be locked in different orders.This fast path does not use
chanSelectLock, and also avoidslockAllStates/unlockAllStates. Instead, when parallelism is enabled, it directly locks and unlocks the target channel.lockAllStates/unlockAllStatesusechannel.selectLocked, and that state is protected bychanSelectLock. Therefore, simply skippingchanSelectLockwhile still usinglockAllStates/unlockAllStatesis not safe. The fast path avoids both.Background
#4974 reports a freeze on RP2040 with
-scheduler=coreswhen using channels, goroutines, and timers together.While investigating this issue, I found that a repeated single-channel select send with a default case can reproduce a freeze on RP2040/RP2350 with
-scheduler=cores.The minimized reproducer repeatedly sends from a timer goroutine using this form:
A receiver goroutine continuously receives from the same channel.
At the time of freeze, the last report showed:
So the issue did not appear to be caused by entering the default branch. It looked related to the successful send path through
chanSelectand the receiver wakeup path.Reproducer
I used
a03_nonblocking_select_send_large_buffer_receiver.goas a minimized reproducer.Details
The important part is this single-state default select send:
This form uses
runtime.chanSelectand reproduced the freeze on RP2040/RP2350 with-scheduler=cores.At the time of freeze, the report showed:
This suggests that the channel values were not being lost. Instead, progress appeared to stop around the successful
chanSelectsend path and receiver wakeup.Control case
I also used
a06_two_state_select_send_full_case.goas a multi-state select control.Details
The important part is:
otherChis pre-filled, so the second send case should normally not be selected.This test is intended to check that the existing multi-state select path is not broken. With this PR, multi-state selects still use the existing
chanSelectLockpath.Investigation
I first tried skipping only
chanSelectLockfor single-state selects. However, while still usinglockAllStates/unlockAllStates, the #4974 reproducer hit this panic:This happened because
lockAllStates/unlockAllStatesusechannel.selectLocked, and that state is protected bychanSelectLock.Therefore, this PR adds a dedicated fast path for non-blocking single-state selects. This path avoids both
chanSelectLockandlockAllStates/unlockAllStates, while still directly locking the channel when parallelism is enabled.Validation
RP2040 /
-scheduler=coresa03single-state default select reproducer: 3/3 completeda06multi-state select control: 3/3 completedRP2040 /
-scheduler=tasksa03single-state default select reproducer: 1/1 completeda06multi-state select control: 1/1 completedRP2350 /
-scheduler=coresa03single-state default select reproducer: 3/3 completeda06multi-state select control: 3/3 completedRP2350 /
-scheduler=tasksa03single-state default select reproducer: 1/1 completeda06multi-state select control: 1/1 completedBefore this change
a03reproducer repeatedly froze on RP2040.a03reproducer also reproduced the freeze on RP2350.Notes
This change only adds a fast path for non-blocking single-state selects.
Multi-state selects continue to use the existing
chanSelectLockpath, so the existing protection against deadlocks from locking multiple channels in different orders is preserved.The fast path still directly locks and unlocks the target channel when parallelism is enabled, so channel-level protection is preserved.