void MythSystemSignalManager::run(void) { RunProlog(); LOG(VB_GENERAL, LOG_INFO, "Starting process signal handler"); while( run_system ) { struct timespec ts; ts.tv_sec = 0; ts.tv_nsec = 50 * 1000 * 1000; // 50ms nanosleep(&ts, NULL); // sleep 50ms while( run_system ) { // handle cleanup and signalling for closed processes listLock.lock(); if( msList.isEmpty() ) { listLock.unlock(); break; } MythSystemUnix *ms = msList.takeFirst(); listLock.unlock(); // This can happen if it has been deleted already if (!ms) continue; ms->m_parent->HandlePostRun(); if (ms->m_stdpipe[0] > 0) writeThread->remove(ms->m_stdpipe[0]); CLOSE(ms->m_stdpipe[0]); if (ms->m_stdpipe[1] > 0) readThread->remove(ms->m_stdpipe[1]); CLOSE(ms->m_stdpipe[1]); if (ms->m_stdpipe[2] > 0) readThread->remove(ms->m_stdpipe[2]); CLOSE(ms->m_stdpipe[2]); if( ms->GetStatus() == GENERIC_EXIT_OK ) emit ms->finished(); else emit ms->error(ms->GetStatus()); ms->disconnect(); bool cleanup = ms->m_parent->doAutoCleanup(); ms->Unlock(); if( cleanup ) ms->deleteLater(); } } RunEpilog(); }
void MythSystemManager::run(void) { RunProlog(); LOG(VB_GENERAL, LOG_INFO, "Starting process manager"); // run_system is set to NULL during shutdown, and we need this thread to // exit during shutdown. while( run_system ) { usleep(100000); // sleep 100ms // check for any running processes m_mapLock.lock(); if( m_pMap.isEmpty() ) { m_mapLock.unlock(); continue; } m_mapLock.unlock(); MythSystemUnix *ms; pid_t pid; int status; // check for any newly exited processes listLock.lock(); while( (pid = waitpid(-1, &status, WNOHANG)) > 0 ) { m_mapLock.lock(); // unmanaged process has exited if( !m_pMap.contains(pid) ) { LOG(VB_SYSTEM, LOG_INFO, QString("Unmanaged child (PID: %1) has exited!") .arg(pid)); m_mapLock.unlock(); continue; } // pop exited process off managed list, add to cleanup list ms = m_pMap.take(pid); m_mapLock.unlock(); msList.append(ms); // handle normal exit if( WIFEXITED(status) ) { ms->SetStatus(WEXITSTATUS(status)); LOG(VB_SYSTEM, LOG_INFO, QString("Managed child (PID: %1) has exited! " "command=%2, status=%3, result=%4") .arg(pid) .arg(ms->GetLogCmd()) .arg(status) .arg(ms->GetStatus())); } // handle forced exit else if( WIFSIGNALED(status) && ms->GetStatus() != GENERIC_EXIT_TIMEOUT ) { // Don't override a timed out process which gets killed, but // otherwise set the return status appropriately int sig = WTERMSIG(status); ms->SetStatus( GENERIC_EXIT_KILLED ); LOG(VB_SYSTEM, LOG_INFO, QString("Managed child (PID: %1) has signalled! " "command=%2, status=%3, result=%4, signal=%5") .arg(pid) .arg(ms->GetLogCmd()) .arg(status) .arg(ms->GetStatus()) .arg(sig)); } // handle abnormal exit (crash) else { ms->SetStatus( GENERIC_EXIT_NOT_OK ); LOG(VB_SYSTEM, LOG_ERR, QString("Managed child (PID: %1) has terminated! " "command=%2, status=%3, result=%4") .arg(pid) .arg(ms->GetLogCmd()) .arg(status) .arg(ms->GetStatus())); } } // loop through running processes for any that require action MSMap_t::iterator i, next; time_t now = time(NULL); m_mapLock.lock(); m_jumpLock.lock(); for( i = m_pMap.begin(); i != m_pMap.end(); i = next ) { next = i + 1; pid = i.key(); ms = i.value(); if (!ms) continue; // 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 ) { LOG(VB_SYSTEM, LOG_INFO, QString("Managed child (PID: %1) timed out" ", issuing KILL signal").arg(pid)); // Prevent constant attempts to kill an obstinate child ms->m_timeout = 0; ms->Signal(SIGKILL); } // issuing TERM signal else { LOG(VB_SYSTEM, LOG_INFO, QString("Managed child (PID: %1) timed out" ", issuing TERM signal").arg(pid)); 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 if (readThread) readThread->wake(); if (writeThread) writeThread->wake(); RunEpilog(); }