gh-104530: Enable native Win32 condition variables by default (GH-104531)

This commit is contained in:
Andrew Rogers 2024-02-02 13:50:51 +00:00 committed by GitHub
parent d29f57f603
commit b3f0b698da
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
6 changed files with 41 additions and 35 deletions

View file

@ -35,14 +35,14 @@
#include <windows.h> // CRITICAL_SECTION #include <windows.h> // CRITICAL_SECTION
/* options */ /* options */
/* non-emulated condition variables are provided for those that want /* emulated condition variables are provided for those that want
* to target Windows Vista. Modify this macro to enable them. * to target Windows XP or earlier. Modify this macro to enable them.
*/ */
#ifndef _PY_EMULATED_WIN_CV #ifndef _PY_EMULATED_WIN_CV
#define _PY_EMULATED_WIN_CV 1 /* use emulated condition variables */ #define _PY_EMULATED_WIN_CV 0 /* use non-emulated condition variables */
#endif #endif
/* fall back to emulation if not targeting Vista */ /* fall back to emulation if targeting earlier than Vista */
#if !defined NTDDI_VISTA || NTDDI_VERSION < NTDDI_VISTA #if !defined NTDDI_VISTA || NTDDI_VERSION < NTDDI_VISTA
#undef _PY_EMULATED_WIN_CV #undef _PY_EMULATED_WIN_CV
#define _PY_EMULATED_WIN_CV 1 #define _PY_EMULATED_WIN_CV 1
@ -77,7 +77,7 @@ typedef struct _PyCOND_T
#else /* !_PY_EMULATED_WIN_CV */ #else /* !_PY_EMULATED_WIN_CV */
/* Use native Win7 primitives if build target is Win7 or higher */ /* Use native Windows primitives if build target is Vista or higher */
/* SRWLOCK is faster and better than CriticalSection */ /* SRWLOCK is faster and better than CriticalSection */
typedef SRWLOCK PyMUTEX_T; typedef SRWLOCK PyMUTEX_T;

View file

@ -0,0 +1 @@
Use native Win32 condition variables.

View file

@ -610,8 +610,16 @@ PyEval_SaveThread(void)
void void
PyEval_RestoreThread(PyThreadState *tstate) PyEval_RestoreThread(PyThreadState *tstate)
{ {
#ifdef MS_WINDOWS
int err = GetLastError();
#endif
_Py_EnsureTstateNotNULL(tstate); _Py_EnsureTstateNotNULL(tstate);
_PyThreadState_Attach(tstate); _PyThreadState_Attach(tstate);
#ifdef MS_WINDOWS
SetLastError(err);
#endif
} }

View file

@ -260,13 +260,13 @@ PyMUTEX_UNLOCK(PyMUTEX_T *cs)
return 0; return 0;
} }
Py_LOCAL_INLINE(int) Py_LOCAL_INLINE(int)
PyCOND_INIT(PyCOND_T *cv) PyCOND_INIT(PyCOND_T *cv)
{ {
InitializeConditionVariable(cv); InitializeConditionVariable(cv);
return 0; return 0;
} }
Py_LOCAL_INLINE(int) Py_LOCAL_INLINE(int)
PyCOND_FINI(PyCOND_T *cv) PyCOND_FINI(PyCOND_T *cv)
{ {
@ -279,27 +279,32 @@ PyCOND_WAIT(PyCOND_T *cv, PyMUTEX_T *cs)
return SleepConditionVariableSRW(cv, cs, INFINITE, 0) ? 0 : -1; return SleepConditionVariableSRW(cv, cs, INFINITE, 0) ? 0 : -1;
} }
/* This implementation makes no distinction about timeouts. Signal /* return 0 for success, 1 on timeout, -1 on error */
* 2 to indicate that we don't know.
*/
Py_LOCAL_INLINE(int) Py_LOCAL_INLINE(int)
PyCOND_TIMEDWAIT(PyCOND_T *cv, PyMUTEX_T *cs, long long us) PyCOND_TIMEDWAIT(PyCOND_T *cv, PyMUTEX_T *cs, long long us)
{ {
return SleepConditionVariableSRW(cv, cs, (DWORD)(us/1000), 0) ? 2 : -1; BOOL success = SleepConditionVariableSRW(cv, cs, (DWORD)(us/1000), 0);
if (!success) {
if (GetLastError() == ERROR_TIMEOUT) {
return 1;
}
return -1;
}
return 0;
} }
Py_LOCAL_INLINE(int) Py_LOCAL_INLINE(int)
PyCOND_SIGNAL(PyCOND_T *cv) PyCOND_SIGNAL(PyCOND_T *cv)
{ {
WakeConditionVariable(cv); WakeConditionVariable(cv);
return 0; return 0;
} }
Py_LOCAL_INLINE(int) Py_LOCAL_INLINE(int)
PyCOND_BROADCAST(PyCOND_T *cv) PyCOND_BROADCAST(PyCOND_T *cv)
{ {
WakeAllConditionVariable(cv); WakeAllConditionVariable(cv);
return 0; return 0;
} }

View file

@ -2488,7 +2488,17 @@ PyGILState_Check(void)
return 0; return 0;
} }
return (tstate == gilstate_tss_get(runtime)); #ifdef MS_WINDOWS
int err = GetLastError();
#endif
PyThreadState *tcur = gilstate_tss_get(runtime);
#ifdef MS_WINDOWS
SetLastError(err);
#endif
return (tstate == tcur);
} }
PyGILState_STATE PyGILState_STATE

View file

@ -444,16 +444,7 @@ PyThread_set_key_value(int key, void *value)
void * void *
PyThread_get_key_value(int key) PyThread_get_key_value(int key)
{ {
/* because TLS is used in the Py_END_ALLOW_THREAD macro, return TlsGetValue(key);
* it is necessary to preserve the windows error state, because
* it is assumed to be preserved across the call to the macro.
* Ideally, the macro should be fixed, but it is simpler to
* do it here.
*/
DWORD error = GetLastError();
void *result = TlsGetValue(key);
SetLastError(error);
return result;
} }
void void
@ -525,14 +516,5 @@ void *
PyThread_tss_get(Py_tss_t *key) PyThread_tss_get(Py_tss_t *key)
{ {
assert(key != NULL); assert(key != NULL);
/* because TSS is used in the Py_END_ALLOW_THREAD macro, return TlsGetValue(key->_key);
* it is necessary to preserve the windows error state, because
* it is assumed to be preserved across the call to the macro.
* Ideally, the macro should be fixed, but it is simpler to
* do it here.
*/
DWORD error = GetLastError();
void *result = TlsGetValue(key->_key);
SetLastError(error);
return result;
} }