// NOTE: This is only to be run while m_mapLock is locked!!! void MythSystemLegacyManager::ChildListRebuild() { int oldCount; oldCount = m_childCount; m_childCount = m_pMap.size(); MSMap_t::iterator i; int j; HANDLE child; if ( oldCount != m_childCount ) { HANDLE *new_children; new_children = (HANDLE *)realloc(m_children, m_childCount * sizeof(HANDLE)); if (!new_children && m_childCount) { LOG(VB_SYSTEM, LOG_CRIT, "No memory to allocate new children"); free(m_children); m_children = nullptr; return; } m_children = new_children; } for (i = m_pMap.begin(), j = 0; i != m_pMap.end(); ++i) { child = i.key(); m_children[j++] = child; } }
// NOTE: This is only to be run while m_mapLock is locked!!! void MythSystemManager::ChildListRebuild() { int oldCount; oldCount = m_childCount; m_childCount = m_pMap.size(); MSMap_t::iterator i; int j; HANDLE child; if ( oldCount != m_childCount ) m_children = (HANDLE *)realloc(m_children, m_childCount * sizeof(HANDLE)); for( i = m_pMap.begin(), j = 0; i != m_pMap.end(); i++, j++ ) { child = i.key(); m_children[j] = child; } }
void MythSystemManager::run(void) { VERBOSE(VB_GENERAL|VB_SYSTEM, "Starting process manager"); // gCoreContext is set to NULL during shutdown, and we need this thread to // exit during shutdown. while( gCoreContext ) { // check for any running processes m_mapLock.lock(); if( m_childCount == 0 ) { m_mapLock.unlock(); usleep( 100000 ); continue; } DWORD result = WaitForMultipleObjects( m_childCount, m_children, FALSE, 100 ); if ( result == WAIT_TIMEOUT || result == WAIT_FAILED ) { m_mapLock.unlock(); continue; } int index = result - WAIT_OBJECT_0; if ( index < 0 || index > m_childCount - 1 ) { m_mapLock.unlock(); continue; } HANDLE child = m_children[index]; // pop exited process off managed list, add to cleanup list MythSystemWindows *ms = m_pMap.take(child); ChildListRebuild(); m_mapLock.unlock(); listLock.lock(); msList.append(ms); DWORD status; GetExitCodeProcess( child, &status ); ms->SetStatus(status); VERBOSE(VB_SYSTEM, QString("Managed child (Handle: %1) has exited! " "command=%2, status=%3, result=%4") .arg((long long)child) .arg(ms->GetLogCmd()) .arg(status) .arg(ms->GetStatus())); // loop through running processes for any that require action MSMap_t::iterator i; time_t now = time(NULL); m_mapLock.lock(); m_jumpLock.lock(); for( i = m_pMap.begin(); i != m_pMap.end(); i++ ) { child = i.key(); ms = i.value(); // handle processes beyond marked timeout if( ms->m_timeout > 0 && ms->m_timeout < now ) { // issuing KILL signal after TERM failed in a timely manner if( ms->GetStatus() == GENERIC_EXIT_TIMEOUT ) { VERBOSE(VB_SYSTEM, QString("Managed child (Handle: %1) timed out, " "issuing KILL signal").arg((long long)child)); // Prevent constant attempts to kill an obstinate child ms->m_timeout = 0; ms->Signal(SIGKILL); } // issuing TERM signal else { VERBOSE(VB_SYSTEM, QString("Managed child (Handle: %1) timed out" ", issuing TERM signal").arg((long long)child)); ms->SetStatus( GENERIC_EXIT_TIMEOUT ); ms->m_timeout = now + 1; ms->Term(); } } if ( m_jumpAbort && ms->GetSetting("AbortOnJump") ) ms->Term(); } m_jumpAbort = false; m_jumpLock.unlock(); m_mapLock.unlock(); // hold off unlocking until all the way down here to // give the buffer handling a chance to run before // being closed down by signal thread listLock.unlock(); } // kick to allow them to close themselves cleanly readThread->wake(); writeThread->wake(); }