@@ -9115,16 +9115,98 @@ os_setpgrp_impl(PyObject *module)
9115
9115
#ifdef HAVE_GETPPID
9116
9116
9117
9117
#ifdef MS_WINDOWS
9118
- #include <processsnapshot.h>
9118
+ #include <winternl.h>
9119
+ #include <ProcessSnapshot.h>
9120
+
9121
+ // The structure definition in winternl.h may be incomplete.
9122
+ // This structure is the full version from the MSDN documentation.
9123
+ typedef struct _PROCESS_BASIC_INFORMATION_FULL {
9124
+ NTSTATUS ExitStatus ;
9125
+ PVOID PebBaseAddress ;
9126
+ ULONG_PTR AffinityMask ;
9127
+ LONG BasePriority ;
9128
+ ULONG_PTR UniqueProcessId ;
9129
+ ULONG_PTR InheritedFromUniqueProcessId ;
9130
+ } PROCESS_BASIC_INFORMATION_FULL ;
9131
+
9132
+ typedef NTSTATUS (NTAPI * PNT_QUERY_INFORMATION_PROCESS ) (
9133
+ IN HANDLE ProcessHandle ,
9134
+ IN PROCESSINFOCLASS ProcessInformationClass ,
9135
+ OUT PVOID ProcessInformation ,
9136
+ IN ULONG ProcessInformationLength ,
9137
+ OUT PULONG ReturnLength OPTIONAL );
9138
+
9139
+ // This function returns the process ID of the parent process.
9140
+ // Returns 0 on failure.
9141
+ static ULONG
9142
+ win32_getppid_fast (void )
9143
+ {
9144
+ NTSTATUS status ;
9145
+ HMODULE ntdll ;
9146
+ PNT_QUERY_INFORMATION_PROCESS pNtQueryInformationProcess ;
9147
+ PROCESS_BASIC_INFORMATION_FULL basic_information ;
9148
+ static ULONG cached_ppid = 0 ;
9149
+
9150
+ if (cached_ppid ) {
9151
+ // No need to query the kernel again.
9152
+ return cached_ppid ;
9153
+ }
9154
+
9155
+ ntdll = GetModuleHandleW (L"ntdll.dll" );
9156
+ if (!ntdll ) {
9157
+ return 0 ;
9158
+ }
9159
+
9160
+ pNtQueryInformationProcess = (PNT_QUERY_INFORMATION_PROCESS ) GetProcAddress (ntdll , "NtQueryInformationProcess" );
9161
+ if (!pNtQueryInformationProcess ) {
9162
+ return 0 ;
9163
+ }
9164
+
9165
+ status = pNtQueryInformationProcess (GetCurrentProcess (),
9166
+ ProcessBasicInformation ,
9167
+ & basic_information ,
9168
+ sizeof (basic_information ),
9169
+ NULL );
9170
+
9171
+ if (!NT_SUCCESS (status )) {
9172
+ return 0 ;
9173
+ }
9174
+
9175
+ // Perform sanity check on the parent process ID we received from NtQueryInformationProcess.
9176
+ // The check covers values which exceed the 32-bit range (if running on x64) as well as
9177
+ // zero and (ULONG) -1.
9178
+
9179
+ if (basic_information .InheritedFromUniqueProcessId == 0 ||
9180
+ basic_information .InheritedFromUniqueProcessId >= ULONG_MAX )
9181
+ {
9182
+ return 0 ;
9183
+ }
9184
+
9185
+ // Now that we have reached this point, the BasicInformation.InheritedFromUniqueProcessId
9186
+ // structure member contains a ULONG_PTR which represents the process ID of our parent
9187
+ // process. This process ID will be correctly returned even if the parent process has
9188
+ // exited or been terminated.
9189
+
9190
+ cached_ppid = (ULONG ) basic_information .InheritedFromUniqueProcessId ;
9191
+ return cached_ppid ;
9192
+ }
9119
9193
9120
9194
static PyObject *
9121
9195
win32_getppid (void )
9122
9196
{
9123
9197
DWORD error ;
9124
9198
PyObject * result = NULL ;
9125
9199
HANDLE process = GetCurrentProcess ();
9126
-
9127
9200
HPSS snapshot = NULL ;
9201
+ ULONG pid ;
9202
+
9203
+ pid = win32_getppid_fast ();
9204
+ if (pid != 0 ) {
9205
+ return PyLong_FromUnsignedLong (pid );
9206
+ }
9207
+
9208
+ // If failure occurs in win32_getppid_fast(), fall back to using the PSS API.
9209
+
9128
9210
error = PssCaptureSnapshot (process , PSS_CAPTURE_NONE , 0 , & snapshot );
9129
9211
if (error != ERROR_SUCCESS ) {
9130
9212
return PyErr_SetFromWindowsErr (error );
0 commit comments