@@ -8151,10 +8151,33 @@ void PrivateInstanceAAMP::Stop( bool isDestructing )
81518151 {
81528152 std::lock_guard<std::mutex> guard (mMutexPlaystart );
81538153 waitforplaystart.notify_all ();
8154+ AAMPLOG_WARN (" HariPriya Stop: notified PreCache thread, isDestructing=%d" , isDestructing);
81548155 }
81558156 if (mPreCachePlaylistThreadId .joinable ())
81568157 {
8157- mPreCachePlaylistThreadId .join ();
8158+ auto joinStartTime = NOW_STEADY_TS_MS;
8159+ AAMPLOG_WARN (" HariPriya Stop: About to join PreCache thread, isDestructing=%d" , isDestructing);
8160+
8161+ // Fix for GC deadlock: During GC finalization (isDestructing=true), the PreCache thread
8162+ // may be blocked in network I/O (curl_easy_perform). Using join() would block the main
8163+ // thread indefinitely, causing freeze/crash. Instead, use detach() to let the thread
8164+ // clean up itself. The thread will exit safely once network I/O completes.
8165+ if (isDestructing)
8166+ {
8167+ AAMPLOG_WARN (" HariPriya Stop: Detaching PreCache thread (GC path) to avoid blocking, isDestructing=%d" , isDestructing);
8168+ mPreCachePlaylistThreadId .detach ();
8169+ }
8170+ else
8171+ {
8172+ // Normal stop path - wait for thread to complete
8173+ mPreCachePlaylistThreadId .join ();
8174+ auto joinDuration = NOW_STEADY_TS_MS - joinStartTime;
8175+ AAMPLOG_WARN (" HariPriya Stop: PreCache thread joined after %lld ms, isDestructing=%d" , joinDuration, isDestructing);
8176+ }
8177+ }
8178+ else
8179+ {
8180+ AAMPLOG_INFO (" HariPriya Stop: PreCache thread not joinable, isDestructing=%d" , isDestructing);
81588181 }
81598182
81608183 if (mAampCacheHandler )
@@ -10271,14 +10294,17 @@ void PrivateInstanceAAMP::PreCachePlaylistDownloadTask()
1027110294{
1027210295 // This is the thread function to download all the HLS Playlist in a
1027310296 // differed manner
10297+ AAMPLOG_WARN (" PreCachePlaylistDownloadTask: Thread started" );
1027410298 int maxWindowForDownload = mPreCacheDnldTimeWindow * 60 ; // convert to seconds
1027510299 int szPlaylistCount = (int )mPreCacheDnldList .size ();
1027610300 if (szPlaylistCount)
1027710301 {
1027810302 // First wait for Tune to complete to start this functionality
1027910303 {
1028010304 std::unique_lock<std::mutex> lock (mMutexPlaystart );
10305+ AAMPLOG_WARN (" PreCachePlaylistDownloadTask: Waiting for playstart notification" );
1028110306 waitforplaystart.wait (lock);
10307+ AAMPLOG_WARN (" PreCachePlaylistDownloadTask: Received playstart notification, proceeding" );
1028210308 }
1028310309 // May be Stop is called to release all resources .
1028410310 // Before download , check the state
@@ -10312,7 +10338,25 @@ void PrivateInstanceAAMP::PreCachePlaylistDownloadTask()
1031210338 bool ret = false ;
1031310339 // Using StreamLock to avoid StreamAbstractionAAMP deletion when external player commands or stop call received
1031410340 AcquireStreamLock ();
10341+ auto getFileStartTime = NOW_STEADY_TS_MS;
10342+ AAMPLOG_WARN (" HariPriya PreCachePlaylistDownloadTask: About to call GetFile (network I/O), state=%d" , GetState ());
10343+
10344+ // DEBUG: Simulate slow network to reproduce GC deadlock issue
10345+ // Set AAMP_SIMULATE_SLOW_PRECACHE_MS env var to inject delay (e.g., export AAMP_SIMULATE_SLOW_PRECACHE_MS=5000)
10346+ const char * delayEnv = getenv (" AAMP_SIMULATE_SLOW_PRECACHE_MS" );
10347+ if (delayEnv)
10348+ {
10349+ int delayMs = atoi (delayEnv);
10350+ if (delayMs > 0 )
10351+ {
10352+ AAMPLOG_WARN (" HariPriya PreCachePlaylistDownloadTask: DEBUG - Simulating slow network with %d ms delay" , delayMs);
10353+ std::this_thread::sleep_for (std::chrono::milliseconds (delayMs));
10354+ }
10355+ }
10356+
1031510357 ret = GetFile (newelem.url , newelem.type , &playlistStore, playlistEffectiveUrl, &http_code, &downloadTime, NULL , eCURLINSTANCE_PLAYLISTPRECACHE, true );
10358+ auto getFileDuration = NOW_STEADY_TS_MS - getFileStartTime;
10359+ AAMPLOG_WARN (" HariPriya PreCachePlaylistDownloadTask: GetFile returned after %lld ms, ret=%d, state=%d" , getFileDuration, ret, GetState ());
1031610360 ReleaseStreamLock ();
1031710361 if (ret != false )
1031810362 {
@@ -10337,11 +10381,12 @@ void PrivateInstanceAAMP::PreCachePlaylistDownloadTask()
1033710381 }
1033810382 }
1033910383 }while (idx < mPreCacheDnldList .size () && state != eSTATE_STOPPING && state != eSTATE_IDLE && state != eSTATE_ERROR);
10384+ AAMPLOG_WARN (" HariPriya PreCachePlaylistDownloadTask: Exiting loop, state=%d, idx=%d, size=%zu" , state, idx, mPreCacheDnldList .size ());
1034010385 mPreCacheDnldList .clear ();
1034110386 CurlTerm (eCURLINSTANCE_PLAYLISTPRECACHE);
1034210387 }
1034310388 }
10344- AAMPLOG_WARN (" End of PreCachePlaylistDownloadTask " );
10389+ AAMPLOG_WARN (" PreCachePlaylistDownloadTask: Thread exiting, state=%d " , GetState () );
1034510390}
1034610391
1034710392/* *
@@ -14448,5 +14493,3 @@ void PrivateInstanceAAMP::SetStreamCaps(AampMediaType type, MediaCodecInfo&& cod
1444814493 if (sink)
1444914494 {
1445014495 sink->SetStreamCaps (type, std::move (codecInfo));
14451- }
14452- }
0 commit comments