@@ -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
715731public:
0 commit comments