A small feature in the roslaunch is similar to the service restart feature in the Android init process, and if the process is created with the Respawn property, it needs to be restarted after the process dead, which is a process monitoring role, and the relevant source code is located in pmon.py.
The following analysis of its main functions,
#ros_comm \tools\roslaunch\src\roslaunch\pmon.py
class Process (object): "" "
Basic Process Representation for L{processmonitor}. Must is subclassed to
provide actual start ()/stop () implementations.
Constructor *must* is called from the Python Main thread in order for
signal handlers to register properly. ""
def __init__ (self, package, name, args, env,
Respawn=false, respawn_delay=0.0, Required=false):
properties of the #① process, Respawn is required to restart
self.respawn = respawn
self.respawn_delay = respawn_delay
self.required = Required
The process () class is the base class that processmonitor () monitoring processes need to inherit, and you can set dead if the properties need to be restarted.
You can start a processmonitor process (thread) by calling the Start_process_monitor () function.
#① can have multiple pmon _pmons = [] _pmon_counter = 0 def start_process_monitor (): Global _pmon_counter If _shutting_down: #logger. Error ("Start_process_monitor:cannot start new Processmonitor (shutdown initiated)" ) return None _pmon_counter + = 1 name = "processmonitor-%s"%_pmon_counter logger.info ("Start_process_m Onitor:creating processmonitor ") #② Create Processmonitor Object process_monitor = processmonitor (name) Try: # p Revent race condition with Pmon_shutdown () being triggered # as we are starting a processmonitor (i.e. user hits C
TRL-C # during startup) _shutdown_lock.acquire () #③ add Processmonitor object to _pmons and call its start () function _pmons.append (Process_monitor) Process_monitor.start () logger.info ("Start_process_monitor:processmoni Tor started ") Finally: _shutdown_lock.release () return process_monitor
Class Processmonitor (Thread): Def __init__ (self, name= "Processmonitor"): thread.__init__ (self, name=name) #① monitored process self.procs = [] # #885: Ensure core procs Self.core_procs = [] def register (SE
LF, p): "" "Register process with L{processmonitor} @param p:process @type p:l{process} @raise rlexception:if process with same name is already registered "" Logger.info ("Processmonit
or.register[%s] "%p.name) e = None with Self.plock:if self.has_process (p.name):
E = Rlexception ("Cannot add process with duplicate name '%s '"%p.name) elif Self.is_shutdown: E = Rlexception ("Cannot add process [%s] after process Monitor have been shut down"%p.name) Else: #② register process with Pro
Cessmonitor, which is the thread function added to the procs self.procs.append (p) #③processmonitor thread, Def run (self): "" " Thread routine of THe process Monitor. Note:you must still call Mainthread_spin or mainthread_spin_once () from the main thread in order to pick
Up main thread work from the process Monitor. "" "Try: #don ' t let exceptions bomb thread, interferes with exit try:self . _run () finally:self._post_run () #④processmonitor thread function Body def _run (self): PLO
CK = Self.plock Dead = [] respawn = [] #while循环, pmon off switch while not self.is_shutdown:
#监控中的进程 for P in Procs:try:if not p.is_alive ():
Logger.debug ("process[%s" has died, respawn=%s, required=%s, exit_code=%s ", P.name,
"True (%f)"% p.respawn_delay if p.respawn else P.respawn, p.required, P.exit_code) exit_code_str= P.get_exit_description () #⑤ This process is necessary, the required process dead off, Pmon itself also closes #将self. Is_shu Tdown set to True if p.required:printerrlog (' = ' *80+ ' required process [%s] ] has died!\n%s\ninitiating shutdown!\n "% (p.name, exit_code_str) + ' = ' *80) Self.is_shutdown = Tr
UE _respawn=[] for R in Respawn:try:if Self.is_shutdown: Break if R.should_respawn () <= 0.0:printlog ("[%s] Restarting process "% r.name) # stop process, don ' t accumulate errors #⑥
Restarting the process that requires a restart, plays a role in process monitoring. R.stop ([]) R.start () Else: # Not ready yet, keep it ar Ound _respawn.append (R) except:traceback. Print_exc () logger.error ("Restart failed%s", Traceback.format_exc ()) respawn = _respawn Time.sleep (0.1) #yield thread #moved this to finally block of _post_run #self. _post_run () #kill
All processes
Discovered by the above code, Self.is_shutdown is the pmon shutdown switch, when Is_shutdown is true, then the while loop exits, will continue to execute _post_run (), will kill all the monitoring process, but in order, Finally kill the core process (Core_procs).
def _post_run (self): Logger.info ("Processmonitor._post_run%s"%self) # This is already true entering, b
UT go ahead and make sure Self.is_shutdown = True # Killall processes on run exit q = Queue () Q.join () with Self.plock: # make copy of Core_procs for threadsafe usage Core_procs
= self.core_procs[:] Logger.info ("Processmonitor._post_run%s:remaining procs is%s"% (self, self.procs))
# enqueue All Non-core procs in reverse order for parallel kill # #526/885:ignore core procs
[Q.put (P) for p in reversed (Self.procs) if not p in Core_procs] # use workers killers = [] For I in range: t = _processkiller (q, i) killers.append (t) T.start () #
Wait for workers-to-finish Q.join () shutdown_errors = [] # accumulate all the shutdown errors
For T in killers: Shutdown_errors.extend (t.errors) del killers[:] # #526/885:kill Core Procs Last # we Don ' t want to parallelize this as the master have to is last for P in reversed (Core_procs): _kill_proc ESS (P, shutdown_errors) # delete everything except dead_list logger.info ("Processmonitor exit:cleaning u
P Data structures and Signals ") with Self.plock:del core_procs[:] del self.procs[:]
Del self.core_procs[:] reacquire_signals = self.reacquire_signals if reacquire_signals:
Reacquire_signals.clear () logger.info ("Processmonitor Exit:pmon has shutdown") Self.done = True If Shutdown_errors:printerrlog ("Shutdown errors:\n" + ' \ n '. Join (["*%s"%e for E in shutdown_errors]))
through pmon.py code analysis, pmon.py must be in the main thread of a process to import, call Start_process_monitor () function will produce a pmon, and then the need to monitor the process (thread) Registering to Pmon, the main thread will have multiple Pmon saved in global _pmons = [].