threads_detached.cpp 3.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152
  1. //
  2. // Copyright (c) 2017-2026, Manticore Software LTD (https://manticoresearch.com)
  3. // Copyright (c) 2001-2016, Andrew Aksyonoff
  4. // Copyright (c) 2008-2016, Sphinx Technologies Inc
  5. // All rights reserved
  6. //
  7. // This program is free software; you can redistribute it and/or modify
  8. // it under the terms of the GNU General Public License. You should have
  9. // received a copy of the GPL license along with this program; if you
  10. // did not, you can find it at http://www.gnu.org/
  11. //
  12. #include "threadutils.h"
  13. #include <csignal>
  14. using namespace Threads;
  15. namespace {
  16. RwLock_t& g_dDetachedGuard()
  17. {
  18. static RwLock_t dDetachedGuard;
  19. return dDetachedGuard;
  20. }
  21. CSphVector<LowThreadDesc_t *>& g_dDetachedThreads()
  22. {
  23. static CSphVector<LowThreadDesc_t *> dDetachedThreads GUARDED_BY ( g_dDetachedGuard () );
  24. return dDetachedThreads;
  25. }
  26. }
  27. // walk over list of running detached threads and apply fnHandler to each of them
  28. // Each call made under r-lock to keep thread list intact
  29. void Iterate ( ThreadFN& fnHandler )
  30. {
  31. ScRL_t _ ( g_dDetachedGuard () );
  32. for ( auto * pThread : g_dDetachedThreads () )
  33. fnHandler ( pThread );
  34. }
  35. // register shutdown action that will walk over list of running detached threads and send SIGTERM to each of them.
  36. // then wait until they're finished.
  37. // Also register iterations right now;
  38. void Detached::MakeAloneIteratorAvailable ()
  39. {
  40. #ifndef NDEBUG
  41. static bool bAlreadyInvoked = false;
  42. assert ( !bAlreadyInvoked );
  43. bAlreadyInvoked = true;
  44. #endif
  45. Threads::RegisterIterator ( Iterate );
  46. // all about windows that we use pthread_kill right now.
  47. // if analogue exists there, the limitation can be removed.
  48. //#if !_WIN32
  49. // searchd::AddShutdownCb ( []
  50. // {
  51. // Detached::ShutdownAllAlones();
  52. // });
  53. //#endif
  54. }
  55. static int64_t g_tmShutdownAllAlonesDelta = 3; // max allowed wait in seconds
  56. void Detached::ShutdownAllAlones()
  57. {
  58. #if !_WIN32
  59. int iThreads;
  60. {
  61. ScRL_t _ ( g_dDetachedGuard() );
  62. iThreads = g_dDetachedThreads().GetLength();
  63. }
  64. int iTurn = 1;
  65. int64_t tmStart = sphMicroTimer();
  66. int64_t tmEnd = tmStart + g_tmShutdownAllAlonesDelta * 1000000;
  67. while ( iThreads > 0 )
  68. {
  69. {
  70. ScRL_t _ ( g_dDetachedGuard() );
  71. sphWarning ( "ShutdownAllAlones will kill %d threads", iThreads );
  72. for ( auto* pThread : g_dDetachedThreads() )
  73. {
  74. if ( pThread )
  75. {
  76. sphInfo ( "Kill thread '%s' with id %d, try %d",
  77. pThread->m_sThreadName.cstr(),
  78. pThread->m_iThreadID,
  79. iTurn );
  80. pthread_kill ( pThread->m_tThread, SIGTERM );
  81. }
  82. }
  83. }
  84. auto iStart = 0;
  85. while ( true )
  86. {
  87. {
  88. ScRL_t _ ( g_dDetachedGuard() );
  89. iThreads = g_dDetachedThreads().GetLength();
  90. }
  91. if ( iThreads <= 0 )
  92. break;
  93. sphSleepMsec ( 50 );
  94. iStart += 50;
  95. if ( iStart >= 10000 ) // wait 10 seconds between tries
  96. {
  97. sphWarning ( "ShutdownAllAlones catch still has %d alone threads", iThreads );
  98. break;
  99. }
  100. }
  101. ++iTurn;
  102. int64_t tmCur = sphMicroTimer();
  103. if ( tmCur>tmEnd )
  104. {
  105. sphWarning ( "ShutdownAllAlones exits by timeout (%.3f seconds) but still has %d alone threads", ( (tmCur-tmStart)/1000000.0f ), iThreads );
  106. break;
  107. }
  108. }
  109. #endif
  110. }
  111. void Detached::AddThread ( LowThreadDesc_t* pThread )
  112. {
  113. ScWL_t _ ( g_dDetachedGuard() );
  114. sphLogDebug ( "Detached::AddThread called for '%s', tid %d",
  115. pThread->m_sThreadName.cstr(), pThread->m_iThreadID );
  116. g_dDetachedThreads ().Add ( pThread );
  117. }
  118. void Detached::RemoveThread ( LowThreadDesc_t* pVictim )
  119. {
  120. sphLogDebug ( "Detached::RemoveThread called for %d", pVictim->m_iThreadID );
  121. ScWL_t _ ( g_dDetachedGuard() );
  122. ARRAY_FOREACH ( i, g_dDetachedThreads() )
  123. {
  124. auto pThread = g_dDetachedThreads ()[i];
  125. if ( Threads::Same ( pThread, pVictim ) )
  126. {
  127. sphLogDebug ( "Terminated thread %d, '%s'", pThread->m_iThreadID, pThread->m_sThreadName.cstr () );
  128. g_dDetachedThreads().RemoveFast ( i );
  129. return;
  130. }
  131. }
  132. }