Assign descriptive names to SDRangel threads so thread activity can be
identified when investigating multi-threaded behavior, including crashes,
leaks, and synchronization issues in debuggers and others tools.
Use compact names to fit platform thread-name limits (14 chars) while
retaining the component and thread role where possible.
Signed-off-by: Robin Getz <rgetz503@gmail.com>
MessageQueue::pop() transfers ownership of the popped message to the
caller, but many handleInputMessages() implementations only deleted
the message when handleMessage() returned true. When a message was not
handled, ownership had already been transferred from the queue and the
message was leaked.
This was identified while investigating an ASAN leak in the audio
subsystem.
Update the applicable handleInputMessages() implementations to always
delete messages after handleMessage() returns. Unhandled messages are
also logged with the component and message identifier so unexpected
message routing is visible during debugging.
This change:
- Ensures every message popped from a queue has its ownership resolved.
- Prevents leaks when handleMessage() returns false.
- Makes unhandled messages visible instead of silently discarding them.
- Preserves the existing message handling logic and does not require
components to handle message types that are legitimately irrelevant
to them.
The changes are intentionally mechanical and limited to the common
message queue ownership and diagnostic pattern.
Signed-off-by: Robin Getz <rgetz503@gmail.com>
Every feature GUI ran its own one second QTimer, read getState(), compared
it against a remembered m_lastFeatureState and restyled its start/stop
button when the two differed. The same twenty five lines appeared in each
of them.
Feature now keeps m_state private behind setState(), which emits
stateChanged() when it actually changes, and FeatureGUI grows a shared
updateStartStopButton() that restyles the button and reports an error
state. A GUI connects to the signal and calls that, so the state is
reflected as soon as it changes rather than up to a second later, and the
per feature timers and m_lastFeatureState members are gone.
FeatureUISet disconnects the feature from its GUI before the feature is
deleted: QObject emits destroyed() before dropping its connections, so a
stateChanged() emitted from the feature's destructor could otherwise reach
a GUI that has already deleted its ui object.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
QMessageBox::information() and friends build the box on the stack, parent
it to the calling widget and run a nested event loop in exec(). If the
parent is closed while the box is open, which the Web API can do at any
time, the parent deletes the box and its children and the heap is
corrupted.
MessageDialog offers the same calls, but the box is heap allocated, given
Qt::WA_DeleteOnClose and shown rather than exec'd, so nothing runs a
nested event loop and the box owns its own lifetime. A box with the same
text as one already up is raised instead of a second being created.
The trade off is that information(), warning() and critical() return
immediately and cannot report which button was pressed. question() takes
a callback for the cases that need the answer.
Converts the call sites in the device, channel and feature GUIs.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
The generated SWG setters overwrite the string pointer without deleting
what is already there, and every webapiSettingsGet and webapiReportGet
calls init() first, which has allocated one. Each call therefore leaked a
QString per string field. Measured at 117 bytes per settings GET for the
Satellite Tracker, over 20,000 requests.
Assign in place when the pointer is already set, which is what these same
functions have always done for title and reverseAPIAddress. 394 sites
across webapiFormatChannelSettings, webapiFormatDeviceSettings,
webapiFormatFeatureSettings and the three report equivalents.
The webapiReverseSend* functions are deliberately left alone: they build a
fresh SWG object whose constructor leaves the pointers null, so passing a
new QString is correct there.
After the change the same measurement is flat, at 7 bytes per GET.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
VOR localizer: Allow plugin to be compiled as static lib.
SID feature: Allow plugin to be compiled as static lib.
Satellite Tracker: Allow building without texttospeech or timezone.
Map: Allow plugin to be compiled as static lib. Allow building without SSL.
APT: Allow plugin to be compiled as static lib.
Radio Astronomy: Allow plugin to be compiled as static lib. Allow building without process.
ChannelWebAPIUtils: Fix memory leaks.
DeviceSampleSource: Add signals that indicate when the position or direction of a device (or it's antenna) has changed. This is to support per device position, which is useful for remote devices not at My Position.
Frees memory allocated
in AudioOutputPlugin::createSampleSinkPluginInstance(QString const&, DeviceAPI*) /home//sdrangel/plugins/samplesink/audiooutput/audiooutputplugin.cpp:136
in ChirpChatDemod::ChirpChatDemod(DeviceAPI*) /home/sdrangel/plugins/channelrx/demodchirpchat/chirpchatdemod.cpp:84
in FileOutput::FileOutput(DeviceAPI*) /home/sdrangel/plugins/samplesink/fileoutput/fileoutput.cpp:54
in RadioAstronomyGUI::RadioAstronomyGUI(PluginAPI*, DeviceUISet*, BasebandSampleSink*, QWidget*) /home/sdrangel/plugins/channelrx/radioastronomy/radioastronomygui.cpp:2061
in SatelliteSelectionDialog::SatelliteSelectionDialog(SatelliteTrackerSettings*, QHash<QString, SatNogsSatellite*> const&, QWidget*) /home/sdrangel/plugins/feature/satellitetracker/satelliteselectiondialog.cpp:42:24
in SatelliteTracker::SatelliteTracker(WebAPIAdapterInterface*) /home/sdrangel/plugins/feature/satellitetracker/satellitetracker.cpp:61:24
Most plugins that use reverse API to PATCH settings updates to remote
server only do so when `useReverseAPI` is toggled, but not when the
relevant settings are being updated. So lets fix the precondition to
use the `m_useReverseAPI` flag instead.