Thanks to visit codestin.com
Credit goes to github.com

Skip to content

gh-116195: Implement win32_getppid_fast #116205

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 11 commits into from Mar 14, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Improves performance of :func:`os.getppid` by using an alternate system API when available. Contributed by vxiiduu.
86 changes: 84 additions & 2 deletions Modules/posixmodule.c
Original file line number Diff line number Diff line change
Expand Up @@ -9115,16 +9115,98 @@ os_setpgrp_impl(PyObject *module)
#ifdef HAVE_GETPPID

#ifdef MS_WINDOWS
#include <processsnapshot.h>
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this header file is still required because we are using PssCaptureSnapshot bellow.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Indeed it is - missed that. Is there a way I can add commits to the PR without making a new one? On other repos just committing to my own branch worked.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You can just add new commit to your branch, and this PR will be updated. Close a PR and create new one will make the review work harder.

#include <winternl.h>
#include <ProcessSnapshot.h>

// The structure definition in winternl.h may be incomplete.
// This structure is the full version from the MSDN documentation.
typedef struct _PROCESS_BASIC_INFORMATION_FULL {
NTSTATUS ExitStatus;
PVOID PebBaseAddress;
ULONG_PTR AffinityMask;
LONG BasePriority;
ULONG_PTR UniqueProcessId;
ULONG_PTR InheritedFromUniqueProcessId;
} PROCESS_BASIC_INFORMATION_FULL;

typedef NTSTATUS (NTAPI *PNT_QUERY_INFORMATION_PROCESS) (
IN HANDLE ProcessHandle,
IN PROCESSINFOCLASS ProcessInformationClass,
OUT PVOID ProcessInformation,
IN ULONG ProcessInformationLength,
OUT PULONG ReturnLength OPTIONAL);

// This function returns the process ID of the parent process.
// Returns 0 on failure.
static ULONG
win32_getppid_fast(void)
{
NTSTATUS status;
HMODULE ntdll;
PNT_QUERY_INFORMATION_PROCESS pNtQueryInformationProcess;
PROCESS_BASIC_INFORMATION_FULL basic_information;
static ULONG cached_ppid = 0;

if (cached_ppid) {
// No need to query the kernel again.
return cached_ppid;
}

ntdll = GetModuleHandleW(L"ntdll.dll");
if (!ntdll) {
return 0;
}

pNtQueryInformationProcess = (PNT_QUERY_INFORMATION_PROCESS) GetProcAddress(ntdll, "NtQueryInformationProcess");
if (!pNtQueryInformationProcess) {
return 0;
}

status = pNtQueryInformationProcess(GetCurrentProcess(),
ProcessBasicInformation,
&basic_information,
sizeof(basic_information),
NULL);

if (!NT_SUCCESS(status)) {
return 0;
}

// Perform sanity check on the parent process ID we received from NtQueryInformationProcess.
// The check covers values which exceed the 32-bit range (if running on x64) as well as
// zero and (ULONG) -1.

if (basic_information.InheritedFromUniqueProcessId == 0 ||
basic_information.InheritedFromUniqueProcessId >= ULONG_MAX)
{
return 0;
}

// Now that we have reached this point, the BasicInformation.InheritedFromUniqueProcessId
// structure member contains a ULONG_PTR which represents the process ID of our parent
// process. This process ID will be correctly returned even if the parent process has
// exited or been terminated.

cached_ppid = (ULONG) basic_information.InheritedFromUniqueProcessId;
return cached_ppid;
}

static PyObject*
win32_getppid(void)
{
DWORD error;
PyObject* result = NULL;
HANDLE process = GetCurrentProcess();

HPSS snapshot = NULL;
ULONG pid;

pid = win32_getppid_fast();
if (pid != 0) {
return PyLong_FromUnsignedLong(pid);
}

// If failure occurs in win32_getppid_fast(), fall back to using the PSS API.

error = PssCaptureSnapshot(process, PSS_CAPTURE_NONE, 0, &snapshot);
if (error != ERROR_SUCCESS) {
return PyErr_SetFromWindowsErr(error);
Expand Down