Skip to content

Stop the connection manager before joining the update thread - #1049

Open
kel-mo wants to merge 1 commit into
kodi-pvr:Piersfrom
kel-mo:fix-destructor-race
Open

kel-mo wants to merge 1 commit into
kodi-pvr:Piersfrom
kel-mo:fix-destructor-race

Conversation

@kel-mo

@kel-mo kel-mo commented Oct 17, 2026

Copy link
Copy Markdown

Description

Kodi aborts in ~IptvSimple() if the add-on is disabled while its connection manager is still checking the M3U URL.

The destructor sets m_running = false and skips the join, because the update thread hasn't started yet. Then it calls connectionManager->Stop(), which waits for the connection thread. That thread is still in WebUtils::Check(). When the check succeeds, ConnectionManager::Process() calls SetState(PVR_CONNECTION_STATE_CONNECTED), so ConnectionEstablished() loads the playlist, sets m_running = true and starts m_thread. The destructor then finishes, and the still-joinable std::thread member calls std::terminate().

This change stops the connection manager first, so nothing can start the update thread once the destructor joins it.

Backtrace of the aborting thread without the change:

#5  std::terminate()
#6  IptvSimple::~IptvSimple() [clone .cold] () from pvr.iptvsimple.so.22.6.5
#7  IptvSimple::~IptvSimple() ()
#8  kodi::addon::CAddonBase::ADDONBASE_DestroyInstance(...)
#9  ADDON::CAddonDll::DestroyInstance  AddonDll.cpp:289
#11 PVR::CPVRClient::Destroy  PVRClient.cpp:572
#12 PVR::CPVRClients::StopClient  PVRClients.cpp:321
#13 PVR::CPVRClients::UpdateClients  PVRClients.cpp:270

Testing

Kodi 22.0 RC1 (Piers) flatpak on Linux x86_64, pvr.iptvsimple 22.6.5 (6d334f6):

  • I served the M3U from an HTTP server that waits 4 s before it answers and pointed an instance at it (remote path, cache off). Then I enabled the add-on and disabled it 1.5 s later with JSON-RPC Addons.SetAddonEnabled.
  • Without the change, Kodi aborted on the first try. With it, two tries in a row shut down cleanly: the update thread starts, the connection manager stops, then the destructor joins the update thread.

(Diagnosed with Claude Code.)

The connection manager thread can still be in its M3U check when the
instance is destroyed. If the check then succeeds, it calls
ConnectionEstablished(), which starts the update thread after the
destructor has already looked for it, and destroying the still-joinable
std::thread calls std::terminate().

Stop the connection manager first, so nothing can start the update
thread once the destructor joins it.

@garbear garbear left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

PR #1049 — Review

No blocking findings.

The shutdown ordering fixes the reported race without introducing an apparent regression. CI checks passed.

Verdict: Approve.

@kel-mo kel-mo mentioned this pull request Nov 6, 2026
1 of 7 tasks
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants