Repository navigation
client: report stream lifecycle RPC failure as error codes - #112
Open
davidonuoha wants to merge 1 commit into
Open
davidonuoha wants to merge 1 commit into
davidonuoha wants to merge 1 commit into
Conversation
The SoapySDR stream API reports failures through the return value:
deactivateStream() is documented as "0 for success or error code on
failure" and closeStream() returns void. These calls are also made from
places that cannot handle an exception:
- deactivateStream() is called from the destructor of gr::block_executor
(GNU Radio), which is implicitly noexcept. The client throws
std::runtime_error when the control connection is gone ("Connection
reset by peer", or EOF when the server went away), so losing the remote
link aborts the whole host process instead of reporting a dead device.
This is gqrx-sdr/gqrx#1445:
terminate reached from thread id: ... Got std::runtime_error
SoapyRPCUnpacker::recv(header) FAIL: recv() [104: Connection reset by peer]
... SoapyRemoteDevice::deactivateStream(...) [clone .cold]+0x2b
... gr::block_executor::~block_executor()+0x2b2
- activateStream() is called from the block_executor constructor on the
block threads. An exception there leaves the scheduler's start barrier
unsatisfied, so the host process deadlocks in top_block::unlock() on the
next flow graph reconfiguration instead of just failing.
- closeStream() is called from the destructor of the client device, and
returns void, so it has no way to report such a failure at all. Also
release the local stream data unconditionally, so a failed remote call
no longer leaks the endpoint.
Log the transport error through SoapySDR's logger and report
SOAPY_SDR_STREAM_ERROR, so that a lost link is visible as a device error.
setupStream() keeps throwing, as documented by SoapySDR.
Fixes: gqrx-sdr/gqrx#1445
Member
|
Thanks! Seems sensible, errors in teardown ( Let's keep this open for discussion for a few weeks, good to merge otherwise. |
|
I ran an independent test of this branch ( Setup
A UBSan build of this branch was clean on the failure scenarios. Platform: macOS arm64, SoapySDR 0.8.1. Separately, #113 fixes a hang in the RPC payload receive that this PR doesn't touch. Disclosure: done with AI assistance. |
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.
When the TCP control connection to the server is gone, the client throws
std::runtime_errorfromdeactivateStream(),activateStream()andcloseStream(). SoapySDR documents these as error-code /voidcalls(
SoapySDR/Device.hpp), and their real call sites are the constructor anddestructor of GNU Radio's
gr::block_executor(block_executor.cc:254), whichcannot handle an exception.
deactivateStream()throwing from that destructor aborts the host applicationthrough
std::terminate. Reported as gqrx-sdr/gqrx#1445: gqrx aborts about onetime in four when the modulation is changed or audio recording is started with an
SDRplay RSPdx behind SoapyRemote, because each of those actions tears down and
rebuilds the flow graph and therefore deactivates/reactivates the remote stream:
activateStream()is called from the same class's constructor, where an exceptionleaves the scheduler's start barrier unsatisfied and the next flow-graph restart
deadlocks instead of failing.
closeStream()is called from the client device'sdestructor and returns
void, so it has no way to report the failure at all.This change logs the transport error via SoapySDR's logger and returns
SOAPY_SDR_STREAM_ERRORfromdeactivateStream()/activateStream(); the loggingkeeps the original reason visible (
SoapyRemoteDevice::deactivateStream() FAIL: ...), so this reports a dead link rather than hiding it.closeStream()logs andstill releases the local stream data, which it previously leaked when the call
failed.
setupStream()keeps throwing, as documented. No protocol, API or ABIchange.
Tested without SDR hardware: a dummy SoapySDR device served by a real
SoapySDRServer, the control link closed with FIN, with RST, and with RST afterthe request was forwarded, teardown exercised from a
noexceptdestructor on aworker thread. Before: 4 of 9 cases abort with
SIGABRTand the messages above.After: no aborts, every failure logged and returned as
-2; healthyactivate/deactivate cycles and
SoapySDRUtil --check=remoteunchanged. Still needsone confirmation run on real hardware.