From 4b6fdf38525382dc279c5b32023f931e6db98591 Mon Sep 17 00:00:00 2001 From: Amaury Forgeot d'Arc Date: Tue, 7 Sep 2010 21:31:17 +0000 Subject: [PATCH] #6394: Add os.getppid() support for Windows. --- Doc/library/os.rst | 8 +++++-- Doc/whatsnew/3.2.rst | 5 ++++ Lib/test/test_os.py | 12 ++++++++++ Misc/ACKS | 1 + Misc/NEWS | 4 ++++ Modules/posixmodule.c | 54 +++++++++++++++++++++++++++++++++++++++++-- 6 files changed, 80 insertions(+), 4 deletions(-) diff --git a/Doc/library/os.rst b/Doc/library/os.rst index 2e29e4a4672..9373bda655e 100644 --- a/Doc/library/os.rst +++ b/Doc/library/os.rst @@ -281,10 +281,14 @@ process and user. .. index:: single: process; id of parent - Return the parent's process id. + Return the parent's process id. When the parent process has exited, on Unix + the id returned is the one of the init process (1), on Windows it is still + the same id, which may be already reused by another process. - Availability: Unix. + Availability: Unix, Windows + .. versionchanged:: 3.2 + Added support for Windows. .. function:: getresuid() diff --git a/Doc/whatsnew/3.2.rst b/Doc/whatsnew/3.2.rst index 1dd1449d9a4..ff54bdda9a7 100644 --- a/Doc/whatsnew/3.2.rst +++ b/Doc/whatsnew/3.2.rst @@ -312,6 +312,11 @@ New, Improved, and Deprecated Modules (Patch by Adam Jackson; :issue:`7647`.) +* :func:`os.getppid` is now supported on Windows. Note that it will continue to + return the same pid even after the parent process has exited. + + (Patch by Jon Anglin; :issue:`6394`.) + * The :func:`shutil.copytree` function has two new options: * *ignore_dangling_symlinks*: when ``symlinks=False`` so that the function diff --git a/Lib/test/test_os.py b/Lib/test/test_os.py index 6ce0d5f42c7..f42290f4dfd 100644 --- a/Lib/test/test_os.py +++ b/Lib/test/test_os.py @@ -1183,6 +1183,17 @@ class FSEncodingTests(unittest.TestCase): check('iso-8859-15', b'\xef\xa4', '\xef\u20ac') +class PidTests(unittest.TestCase): + @unittest.skipUnless(hasattr(os, 'getppid'), "test needs os.getppid") + def test_getppid(self): + p = subprocess.Popen([sys.executable, '-c', + 'import os; print(os.getppid())'], + stdout=subprocess.PIPE) + stdout, _ = p.communicate() + # We are the parent of our subprocess + self.assertEqual(int(stdout), os.getpid()) + + def test_main(): support.run_unittest( FileTests, @@ -1200,6 +1211,7 @@ def test_main(): Win32KillTests, Win32SymlinkTests, FSEncodingTests, + PidTests, ) if __name__ == "__main__": diff --git a/Misc/ACKS b/Misc/ACKS index 2c24d2f060c..ef67d58d195 100644 --- a/Misc/ACKS +++ b/Misc/ACKS @@ -28,6 +28,7 @@ John Anderson Erik Andersén Oliver Andrich Ross Andrus +Jon Anglin Éric Araujo Jason Asbahr David Ascher diff --git a/Misc/NEWS b/Misc/NEWS index c0f2d6edee9..f3c5592196a 100644 --- a/Misc/NEWS +++ b/Misc/NEWS @@ -13,6 +13,10 @@ Core and Builtins Library ------- +- Issue #6394: os.getppid() is now supported on Windows. Note that it will + still return the id of the parent process after it has exited. This process + id may even have been reused by another unrelated process. + - Issue #9792: In case of connection failure, socket.create_connection() would swallow the exception and raise a new one, making it impossible to fetch the original errno, or to filter timeout errors. Now the diff --git a/Modules/posixmodule.c b/Modules/posixmodule.c index a83a06bb31f..981132975d6 100644 --- a/Modules/posixmodule.c +++ b/Modules/posixmodule.c @@ -121,6 +121,7 @@ corresponding Unix manual entries for more information on calls."); #else #ifdef _MSC_VER /* Microsoft compiler */ #define HAVE_GETCWD 1 +#define HAVE_GETPPID 1 #define HAVE_SPAWNV 1 #define HAVE_EXECV 1 #define HAVE_PIPE 1 @@ -4363,16 +4364,65 @@ posix_setpgrp(PyObject *self, PyObject *noargs) #endif /* HAVE_SETPGRP */ #ifdef HAVE_GETPPID + +#ifdef MS_WINDOWS +#include + +static PyObject* +win32_getppid() +{ + HANDLE snapshot; + pid_t mypid; + PyObject* result = NULL; + BOOL have_record; + PROCESSENTRY32 pe; + + mypid = getpid(); /* This function never fails */ + + snapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0); + if (snapshot == INVALID_HANDLE_VALUE) + return PyErr_SetFromWindowsErr(GetLastError()); + + pe.dwSize = sizeof(pe); + have_record = Process32First(snapshot, &pe); + while (have_record) { + if (mypid == (pid_t)pe.th32ProcessID) { + /* We could cache the ulong value in a static variable. */ + result = PyLong_FromPid((pid_t)pe.th32ParentProcessID); + break; + } + + have_record = Process32Next(snapshot, &pe); + } + + /* If our loop exits and our pid was not found (result will be NULL) + * then GetLastError will return ERROR_NO_MORE_FILES. This is an + * error anyway, so let's raise it. */ + if (!result) + result = PyErr_SetFromWindowsErr(GetLastError()); + + CloseHandle(snapshot); + + return result; +} +#endif /*MS_WINDOWS*/ + PyDoc_STRVAR(posix_getppid__doc__, "getppid() -> ppid\n\n\ -Return the parent's process id."); +Return the parent's process id. If the parent process has already exited,\n\ +Windows machines will still return its id; others systems will return the id\n\ +of the 'init' process (1)."); static PyObject * posix_getppid(PyObject *self, PyObject *noargs) { +#ifdef MS_WINDOWS + return win32_getppid(); +#else return PyLong_FromPid(getppid()); -} #endif +} +#endif /* HAVE_GETPPID */ #ifdef HAVE_GETLOGIN