and kill the process. Only enable this in environments where the
huge-page pool is properly sized and fork-safety is not a concern.
+ On Windows you need a special privilege. See the
+ `Windows documentation for large pages
+ <https://learn.microsoft.com/windows/win32/memory/large-page-support>`_
+ for details. Python will fail on startup if the required privilege
+ `SeLockMemoryPrivilege
+ <https://learn.microsoft.com/previous-versions/windows/it-pro/windows-10/security/threat-protection/security-policy-settings/lock-pages-in-memory>`_
+ is not held by the user.
+
.. versionadded:: 3.15
Even when compiled with this option, huge pages are **not** used at runtime
unless the :envvar:`PYTHON_PYMALLOC_HUGEPAGES` environment variable is set
- to ``1``. This opt-in is required because huge pages carry risks on Linux:
- if the huge-page pool is exhausted, page faults (including copy-on-write
- faults after :func:`os.fork`) deliver ``SIGBUS`` and kill the process.
+ to ``1``. This opt-in is required because huge pages
+
+ * carry risks on Linux: if the huge-page pool is exhausted, page faults
+ (including copy-on-write faults after :func:`os.fork`) deliver ``SIGBUS``
+ and kill the process.
+
+ * need a special privilege on Windows. See the `Windows documentation for large pages
+ <https://learn.microsoft.com/windows/win32/memory/large-page-support>`_
+ for details. Python will fail on startup if the required privilege
+ `SeLockMemoryPrivilege
+ <https://learn.microsoft.com/previous-versions/windows/it-pro/windows-10/security/threat-protection/security-policy-settings/lock-pages-in-memory>`_
+ is not held by the user.
The configure script checks that the platform supports ``MAP_HUGETLB``
and emits a warning if it is not available.
#include "pycore_jit.h" // _PyJIT_Fini()
#endif
+#if defined(PYMALLOC_USE_HUGEPAGES) && defined(MS_WINDOWS)
+#include <Windows.h>
+#endif
+
#include "opcode.h"
#include <locale.h> // setlocale()
return _PyStatus_OK();
}
+#if defined(PYMALLOC_USE_HUGEPAGES) && defined(MS_WINDOWS)
+static PyStatus
+get_huge_pages_privilege(void)
+{
+ HANDLE hToken;
+ if (!OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &hToken))
+ {
+ return _PyStatus_ERR("failed to open process token");
+ }
+ TOKEN_PRIVILEGES tp;
+ if (!LookupPrivilegeValue(NULL, SE_LOCK_MEMORY_NAME, &tp.Privileges[0].Luid))
+ {
+ CloseHandle(hToken);
+ return _PyStatus_ERR("failed to lookup SeLockMemoryPrivilege for huge pages");
+ }
+ tp.PrivilegeCount = 1;
+ tp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
+ // AdjustTokenPrivileges can return with nonzero status (i.e. success)
+ // but without having all privileges adjusted (ERROR_NOT_ALL_ASSIGNED).
+ BOOL status = AdjustTokenPrivileges(hToken, FALSE, &tp, sizeof(TOKEN_PRIVILEGES), NULL, NULL);
+ DWORD error = GetLastError();
+ if (!status || (error != ERROR_SUCCESS))
+ {
+ CloseHandle(hToken);
+ return _PyStatus_ERR(
+ "SeLockMemoryPrivilege not held; "
+ "grant it via Local Security Policy or disable PYTHON_PYMALLOC_HUGEPAGES");
+ }
+ if (!CloseHandle(hToken))
+ {
+ return _PyStatus_ERR("failed to close process token handle");
+ }
+ return _PyStatus_OK();
+}
+#endif
static PyStatus
pycore_init_runtime(_PyRuntimeState *runtime,
return status;
}
+#if defined(PYMALLOC_USE_HUGEPAGES) && defined(MS_WINDOWS)
+ if (runtime->allocators.use_hugepages) {
+ status = get_huge_pages_privilege();
+ if (_PyStatus_EXCEPTION(status)) {
+ return status;
+ }
+ }
+#endif
+
/* Py_Finalize leaves _Py_Finalizing set in order to help daemon
* threads behave a little more gracefully at interpreter shutdown.
* We clobber it here so the new interpreter can start with a clean