Skip to content

Commit b4719a6

Browse files
YannickJadoulwjakob
authored andcommitted
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
1 parent b30734e commit b4719a6

File tree

3 files changed

+38
-20
lines changed

3 files changed

+38
-20
lines changed

.travis.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -68,7 +68,7 @@ matrix:
6868
env: PYTHON=2.7 CPP=14 CLANG CMAKE=1
6969
- os: osx
7070
osx_image: xcode9
71-
env: PYTHON=3.6 CPP=14 CLANG DEBUG=1
71+
env: PYTHON=3.7 CPP=14 CLANG DEBUG=1
7272
# Test a PyPy 2.7 build
7373
- os: linux
7474
env: PYPY=5.8 PYTHON=2.7 CPP=11 GCC=4.8

include/pybind11/detail/internals.h

Lines changed: 32 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,25 @@ inline PyTypeObject *make_static_property_type();
1818
inline PyTypeObject *make_default_metaclass();
1919
inline PyObject *make_object_base_type(PyTypeObject *metaclass);
2020

21+
// The old Python Thread Local Storage (TLS) API is deprecated in Python 3.7 in favor of the new
22+
// Thread Specific Storage (TSS) API.
23+
#if PY_VERSION_HEX >= 0x03070000
24+
#define PYBIND11_TLS_KEY_INIT(var) Py_tss_t *var = nullptr
25+
#define PYBIND11_TLS_GET_VALUE(key) PyThread_tss_get((key))
26+
#define PYBIND11_TLS_REPLACE_VALUE(key, value) PyThread_tss_set((key), (tstate))
27+
#define PYBIND11_TLS_DELETE_VALUE(key) PyThread_tss_set((key), nullptr)
28+
#else
29+
// Usually an int but a long on Cygwin64 with Python 3.x
30+
#define PYBIND11_TLS_KEY_INIT(var) decltype(PyThread_create_key()) var = 0
31+
#define PYBIND11_TLS_GET_VALUE(key) PyThread_get_key_value((key))
32+
#if PY_MAJOR_VERSION < 3
33+
#define PYBIND11_TLS_REPLACE_VALUE(key, value) do { PyThread_delete_key_value((key)); PyThread_set_key_value((key), (value)); } while (false)
34+
#else
35+
#define PYBIND11_TLS_REPLACE_VALUE(key, value) PyThread_set_key_value((key), (value))
36+
#endif
37+
#define PYBIND11_TLS_DELETE_VALUE(key) PyThread_set_key_value((key), nullptr)
38+
#endif
39+
2140
// Python loads modules by default with dlopen with the RTLD_LOCAL flag; under libc++ and possibly
2241
// other STLs, this means `typeid(A)` from one module won't equal `typeid(A)` from another module
2342
// even when `A` is the same, non-hidden-visibility type (e.g. from a common include). Under
@@ -79,7 +98,7 @@ struct internals {
7998
PyTypeObject *default_metaclass;
8099
PyObject *instance_base;
81100
#if defined(WITH_THREAD)
82-
decltype(PyThread_create_key()) tstate = 0; // Usually an int but a long on Cygwin64 with Python 3.x
101+
PYBIND11_TLS_KEY_INIT(tstate);
83102
PyInterpreterState *istate = nullptr;
84103
#endif
85104
};
@@ -111,7 +130,7 @@ struct type_info {
111130
};
112131

113132
/// Tracks the `internals` and `type_info` ABI version independent of the main library version
114-
#define PYBIND11_INTERNALS_VERSION 1
133+
#define PYBIND11_INTERNALS_VERSION 2
115134

116135
#if defined(WITH_THREAD)
117136
# define PYBIND11_INTERNALS_KIND ""
@@ -166,8 +185,17 @@ PYBIND11_NOINLINE inline internals &get_internals() {
166185
#if defined(WITH_THREAD)
167186
PyEval_InitThreads();
168187
PyThreadState *tstate = PyThreadState_Get();
169-
internals_ptr->tstate = PyThread_create_key();
170-
PyThread_set_key_value(internals_ptr->tstate, tstate);
188+
#if PY_VERSION_HEX >= 0x03070000
189+
internals_ptr->tstate = PyThread_tss_alloc();
190+
if (!internals_ptr->tstate || PyThread_tss_create(internals_ptr->tstate))
191+
pybind11_fail("get_internals: could not successfully initialize the TSS key!");
192+
PyThread_tss_set(internals_ptr->tstate, tstate);
193+
#else
194+
internals_ptr->tstate = PyThread_create_key();
195+
if (internals_ptr->tstate == -1)
196+
pybind11_fail("get_internals: could not successfully initialize the TLS key!");
197+
PyThread_set_key_value(internals_ptr->tstate, tstate);
198+
#endif
171199
internals_ptr->istate = tstate->interp;
172200
#endif
173201
builtins[id] = capsule(internals_pp);

include/pybind11/pybind11.h

Lines changed: 5 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1774,7 +1774,7 @@ class gil_scoped_acquire {
17741774
public:
17751775
PYBIND11_NOINLINE gil_scoped_acquire() {
17761776
auto const &internals = detail::get_internals();
1777-
tstate = (PyThreadState *) PyThread_get_key_value(internals.tstate);
1777+
tstate = (PyThreadState *) PYBIND11_TLS_GET_VALUE(internals.tstate);
17781778

17791779
if (!tstate) {
17801780
tstate = PyThreadState_New(internals.istate);
@@ -1783,10 +1783,7 @@ class gil_scoped_acquire {
17831783
pybind11_fail("scoped_acquire: could not create thread state!");
17841784
#endif
17851785
tstate->gilstate_counter = 0;
1786-
#if PY_MAJOR_VERSION < 3
1787-
PyThread_delete_key_value(internals.tstate);
1788-
#endif
1789-
PyThread_set_key_value(internals.tstate, tstate);
1786+
PYBIND11_TLS_REPLACE_VALUE(internals.tstate, tstate);
17901787
} else {
17911788
release = detail::get_thread_state_unchecked() != tstate;
17921789
}
@@ -1825,7 +1822,7 @@ class gil_scoped_acquire {
18251822
#endif
18261823
PyThreadState_Clear(tstate);
18271824
PyThreadState_DeleteCurrent();
1828-
PyThread_delete_key_value(detail::get_internals().tstate);
1825+
PYBIND11_TLS_DELETE_VALUE(detail::get_internals().tstate);
18291826
release = false;
18301827
}
18311828
}
@@ -1850,11 +1847,7 @@ class gil_scoped_release {
18501847
tstate = PyEval_SaveThread();
18511848
if (disassoc) {
18521849
auto key = internals.tstate;
1853-
#if PY_MAJOR_VERSION < 3
1854-
PyThread_delete_key_value(key);
1855-
#else
1856-
PyThread_set_key_value(key, nullptr);
1857-
#endif
1850+
PYBIND11_TLS_DELETE_VALUE(key);
18581851
}
18591852
}
18601853
~gil_scoped_release() {
@@ -1863,10 +1856,7 @@ class gil_scoped_release {
18631856
PyEval_RestoreThread(tstate);
18641857
if (disassoc) {
18651858
auto key = detail::get_internals().tstate;
1866-
#if PY_MAJOR_VERSION < 3
1867-
PyThread_delete_key_value(key);
1868-
#endif
1869-
PyThread_set_key_value(key, tstate);
1859+
PYBIND11_TLS_REPLACE_VALUE(key, tstate);
18701860
}
18711861
}
18721862
private:

0 commit comments

Comments
 (0)