pid.py
Go to the documentation of this file.
00001 #
00002 # License: BSD
00003 #   https://raw.github.com/robotics-in-concert/rocon_tools/license/LICENSE
00004 #
00005 
00006 ##############################################################################
00007 # Imports
00008 ##############################################################################
00009 
00010 # system
00011 import os
00012 import time
00013 import errno
00014 
00015 # local
00016 from rocon_python_utils.exceptions import TimeoutExpiredError
00017 
00018 ##############################################################################
00019 # PID
00020 ##############################################################################
00021 
00022 
00023 def pid_exists(pid):
00024     """Check whether pid exists in the current process table."""
00025     if pid < 0:
00026         return False
00027     try:
00028         os.kill(pid, 0)
00029     except OSError, e:
00030         return e.errno == errno.EPERM
00031     else:
00032         return True
00033 
00034 
00035 def wait_pid(pid, timeout=None):
00036     """Wait for process with pid 'pid' to terminate and return its
00037     exit status code as an integer.
00038 
00039     If pid is not a children of os.getpid() (current process) just
00040     waits until the process disappears and return None.
00041 
00042     If pid does not exist at all return None immediately.
00043 
00044     Raise TimeoutExpiredError on timeout expired (if specified).
00045     """
00046     def check_timeout(delay):
00047         if timeout is not None:
00048             if time.time() >= stop_at:
00049                 raise TimeoutExpiredError
00050         time.sleep(delay)
00051         return min(delay * 2, 0.04)
00052 
00053     if timeout is not None:
00054         waitcall = lambda: os.waitpid(pid, os.WNOHANG)
00055         stop_at = time.time() + timeout
00056     else:
00057         waitcall = lambda: os.waitpid(pid, 0)
00058 
00059     delay = 0.0001
00060     while 1:
00061         try:
00062             retpid, status = waitcall()
00063         except OSError, err:
00064             if err.errno == errno.EINTR:
00065                 delay = check_timeout(delay)
00066                 continue
00067             elif err.errno == errno.ECHILD:
00068                 # This has two meanings:
00069                 # - pid is not a child of os.getpid() in which case
00070                 #   we keep polling until it's gone
00071                 # - pid never existed in the first place
00072                 # In both cases we'll eventually return None as we
00073                 # can't determine its exit status code.
00074                 while 1:
00075                     if pid_exists(pid):
00076                         delay = check_timeout(delay)
00077                     else:
00078                         return
00079             else:
00080                 raise
00081         else:
00082             if retpid == 0:
00083                 # WNOHANG was used, pid is still running
00084                 delay = check_timeout(delay)
00085                 continue
00086             # process exited due to a signal; return the integer of
00087             # that signal
00088             if os.WIFSIGNALED(status):
00089                 return os.WTERMSIG(status)
00090             # process exited using exit(2) system call; return the
00091             # integer exit(2) system call has been called with
00092             elif os.WIFEXITED(status):
00093                 return os.WEXITSTATUS(status)
00094             else:
00095                 # should never happen
00096                 raise RuntimeError("unknown process exit status")


rocon_python_utils
Author(s): Daniel Stonier
autogenerated on Fri May 2 2014 10:35:39