Commit c07c0c74 by Yannick Jadoul Committed by Wenzel Jakob

Switching deprecated Thread Local Storage (TLS) usage in Python 3.7 to Thread…

Switching deprecated Thread Local Storage (TLS) usage in Python 3.7 to Thread Specific Storage (TSS) (#1454)

* Switching deprecated Thread Local Storage (TLS) usage in Python 3.7 to Thread Specific Storage (TSS)

* Changing Python version from 3.6 to 3.7 for Travis CI, to match brew's version of Python 3

* Introducing PYBIND11_ macros to switch between TLS and TSS API
parent 11ee8ad5
...@@ -67,8 +67,8 @@ matrix: ...@@ -67,8 +67,8 @@ matrix:
osx_image: xcode7.3 osx_image: xcode7.3
env: PYTHON=2.7 CPP=14 CLANG CMAKE=1 env: PYTHON=2.7 CPP=14 CLANG CMAKE=1
- os: osx - os: osx
osx_image: xcode8.3 osx_image: xcode9
env: PYTHON=3.6 CPP=14 CLANG DEBUG=1 env: PYTHON=3.7 CPP=14 CLANG DEBUG=1
# Test a PyPy 2.7 build # Test a PyPy 2.7 build
- os: linux - os: linux
env: PYPY=5.8 PYTHON=2.7 CPP=11 GCC=4.8 env: PYPY=5.8 PYTHON=2.7 CPP=11 GCC=4.8
......
...@@ -18,6 +18,25 @@ inline PyTypeObject *make_static_property_type(); ...@@ -18,6 +18,25 @@ inline PyTypeObject *make_static_property_type();
inline PyTypeObject *make_default_metaclass(); inline PyTypeObject *make_default_metaclass();
inline PyObject *make_object_base_type(PyTypeObject *metaclass); inline PyObject *make_object_base_type(PyTypeObject *metaclass);
// The old Python Thread Local Storage (TLS) API is deprecated in Python 3.7 in favor of the new
// Thread Specific Storage (TSS) API.
#if PY_VERSION_HEX >= 0x03070000
#define PYBIND11_TLS_KEY_INIT(var) Py_tss_t *var = nullptr
#define PYBIND11_TLS_GET_VALUE(key) PyThread_tss_get((key))
#define PYBIND11_TLS_REPLACE_VALUE(key, value) PyThread_tss_set((key), (tstate))
#define PYBIND11_TLS_DELETE_VALUE(key) PyThread_tss_set((key), nullptr)
#else
// Usually an int but a long on Cygwin64 with Python 3.x
#define PYBIND11_TLS_KEY_INIT(var) decltype(PyThread_create_key()) var = 0
#define PYBIND11_TLS_GET_VALUE(key) PyThread_get_key_value((key))
#if PY_MAJOR_VERSION < 3
#define PYBIND11_TLS_REPLACE_VALUE(key, value) do { PyThread_delete_key_value((key)); PyThread_set_key_value((key), (value)); } while (false)
#else
#define PYBIND11_TLS_REPLACE_VALUE(key, value) PyThread_set_key_value((key), (value))
#endif
#define PYBIND11_TLS_DELETE_VALUE(key) PyThread_set_key_value((key), nullptr)
#endif
// Python loads modules by default with dlopen with the RTLD_LOCAL flag; under libc++ and possibly // Python loads modules by default with dlopen with the RTLD_LOCAL flag; under libc++ and possibly
// other STLs, this means `typeid(A)` from one module won't equal `typeid(A)` from another module // other STLs, this means `typeid(A)` from one module won't equal `typeid(A)` from another module
// even when `A` is the same, non-hidden-visibility type (e.g. from a common include). Under // even when `A` is the same, non-hidden-visibility type (e.g. from a common include). Under
...@@ -79,7 +98,7 @@ struct internals { ...@@ -79,7 +98,7 @@ struct internals {
PyTypeObject *default_metaclass; PyTypeObject *default_metaclass;
PyObject *instance_base; PyObject *instance_base;
#if defined(WITH_THREAD) #if defined(WITH_THREAD)
decltype(PyThread_create_key()) tstate = 0; // Usually an int but a long on Cygwin64 with Python 3.x PYBIND11_TLS_KEY_INIT(tstate);
PyInterpreterState *istate = nullptr; PyInterpreterState *istate = nullptr;
#endif #endif
}; };
...@@ -111,7 +130,7 @@ struct type_info { ...@@ -111,7 +130,7 @@ struct type_info {
}; };
/// Tracks the `internals` and `type_info` ABI version independent of the main library version /// Tracks the `internals` and `type_info` ABI version independent of the main library version
#define PYBIND11_INTERNALS_VERSION 1 #define PYBIND11_INTERNALS_VERSION 2
#if defined(WITH_THREAD) #if defined(WITH_THREAD)
# define PYBIND11_INTERNALS_KIND "" # define PYBIND11_INTERNALS_KIND ""
...@@ -166,8 +185,17 @@ PYBIND11_NOINLINE inline internals &get_internals() { ...@@ -166,8 +185,17 @@ PYBIND11_NOINLINE inline internals &get_internals() {
#if defined(WITH_THREAD) #if defined(WITH_THREAD)
PyEval_InitThreads(); PyEval_InitThreads();
PyThreadState *tstate = PyThreadState_Get(); PyThreadState *tstate = PyThreadState_Get();
#if PY_VERSION_HEX >= 0x03070000
internals_ptr->tstate = PyThread_tss_alloc();
if (!internals_ptr->tstate || PyThread_tss_create(internals_ptr->tstate))
pybind11_fail("get_internals: could not successfully initialize the TSS key!");
PyThread_tss_set(internals_ptr->tstate, tstate);
#else
internals_ptr->tstate = PyThread_create_key(); internals_ptr->tstate = PyThread_create_key();
if (internals_ptr->tstate == -1)
pybind11_fail("get_internals: could not successfully initialize the TLS key!");
PyThread_set_key_value(internals_ptr->tstate, tstate); PyThread_set_key_value(internals_ptr->tstate, tstate);
#endif
internals_ptr->istate = tstate->interp; internals_ptr->istate = tstate->interp;
#endif #endif
builtins[id] = capsule(internals_pp); builtins[id] = capsule(internals_pp);
......
...@@ -1747,7 +1747,7 @@ class gil_scoped_acquire { ...@@ -1747,7 +1747,7 @@ class gil_scoped_acquire {
public: public:
PYBIND11_NOINLINE gil_scoped_acquire() { PYBIND11_NOINLINE gil_scoped_acquire() {
auto const &internals = detail::get_internals(); auto const &internals = detail::get_internals();
tstate = (PyThreadState *) PyThread_get_key_value(internals.tstate); tstate = (PyThreadState *) PYBIND11_TLS_GET_VALUE(internals.tstate);
if (!tstate) { if (!tstate) {
tstate = PyThreadState_New(internals.istate); tstate = PyThreadState_New(internals.istate);
...@@ -1756,10 +1756,7 @@ public: ...@@ -1756,10 +1756,7 @@ public:
pybind11_fail("scoped_acquire: could not create thread state!"); pybind11_fail("scoped_acquire: could not create thread state!");
#endif #endif
tstate->gilstate_counter = 0; tstate->gilstate_counter = 0;
#if PY_MAJOR_VERSION < 3 PYBIND11_TLS_REPLACE_VALUE(internals.tstate, tstate);
PyThread_delete_key_value(internals.tstate);
#endif
PyThread_set_key_value(internals.tstate, tstate);
} else { } else {
release = detail::get_thread_state_unchecked() != tstate; release = detail::get_thread_state_unchecked() != tstate;
} }
...@@ -1798,7 +1795,7 @@ public: ...@@ -1798,7 +1795,7 @@ public:
#endif #endif
PyThreadState_Clear(tstate); PyThreadState_Clear(tstate);
PyThreadState_DeleteCurrent(); PyThreadState_DeleteCurrent();
PyThread_delete_key_value(detail::get_internals().tstate); PYBIND11_TLS_DELETE_VALUE(detail::get_internals().tstate);
release = false; release = false;
} }
} }
...@@ -1823,11 +1820,7 @@ public: ...@@ -1823,11 +1820,7 @@ public:
tstate = PyEval_SaveThread(); tstate = PyEval_SaveThread();
if (disassoc) { if (disassoc) {
auto key = internals.tstate; auto key = internals.tstate;
#if PY_MAJOR_VERSION < 3 PYBIND11_TLS_DELETE_VALUE(key);
PyThread_delete_key_value(key);
#else
PyThread_set_key_value(key, nullptr);
#endif
} }
} }
~gil_scoped_release() { ~gil_scoped_release() {
...@@ -1836,10 +1829,7 @@ public: ...@@ -1836,10 +1829,7 @@ public:
PyEval_RestoreThread(tstate); PyEval_RestoreThread(tstate);
if (disassoc) { if (disassoc) {
auto key = detail::get_internals().tstate; auto key = detail::get_internals().tstate;
#if PY_MAJOR_VERSION < 3 PYBIND11_TLS_REPLACE_VALUE(key, tstate);
PyThread_delete_key_value(key);
#endif
PyThread_set_key_value(key, tstate);
} }
} }
private: private:
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment