-
Notifications
You must be signed in to change notification settings - Fork 2.1k
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
Switching deprecated Thread Local Storage (TLS) usage in Python 3.7 to Thread Specific Storage (TSS) #1454
Conversation
…o Thread Specific Storage (TSS)
That failing test seems to be due to |
I tried to change the So to properly fix CI, we need this PR and this change. |
Hmmmm, interesting. Seems to be this line in Either way, I'll incorporate those changes in this one, then. Thanks! :-) |
…s version of Python 3
Hurray, checks are passing! Thanks, @bstaletic! So this PR would also solve this problem the other recent PRs that are getting CI failures (i.e., #1455, #1453, #1448, ...) |
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(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Need to check for failure status
This looks great! — I just added one minor comment. |
Regarding this question:
Pybind11 already has a few
This could be interesting, but I'd propose to do it in a separate PR. |
I tried playing with Valgrind and ASAN. Running the benchmaarks for my project, there were consistent memory leaks (nothing alarming, but it was there) pointing to something in the python library. Considering that Not calling The whole point of such an excercise would be to allow projects to use ASAN as a part of the CI. |
@wjakob Done, thanks for the suggestions.
Done that. Apart from that, in principle, the
Yes, done so as well. Just noting that the macro functionality is not needed, so we could also have nice C++ typedefs and functions instead of macros. @wjakob and @bstaletic Yeah, ok, that seems indeed like a separate effort to clean up all allocations and have a clean ASAN/Valgrind run. So, let's add this cleanup to that list of things to do in such a PR, then? |
f025c36
to
8ec9490
Compare
include/pybind11/detail/internals.h
Outdated
// Thread Specific Storage (TSS) API. | ||
#if PY_VERSION_HEX >= 0x03070000 | ||
#define PYBIND11_TLS_KEY_TYPE Py_tss_t * | ||
#define PYBIND11_TLS_KEY_NULL_VALUE nullptr |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Do the type and null value need to be separate here? It looks from the way they are used that you could simplify it to something along the lines of:
#define PYBIND11_TLS_KEY_INIT(var) Py_tss_t *var = nullptr;
// or for <3.7:
#define PYBIND11_TLS_KEY_INIT(var) decltype(PyThread_create_key()) var = 0;
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hmmm, myeah, true. Depends if at some point you'd need to have the type separate.
But I can still change that, if you want? (Or feel free to push that commit to this branch yourself, as you should be allowed by GitHub.)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Considering that these are entirely internal macros (i.e. if you're using them outside of pybind11, shame on you) we can also break them up later if needed -- but for the moment it doesn't look like they are.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
(Pushed a commit)
Yes, that's definitely something that should be done in a different PR. |
Thanks! |
Travis-ci has flagged me for abuse for some unknown reason, and thus ignores my commits. It's a bit annoying. |
Or they just know you don't write bugs? ;-) |
Wow, super-strange. I'll go ahead and merge this now. |
…on 3.7 to Thread Specific Storage (TSS) (pybind#1454)" This reverts commit b4719a6.
#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) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We should use PyThread_delete_key_value
for PYBIND11_TLS_DELETE_VALUE
.
PyThread_set_key_value
is strange that it does not change key value to nullptr when it's already set to non-null value, tested on Python 2.7.12.
I notice this because my Python callback function (overriding virtual function by PYBIND11_OVERLOAD_PURE
) always segfaults upon the second call.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@cyfdecyf And did it do that before this PR? Because I thought the code from before and after would be the same, on < 3.7 Python versions?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hmmm, you're right, something weird is happening, there, using this macro :|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@YannickJadoul, @cyfdecyf : could you check if PR #1517 fixes the issue?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@wjakob I don't know the actual scenario that caused this for @cyfdecyf, but this seems OK to me. Apologies for overlooking this mistake in this original PR :-/
The only difference to the original version I can see now is at here: https://github.com/pybind/pybind11/pull/1454/files#diff-2443092219154d8d844074fa320e45f7L1828, where for Python 3 PyThread_set_key_value((key), nullptr)
is called instead of PyThread_delete_key_value((key))
. It is hard/impossible to find documentation on the old TLS API, but I think this should be OK.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sorry for the late reply. I'll try to construct a test case for this issue.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@wjakob I can confirm your patch fixes a regression we're seeing in PyTorch pytorch/pytorch#11473 (comment). We have a release this Friday, do you have an ETA on when that fix can be merged? Thanks!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I will merge it today and push out a new patch release today.
…o 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
Summary: Fixes #11419 In particular pulling in pybind/pybind11#1454 as well as pending bugfix in pybind/pybind11#1517 (documenting in comment) Pull Request resolved: #11473 Differential Revision: D9776003 Pulled By: jamesr66a fbshipit-source-id: a225dcfb66c06bcae98fd2508d9e690c24be551a
Python 3.7 deprecated the use of the 'Thread Local Storage (TLS) API', resulting in a bunch of warnings when compiling (see #1444). This PR switches between using the old TLS API and new TSS API, based on the Python version number.
See https://python.readthedocs.io/en/latest/c-api/init.html#thread-specific-storage-tss-api and https://www.python.org/dev/peps/pep-0539/ for details on the new API.
Potential issues:
#if
s. But now a few more are added to switch between the old and new API (though only at a handful of places). Is it worth adding a wrapper API, to get rid of some of the preprocessor directives within the code?Py_tss_t *
key type ofinternals::tstate
needs to be allocated (PyThread_tss_alloc()
), but since the internals struct gets statically allocated once (and there is no destructor or other cleanup), it never getsPyThread_tss_free
d (neither is the entry removed withPyThread_tss_delete
). But then the old version never calledPyThread_delete_key
, either, and the struct has a static lifetime. Should there be a way of cleaning this up (e.g., through aPy_AtExit
callback)?