#6394: Add os.getppid() support for Windows.
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 @@
 
    .. 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 @@
 
   (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 @@
         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 @@
         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 @@
 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 @@
 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 @@
 #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 @@
 #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