Source code for rocon_python_utils.system.pid

#
# License: BSD
#   https://raw.github.com/robotics-in-concert/rocon_tools/license/LICENSE
#
##############################################################################
# Description
##############################################################################

"""
.. module:: system.pid
   :platform: Unix
   :synopsis: Helpers for working with system pids.

This module includes a few helpers to enable working with system pids in python.

----

"""

##############################################################################
# Imports
##############################################################################

# system
import os
import time
import errno

# local
from rocon_python_utils.exceptions import TimeoutExpiredError

##############################################################################
# PID
##############################################################################


[docs]def pid_exists(pid): """ Check whether pid exists in the current process table. :param int pid: :returns: true or false depending on its existence. :rtype: bool """ if pid < 0: return False try: os.kill(pid, 0) except OSError, e: return e.errno == errno.EPERM else: return True
[docs]def wait_pid(pid, timeout=None): """Wait for process with pid 'pid' to terminate and return its exit status code as an integer. If pid is not a children of os.getpid() (current process) just waits until the process disappears and return None. If pid does not exist at all return None immediately. :param int pid: :param float timeout: timeout in seconds :raises: :exc:`.TimeoutExpiredError` on timeout expired (if specified). """ def check_timeout(delay): if timeout is not None: if time.time() >= stop_at: raise TimeoutExpiredError time.sleep(delay) return min(delay * 2, 0.04) if timeout is not None: waitcall = lambda: os.waitpid(pid, os.WNOHANG) stop_at = time.time() + timeout else: waitcall = lambda: os.waitpid(pid, 0) delay = 0.0001 while 1: try: retpid, status = waitcall() except OSError, err: if err.errno == errno.EINTR: delay = check_timeout(delay) continue elif err.errno == errno.ECHILD: # This has two meanings: # - pid is not a child of os.getpid() in which case # we keep polling until it's gone # - pid never existed in the first place # In both cases we'll eventually return None as we # can't determine its exit status code. while 1: if pid_exists(pid): delay = check_timeout(delay) else: return else: raise else: if retpid == 0: # WNOHANG was used, pid is still running delay = check_timeout(delay) continue # process exited due to a signal; return the integer of # that signal if os.WIFSIGNALED(status): return os.WTERMSIG(status) # process exited using exit(2) system call; return the # integer exit(2) system call has been called with elif os.WIFEXITED(status): return os.WEXITSTATUS(status) else: # should never happen raise RuntimeError("unknown process exit status")