Skip to content

Commit 20cf49e

Browse files
committed
[LAUNCHER] Track the processes that are spawned of by our process so we can kill our process if the time is due.
1 parent 8288696 commit 20cf49e

2 files changed

Lines changed: 93 additions & 93 deletions

File tree

Launcher.cpp

Lines changed: 18 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -84,43 +84,27 @@ void Launcher::Update(const ProcessObserver::Info& info)
8484

8585
// This can potentially be called on a socket thread, so the deactivation (wich in turn kills this object) must be done
8686
// on a seperate thread. Also make sure this call-stack can be unwound before we are totally destructed.
87-
if (_activity->HasPid(info.Id()) == true) {
88-
89-
switch (info.Event()) {
90-
case ProcessObserver::Info::EVENT_FORK:
91-
TRACE(Trace::Information, (_T("FORK: parent tid=%d pid=%d -> child tid=%d pid=%d\n"), info.Id(), info.Group(), info.ChildId(), info.ChildGroup()));
92-
_activity->AddPid(info.ChildId());
93-
break;
94-
case ProcessObserver::Info::EVENT_EXEC:
95-
TRACE(Trace::Information, (_T("EXEC: tid=%d pid=%d\n"), info.Id(), info.Group()));
96-
break;
97-
case ProcessObserver::Info::EVENT_EXIT:
98-
{
99-
if (_activity->Pid() == info.Id()) {
100-
_memory->Observe(0);
101-
uint32_t result = _activity->ExitCode();
102-
103-
if (result != Core::ERROR_NONE) {
87+
if (_activity->IsActive() == true) {
88+
89+
_activity->Update(info);
90+
91+
if (_activity->IsActive() == false) {
92+
uint32_t result = _activity->ExitCode();
93+
94+
if (result != Core::ERROR_NONE) {
95+
if (_deactivationInProgress == false) {
96+
_deactivationInProgress = true;
10497
SYSLOG(Trace::Fatal, (_T("FORCED Shutdown: %s by error: %d."), _service->Callsign().c_str(), result));
105-
if (_activity->ShutdownInProgress() == false) {
106-
PluginHost::WorkerPool::Instance().Submit(PluginHost::IShell::Job::Create(_service, PluginHost::IShell::DEACTIVATED, PluginHost::IShell::FAILURE));
107-
}
108-
}
109-
else if (_activity->Continuous() == false) {
110-
TRACE(Trace::Information, (_T("Launcher [%s] has run succesfully, deactivation requested."), _service->Callsign().c_str()));
111-
PluginHost::WorkerPool::Instance().Submit(PluginHost::IShell::Job::Create(_service, PluginHost::IShell::DEACTIVATED, PluginHost::IShell::AUTOMATIC));
98+
PluginHost::WorkerPool::Instance().Submit(PluginHost::IShell::Job::Create(_service, PluginHost::IShell::DEACTIVATED, PluginHost::IShell::FAILURE));
11299
}
113-
else {
114-
TRACE(Trace::Information, (_T("Launcher [%s] has run succesfully, scheduled for the next run."), _service->Callsign().c_str()));
115-
}
116-
} else {
117-
_activity->RemovePid(info.Id());
118100
}
119-
break;
120-
}
121-
default:
122-
printf("unhandled proc event\n");
123-
break;
101+
else if (_activity->Continuous() == false) {
102+
TRACE(Trace::Information, (_T("Launcher [%s] has run succesfully, deactivation requested."), _service->Callsign().c_str()));
103+
PluginHost::WorkerPool::Instance().Submit(PluginHost::IShell::Job::Create(_service, PluginHost::IShell::DEACTIVATED, PluginHost::IShell::AUTOMATIC));
104+
}
105+
else {
106+
TRACE(Trace::Information, (_T("Launcher [%s] has run succesfully, scheduled for the next run."), _service->Callsign().c_str()));
107+
}
124108
}
125109
}
126110
}

Launcher.h

Lines changed: 75 additions & 59 deletions
Original file line numberDiff line numberDiff line change
@@ -557,7 +557,7 @@ class Launcher : public PluginHost::IPlugin {
557557
, _interval(interval)
558558
, _closeTime(config->CloseTime.Value())
559559
, _shutdownPhase(0)
560-
, _waitEvent(true, false)
560+
, _processListEmpty(1, 1)
561561
{
562562
auto iter = config->Parameters.Elements();
563563

@@ -584,57 +584,58 @@ class Launcher : public PluginHost::IPlugin {
584584
uint32_t ExitCode() {
585585
return (_process.IsActive() == false ? _process.ExitCode() : Core::ERROR_NONE);
586586
}
587+
bool IsActive() const {
588+
return (_processList.size() > 0);
589+
}
587590
bool Continuous() const {
588591
return (_interval.IsValid() == true);
589592
}
590593
uint32_t Pid() {
591-
return _pid;
592-
}
593-
bool ShutdownInProgress() {
594-
bool status = false;
595-
_adminLock.Lock();
596-
status = _shutdownPhase;
597-
_adminLock.Unlock();
598-
return status;
599-
}
600-
void Kill(uint32_t pid) {
601-
::kill(pid, SIGKILL);
594+
return (_processList.front());
602595
}
603-
bool HasPid(uint32_t pid) {
604-
_adminLock.Lock();
605-
ProcessList::iterator position = std::find(_processList.begin(), _processList.end(), pid);
606-
_adminLock.Unlock();
607-
return (position != _processList.end());
608-
}
609-
void AddPid(uint32_t pid) {
610-
_adminLock.Lock();
611-
if (!_shutdownPhase) {
612-
ASSERT(std::find(_processList.begin(), _processList.end(), pid) == _processList.end());
613-
_processList.push_back(pid);
614-
}
615-
else {
616-
Kill(pid);
617-
}
618-
_adminLock.Unlock();
619-
}
620-
void RemovePid(uint32_t pid) {
621-
_adminLock.Lock();
622-
ProcessList::iterator position = std::find(_processList.begin(), _processList.end(), pid);
623-
if (position != _processList.end()) {
624-
_processList.erase(position);
596+
void Update (const ProcessObserver::Info& info) {
597+
switch (info.Event()) {
598+
case ProcessObserver::Info::EVENT_FORK:
599+
{
600+
_adminLock.Lock();
601+
602+
ProcessList::iterator position (std::find(_processList.begin(), _processList.end(), info.Id()));
603+
if (position != _processList.end()) {
604+
_processList.push_back(info.ChildId());
605+
606+
if (_shutdownPhase == 2) {
607+
::kill(pid, SIGKILL);
608+
}
609+
}
610+
611+
_adminLock.Unlock();
612+
break;
625613
}
626-
if (_processList.empty() == true) {
627-
_waitEvent.SetEvent();
614+
case ProcessObserver::Info::EVENT_EXIT:
615+
{
616+
_adminLock.Lock();
617+
618+
ProcessList::iterator position (std::find(_processList.begin(), _processList.end(), info.Id()));
619+
if (position != _processList.end()) {
620+
_position.erase(position);
621+
if ( (_position.Id() == _pid) && (_process.IsActive() == false) ) {
622+
_memory->Observe(0);
623+
}
624+
else {
625+
// TODO: Probably might need to add the read exit code here for any process that exits to prevent
626+
// Zombie processes here..
627+
}
628+
if (_position.size() == 0) {
629+
_processListEmpty.Unlock();
630+
}
631+
}
632+
633+
_adminLock.Unlock();
634+
break;
628635
}
629-
_adminLock.Unlock();
630-
}
631-
void StopChilds() {
632-
_adminLock.Lock();
633-
ASSERT(!_processList.empty())
634-
for (int i = 1; i < _processList.size(); i++) {
635-
Kill(_processList[i]);
636+
default:
637+
break;
636638
}
637-
_adminLock.Unlock();
638639
}
639640
void Schedule (const Core::Time& time) {
640641
if (time <= Core::Time::Now()) {
@@ -649,24 +650,37 @@ class Launcher : public PluginHost::IPlugin {
649650
_shutdownPhase = 1;
650651
_adminLock.Unlock();
651652

652-
(PluginHost::WorkerPool::Instance().Revoke(Core::ProxyType<Core::IDispatch>(*this)));
653-
_waitEvent.ResetEvent();
653+
PluginHost::WorkerPool::Instance().Revoke(Core::ProxyType<Core::IDispatch>(*this));
654654
if (_process.IsActive() == true) {
655655

656656
// First try a gentle touch....
657657
_process.Kill(false);
658658

659659
// Wait for a maximum configured wait time before we shoot the process!!
660-
if (_process.WaitProcessCompleted(_closeTime * 1000) != Core::ERROR_NONE) {
660+
_process.WaitProcessCompleted(_closeTime * 1000);
661+
662+
// If there was a proper shutdown, all assoicated processes should have left.
663+
// If not, we will start doing it the rude way!!
664+
if (_processList.size() != 0) {
665+
_adminLock.Lock();
666+
_shutdownPhase = 2;
667+
661668
TRACE_L1("Trying to force kill\n");
662-
_process.Kill(true);
663-
_process.WaitProcessCompleted(1000);
669+
for (int i = 0; i < _processList.size(); i++) {
670+
::kill(_processList[i], SIGKILL);
671+
}
672+
673+
_adminLock.Unlock();
664674
}
665-
StopChilds(); //Ensure all childs are exited before quiting
666-
if (_waitEvent.Lock(1000) != Core::ERROR_NONE) {
667-
TRACE_L1("Child list are not yet cleared\n");
675+
676+
if (_processListEmpty.Lock(1000) != Core::ERROR_NONE) {
677+
TRACE(Trace::Fatal, (_T("Could not kill all spawned processes for: %s."), _options.Command().c_str()));
668678
_processList.clear();
669679
}
680+
_processListEmpty.Unlock();
681+
_adminLock.Lock();
682+
_shutdownPhase = 0;
683+
_adminLock.Unlock();
670684
}
671685
}
672686

@@ -677,15 +691,18 @@ class Launcher : public PluginHost::IPlugin {
677691
Core::Time nextRun (Core::Time::Now());
678692

679693
// Check if the process is not active, no need to reschedule the same job again.
680-
if (_process.IsActive() == false) {
694+
if ( (_process.IsActive() == false) && (_shutdownCompleted.Lock(0) != Core::ERROR_NONE) ) {
695+
696+
ASSERT (_processList.size() == 0);
697+
698+
_processList.push_back(0);
681699

682-
_process.Launch(_options, &_pid);
683-
AddPid(_pid);
700+
_process.Launch(_options, &_processList.front());
684701

685-
TRACE(Trace::Information, (_T("Launched command: %s [%d]."), _options.Command().c_str(), _pid));
702+
TRACE(Trace::Information, (_T("Launched command: %s [%d]."), _options.Command().c_str(), Pid()));
686703
ASSERT (_memory != nullptr);
687704

688-
_memory->Observe(_pid);
705+
_memory->Observe(Pid());
689706
}
690707

691708
if (_interval.IsValid() == true) {
@@ -701,15 +718,14 @@ class Launcher : public PluginHost::IPlugin {
701718

702719
private:
703720
Core::CriticalSection _adminLock;
704-
uint32_t _pid;
705721
Core::Process::Options _options;
706722
Core::Process _process;
707723
Exchange::IMemory* _memory;
708724
Time _interval;
709725
uint8_t _closeTime;
710726
uint8_t _shutdownPhase;
711727
ProcessList _processList;
712-
Core::Event _waitEvent;
728+
Core::BinairySamaphore _shutdownCompleted;
713729
};
714730

715731
public:

0 commit comments

Comments
 (0)