diff --git a/ptyprocess/ptyprocess.py b/ptyprocess/ptyprocess.py index cb3efae..d2e02d6 100644 --- a/ptyprocess/ptyprocess.py +++ b/ptyprocess/ptyprocess.py @@ -699,10 +699,76 @@ def isalive(self): except OSError as e: # No child processes if e.errno == errno.ECHILD: - raise PtyProcessError('isalive() encountered condition ' + - 'where "terminated" is 0, but there was no child ' + - 'process. Did someone else call waitpid() ' + - 'on our process?') + try: + """ + The following code is adopted from psutil with slight modification + + https://github.com/giampaolo/psutil/blob/master/LICENSE + psutil is distributed under BSD license reproduced below. + + Copyright (c) 2009, Jay Loden, Dave Daeschler, Giampaolo Rodola' + All rights reserved. + + Redistribution and use in source and binary forms, with or without modification, + are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + * Neither the name of the psutil authors nor the names of its contributors + may be used to endorse or promote products derived from this software without + specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR + ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + """ + os.kill(self.pid, 0) + if sys.platform.startswith("linux"): + with open("/proc/%s/stat" % (self.pid), "rb") as f: + data = f.read() + rpar = data.rfind(b')') + name = data[data.find(b'(') + 1:rpar] + fields_after_name = data[rpar + 2:].split() + if fields_after_name[0] == "Z": + raise PtyProcessError('isalive() encountered condition ' + + 'where the child process becomes a zombie process.' + + ' Does other process kill the ptyprocess?') + elif sys.platform.startswith("darwin"): + pass + elif sys.platform.startswith("freebsd"): + pass + else: + pass + """ + The adoption of psutil code ends here + """ + except OSError as err: + if err.errno == errno.ESRCH: + # No such process + raise PtyProcessError('isalive() encountered condition ' + + 'where "terminated" is 0, but there was no child ' + + 'process. Did someone else call waitpid() ' + + 'on our process?') + elif err.errno == errno.EPERM: + # Process deny access + raise PtyProcessError('isalive() encountered condition ' + + 'where the child process deny access') + else: + # Other possible error + raise err + else: + # Process exists not as child + pid, status = 0, 0 else: raise @@ -717,10 +783,73 @@ def isalive(self): except OSError as e: # pragma: no cover # This should never happen... if e.errno == errno.ECHILD: - raise PtyProcessError('isalive() encountered condition ' + - 'that should never happen. There was no child ' + - 'process. Did someone else call waitpid() ' + - 'on our process?') + try: + """ + The following code is adopted from psutil with slight modification + + https://github.com/giampaolo/psutil/blob/master/LICENSE + psutil is distributed under BSD license reproduced below. + + Copyright (c) 2009, Jay Loden, Dave Daeschler, Giampaolo Rodola' + All rights reserved. + + Redistribution and use in source and binary forms, with or without modification, + are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + * Neither the name of the psutil authors nor the names of its contributors + may be used to endorse or promote products derived from this software without + specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR + ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + """ + os.kill(self.pid, 0) + if sys.platform.startswith("linux"): + with open("/proc/%s/stat" % (self.pid), "rb") as f: + data = f.read() + rpar = data.rfind(b')') + name = data[data.find(b'(') + 1:rpar] + fields_after_name = data[rpar + 2:].split() + if fields_after_name[0] == "Z": + raise PtyProcessError('isalive() encountered condition ' + + 'where the child process becomes a zombie process.' + + ' Does other process kill the ptyprocess?') + elif sys.platform.startswith("darwin"): + pass + elif sys.platform.startswith("freebsd"): + pass + else: + pass + except OSError as err: + if err.errno == errno.ESRCH: + # No such process + raise PtyProcessError('isalive() encountered condition ' + + 'where "terminated" is 0, but there was no child ' + + 'process. Did someone else call waitpid() ' + + 'on our process?') + elif err.errno == errno.EPERM: + # Process deny access + raise PtyProcessError('isalive() encountered condition ' + + 'where the child process deny access') + else: + # Other possible error + raise err + else: + # Process exists not as child + pid, status = 0, 0 else: raise