Summary
GetSdCardFilesAsync / DeleteSdCardFileAsync now switch the shared SPI bus to the SD card inside the text-exchange lock (via the prepareAsync phase added in #406), but they still restore it to LAN outside that lock, from each method's finally. The switch is serialized; the restore is not.
Trace
#406 fixed the acquire side: PrepareSdInterface() + the settle delay run as the exchange's prepare phase, inside _textExchangeLock and ahead of the stale-line boundary. The release side was deliberately left alone and is called from the finally of each SD method, after ExecuteTextCommandAsync has returned and released the lock.
So a second text exchange can interleave between one operation's LIST/DELETE and its PrepareLanInterface(), or observe the bus mid-restore:
thread A: [lock] switch to SD, LIST [unlock]
thread B: [lock] ... some other exchange ... [unlock]
thread A: PrepareLanInterface() <- restores LAN under B's feet, or after B already did
Why it matters
This is the same class of defect #406 fixed, just on the other half of the operation. It is on main today.
It is also narrower than #342: that issue asks the open question of whether Core should serialize all mutating operations per device, and what the concurrency contract should be. This one is a concrete asymmetry inside a path that already has a lock — the acquire is protected and the matching release is not — and can be closed without settling #342.
Suggested direction
A symmetric finalize seam on the exchange, so the restore runs under the same lock that the prepare does. The awkward part, and why it was not folded into #406: it has to run even when the exchange throws, so it is not simply "another prepare at the end" — it needs the exchange to own a try/finally around the caller's finalize action, and to decide what happens if the finalize itself throws while an exception is already in flight.
Worth checking at the same time whether the restore should run at all when the transfer was abandoned on a deadline (see #399/#401), since the abandoned worker may still be using the bus.
Notes
Found while reviewing #406. Not a regression from it — the restore was outside the lock before that PR too; #406 simply made the asymmetry visible by moving the acquire side in.
Refs: #406, #396, #342, #399.
Summary
GetSdCardFilesAsync/DeleteSdCardFileAsyncnow switch the shared SPI bus to the SD card inside the text-exchange lock (via theprepareAsyncphase added in #406), but they still restore it to LAN outside that lock, from each method'sfinally. The switch is serialized; the restore is not.Trace
#406 fixed the acquire side:
PrepareSdInterface()+ the settle delay run as the exchange's prepare phase, inside_textExchangeLockand ahead of the stale-line boundary. The release side was deliberately left alone and is called from thefinallyof each SD method, afterExecuteTextCommandAsynchas returned and released the lock.So a second text exchange can interleave between one operation's LIST/DELETE and its
PrepareLanInterface(), or observe the bus mid-restore:Why it matters
This is the same class of defect #406 fixed, just on the other half of the operation. It is on
maintoday.It is also narrower than #342: that issue asks the open question of whether Core should serialize all mutating operations per device, and what the concurrency contract should be. This one is a concrete asymmetry inside a path that already has a lock — the acquire is protected and the matching release is not — and can be closed without settling #342.
Suggested direction
A symmetric finalize seam on the exchange, so the restore runs under the same lock that the prepare does. The awkward part, and why it was not folded into #406: it has to run even when the exchange throws, so it is not simply "another prepare at the end" — it needs the exchange to own a try/finally around the caller's finalize action, and to decide what happens if the finalize itself throws while an exception is already in flight.
Worth checking at the same time whether the restore should run at all when the transfer was abandoned on a deadline (see #399/#401), since the abandoned worker may still be using the bus.
Notes
Found while reviewing #406. Not a regression from it — the restore was outside the lock before that PR too; #406 simply made the asymmetry visible by moving the acquire side in.
Refs: #406, #396, #342, #399.