Thanks to visit codestin.com
Credit goes to github.com

Skip to content

ENH: (free-threading Python) avoid C APIs returning borrowed references (⏰ wait for discussion #16839) #16834

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

Conversation

neutrinoceros
Copy link
Contributor

@neutrinoceros neutrinoceros commented Aug 15, 2024

Description

Although a bit early to start testing on the free-threaded build of Python 3.13, my prep involved reading through https://docs.python.org/3.13/howto/free-threading-extensions.html#borrowed-references, so I gave it a look and found only 3 lines of code using APIs that return borrowed reference (thread unsafe), so it seemed worth fixing them while I was at it.

Blocked by

  • By checking this box, the PR author has requested that maintainers do NOT use the "Squash and Merge" button. Maintainers should respect this when possible; however, the final decision is at the discretion of the maintainer that merges the PR.

@github-actions github-actions bot added the wcs label Aug 15, 2024
Copy link
Contributor

Thank you for your contribution to Astropy! 🌌 This checklist is meant to remind the package maintainers who will review this pull request of some common things to look for.

  • Do the proposed changes actually accomplish desired goals?
  • Do the proposed changes follow the Astropy coding guidelines?
  • Are tests added/updated as required? If so, do they follow the Astropy testing guidelines?
  • Are docs added/updated as required? If so, do they follow the Astropy documentation guidelines?
  • Is rebase and/or squash necessary? If so, please provide the author with appropriate instructions. Also see instructions for rebase and squash.
  • Did the CI pass? If no, are the failures related? If you need to run daily and weekly cron jobs as part of the PR, please apply the "Extra CI" label. Codestyle issues can be fixed by the bot.
  • Is a change log needed? If yes, did the change log check pass? If no, add the "no-changelog-entry-needed" label. If this is a manual backport, use the "skip-changelog-checks" label unless special changelog handling is necessary.
  • Is this a big PR that makes a "What's new?" entry worthwhile and if so, is (1) a "what's new" entry included in this PR and (2) the "whatsnew-needed" label applied?
  • At the time of adding the milestone, if the milestone set requires a backport to release branch(es), apply the appropriate "backport-X.Y.x" label(s) before merge.

Copy link
Contributor

👋 Thank you for your draft pull request! Do you know that you can use [ci skip] or [skip ci] in your commit messages to skip running continuous integration tests until you are ready?

@neutrinoceros neutrinoceros marked this pull request as ready for review August 15, 2024 07:57
@neutrinoceros neutrinoceros requested a review from mcara as a code owner August 15, 2024 07:57
Copy link
Contributor

@mhvk mhvk left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I like getting us towards free-threading, but this seems a little too ad-hoc. My sense is that we should look at what numpy is doing -- numpy/numpy#26157 -- and see if we can follow their approach. Note that they vendor pythoncapi-compat so that they can just change code, rather than have python version dependent stuff all over. I think we should follow a similar approach (since we built against numpy, perhaps we do not even have to vendor it ourselves?).

@pllim pllim added this to the v7.0.0 milestone Aug 15, 2024
@neutrinoceros
Copy link
Contributor Author

My sense is that we should look at what numpy is doing -- numpy/numpy#26157 -- and see if we can follow their approach

This is actually how I got here: I was following along numpy/numpy#27145 😅

@neutrinoceros
Copy link
Contributor Author

Note that they vendor pythoncapi-compat so that they can just change code, rather than have python version dependent stuff all over. I think we should follow a similar approach (since we built against numpy, perhaps we do not even have to vendor it ourselves?).

I cannot help but feel this could be overkill at this point, but maybe worth opening an issue about it now ?

@mhvk
Copy link
Contributor

mhvk commented Aug 15, 2024

Maybe we can also #include "npy_pycompat.h", which I think gives you PyDict_GetItemStringRef? That would be something one could do on a file-by-file basis. Though of course it does mean that one needs a certain minimum version of numpy to build astropy...

@neutrinoceros neutrinoceros marked this pull request as draft August 15, 2024 17:01
@neutrinoceros neutrinoceros force-pushed the wcs/freethreading/avoid_borrowed_ref_apis branch from 376febd to 18779ca Compare August 15, 2024 17:11
@neutrinoceros neutrinoceros marked this pull request as ready for review August 15, 2024 17:12
@neutrinoceros
Copy link
Contributor Author

I've updated the patch with the missing Py_DECREF. I can open an issue to discuss more broadly the possibility of including pythoncapi-compat tomorrow unless someone wants to beat me to it !

Copy link
Contributor

@mhvk mhvk left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This isn't quite right still for the PyDict_GetItemStringRef and also the actual code is not quite right anyway, since the imported module should be DECREF'd. Not that it would matter much, since if astropy.units disappears, there are larger problems than thread safety...

Somewhat similarly, for the two PyList_GetItemRef, I think the fix is not particularly useful, since if there were multiple threads mangling the list, the code would still fail anyway.

Overall, remain unsure this is worth doing.

@@ -111,6 +114,10 @@ PyUnitListProxy_New(
self->size = size;
self->array = array;
self->unit_class = unit_class;

#if PY_VERSION_HEX >= 0x030d00c1
Py_DECREF(unit_class);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Instead, do not Py_INCREF(unit_class) on l. 104

@@ -91,8 +91,11 @@ PyUnitListProxy_New(
if (units_dict == NULL) {
return NULL;
}

#if PY_VERSION_HEX >= 0x030d00c1
PyDict_GetItemStringRef(units_dict, "Unit", &unit_class);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This still is not quite right: PyDict_GetItemStringRef returns an int that is 1 if the entry is found, 0 if not, -1 on error. One should check this. Indeed, on error, unit_class is not set, so the current check would fail (since unit_class is not initialized to NULL).

@@ -341,7 +341,13 @@ static int PyCelprm_set_ref(PyCelprm* self, PyObject* value, void* closure)

if (PyList_Check(value)) {
for (i = 0; i < size; i++) {
#if PY_VERSION_HEX >= 0x030d00c1
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Here, it is a bit more of a logic question: this list already has been turned into an array. If there is any risk of another thread mangling it during our little loop here, surely the risk that it is mangled between being turned into an array and this piece of code is even larger. So, really, the list would need to be locked, or, perhaps better, the conversion to NPY_DOUBLE should be done in a second stage, after plain conversion to an array (which would be NPY_OBJECT if None were present.

Separately, if we are really worried about other threads mangling the list, we should check for errors...

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think I need to learn about how locking single objects works in the C API before I can properly respond here. I'll add it to my list !

@@ -571,7 +571,13 @@ static int PyPrjprm_set_pv(PyPrjprm* self, PyObject* value, void* closure)

if (PyList_Check(value)) {
for (k = 0; k < size; k++) {
#if PY_VERSION_HEX >= 0x030d00c1
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same as above, though seeing this done twice, it also would seem better to factor this out and make a separate function that returns a MaskedArray or so. To be honest, I think this is best done outside of c.

@neutrinoceros neutrinoceros changed the title ENH: (free-threading Python) avoid C APIs returning borrowed references ENH: (free-threading Python) avoid C APIs returning borrowed references (⏰ wait for discussion #16839) Aug 16, 2024
@neutrinoceros
Copy link
Contributor Author

Clearly I misjudged the difficulty of doing this properly. I'll give it another push to try and make it correct now, but I'll switch it to draft and encourage we move to the broader discussion in #16839.

Thank you so much @mhvk for bearing with me !

@neutrinoceros neutrinoceros marked this pull request as draft August 16, 2024 09:46
@neutrinoceros
Copy link
Contributor Author

This is not nearly converged enough to make the cut. In fact I'm not even sure we should aim to merge this for 7.1 so let's just remove the milestone for now.

@neutrinoceros neutrinoceros removed this from the v7.0.0 milestone Oct 16, 2024
Copy link
Contributor

Hi humans 👋 - this pull request hasn't had any new commits for approximately 4 months. I plan to close this in 30 days if the pull request doesn't have any new commits by then.

In lieu of a stalled pull request, please consider closing this and open an issue instead if a reminder is needed to revisit in the future. Maintainers may also choose to add keep-open label to keep this PR open but it is discouraged unless absolutely necessary.

If this PR still needs to be reviewed, as an author, you can rebase it to reset the clock.

If you believe I commented on this pull request incorrectly, please report this here.

Copy link
Contributor

I'm going to close this pull request as per my previous message. If you think what is being added/fixed here is still important, please remember to open an issue to keep track of it. Thanks!

If this is the first time I am commenting on this issue, or if you believe I closed this issue incorrectly, please report this here.

@github-actions github-actions bot closed this Feb 16, 2025
@neutrinoceros neutrinoceros deleted the wcs/freethreading/avoid_borrowed_ref_apis branch February 18, 2025 14:38
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants