summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Doc/library/os.rst8
-rw-r--r--Doc/whatsnew/3.2.rst5
-rw-r--r--Lib/test/test_os.py12
-rw-r--r--Misc/ACKS1
-rw-r--r--Misc/NEWS4
-rw-r--r--Modules/posixmodule.c54
6 files changed, 80 insertions, 4 deletions
diff --git a/Doc/library/os.rst b/Doc/library/os.rst
index 2e29e4a..9373bda 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 1dd1449..ff54bdd 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 6ce0d5f..f42290f 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 2c24d2f..ef67d58 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 c0f2d6e..f3c5592 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 a83a06b..9811329 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 <tlhelp32.h>
+
+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