Skip to content

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

Closed
neutrinoceros wants to merge 3 commits into
astropy:mainfrom
neutrinoceros:wcs/freethreading/avoid_borrowed_ref_apis
Closed

neutrinoceros wants to merge 3 commits into
astropy:mainfrom
neutrinoceros:wcs/freethreading/avoid_borrowed_ref_apis

Conversation

@neutrinoceros

@neutrinoceros neutrinoceros commented Aug 15, 2024 •

Copy link
Copy Markdown
Contributor

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
@github-actions

Copy link
Copy Markdown
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.

@github-actions

Copy link
Copy Markdown
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

@mhvk mhvk left a comment

Copy link
Copy Markdown
Contributor

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?).

Comment thread astropy/wcs/src/unit_list_proxy.c Outdated
@pllim pllim added this to the v7.0.0 milestone Aug 15, 2024
@neutrinoceros

Copy link
Copy Markdown
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
Copy Markdown
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

mhvk commented Aug 15, 2024

Copy link
Copy Markdown
Contributor

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
Copy Markdown
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 !

@mhvk mhvk left a comment

Copy link
Copy Markdown
Contributor

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.

Comment thread astropy/wcs/src/unit_list_proxy.c Outdated
self->unit_class = unit_class;

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

Copy link
Copy Markdown
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

Comment thread astropy/wcs/src/unit_list_proxy.c Outdated
}

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

Copy link
Copy Markdown
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).


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

Copy link
Copy Markdown
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
Copy Markdown
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 !


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

Copy link
Copy Markdown
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
Copy Markdown
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
Copy Markdown
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
@github-actions github-actions Bot added the Close? Tell stale bot that this issue/PR is stale label Jan 16, 2025
@github-actions

Copy link
Copy Markdown
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.

@github-actions github-actions Bot added the closed-by-bot Closed by stale bot label Feb 16, 2025
@github-actions

Copy link
Copy Markdown
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

Labels

Close? Tell stale bot that this issue/PR is stale closed-by-bot Closed by stale bot Python 3.13 wcs

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants