You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Evaluate all type creation/caching code for obvious GIL-incidental locking or deadlock issues sans GIL.
Evaluate all manual refcounting, buffer manipulations, marshaling code, etc for obvious concurrency issues.
Build a lot more threaded stress tests for the above, measure coverage.
Update documentation to describe current state, concerns around GIL-free operation modes.
Once we have some confidence in true GIL-free operations, provide a high-level opt-in/out for CFFI-backed extensions to call PyUnstable_Module_SetGIL() during extension init to control the automatic legacy extension GIL re-enable.
Clean up and enable at least optional runs of the full test suite under Windows (skipped in CI for time, currently numerous broken tests and at least one item deadlocks under the parallel runner).
Work with high-profile CFFI-consuming projects (e.g. cryptography, pynacl, pygame, ?) to ensure any future threaded stress tests are not broken by CFFI issues.
Hi @arigo@nitzmahone. As an update, after a lot of hard work, we think we've fixed the thread safety issues in the CFFI implementation and we're currently planning to publish a fork of CFFI named CFFI-ft that exports a cffi_ft module. See Quansight-Labs#16.
This will allow @hynek to publish argon2-cffi-bindings wheels that support the free-threaded build, allowing pip install jupyter to successfully complete on the free-threaded interpreter out of the box. See hynek/argon2-cffi-bindings#67 (comment).
Our hope is that the fork is short-lived and we'd like to upstream the changes ASAP. You can see what the changes look like here: main...Quansight-Labs:cffi-ft:c053f17.
The diff I linked to doesn't include subsequent changes to rename the project and modules. It still needs to be cleaned up a little to be upstreamed and a decent fraction of the change is CI configuration. I'd say the full "real" C diff is about 1000 LoC.
The testing is based on the existing CI configuration, with cp313t added to the testing matrix on all platforms. We also set up new macos-latest, windows-latest, and ubuntu-latest CI runs that that run the tests using pytest-run-parallel - a pytest plugin that batch-runs tests from an existing test suite in a thread pool to trigger thread safety issues due to use of global state in the implementation. We also set up a similar CI run using the cpython_sanity docker images running a thread sanitizer-instrumented CPython and CFFI build.
The code supports cp313t and the current beta cp314t, with CI enabled on all platforms for cp313t and the Linux TSAN build running on cp314t to avoid triggering known races in CPython that have been fixed in 3.14. While we've added a suppression file for some races in CPython that still happen under 3.14, our implementation does not trigger any races under TSAN inside CFFI in our testing.
We've also manually tested both argon2-cffi and pynacl using pytest-run-parallel and TSAN and have not seen any race reports on either an ARM Mac or on the x86 Linux docker image. The argon2-cffi tests also include an explicitly multithreaded test that doesn't trigger any races.
We're doing the fork both to fix a common annoyance users hit when they set up an environment and to get real-world testing of our code. We're happy to deal with teething issues or have any free-threading related bugs or feature requests directed to our fork.
On the other hand, this approach does impose real costs on users of CFFI who would like to experiment with free-threading. It also forces those users to depend on CFFI-ft for all Python 3.13 and newer builds due to limitations of the current environment marker standard. To mitigate that, would you prefer we don't do the temporary fork and instead open a PR with our changes for you to review right now? Or do you agree that forking is a reasonable way for us to test this without putting a lot of burden on you and the broader CFFI ecosystem and give you confidence in our changes? Ultimately we want to upstream the changes in a manner that makes you feel the most comfortable.
Reacted by Markus Unterwaditzer, Hynek Schlawack and Sam Gross
I can immediately see places that are not safe (as far as I understand it, so I may be wrong) but aren't mentioned in the diff---for example, any usage of unique_cache in _cffi_backend.c. But that's besides the point I want to make: cffi is at this point a bit moribund, and even reviewing 1000 lines of diff to make sure there is no new subtle bug in the non-freethreading case is more than I can promise. So I think that the best approach is to start and manage your own fork.
for example, any usage of unique_cache in _cffi_backend.c
See the LOCK_UNIQUE_CACHE() and UNLOCK_UNIQUE_CACHE() macros - there's a global lock that prevents concurrent access. There's no locking during the module initialization because the interpreter holds a per-module lock during import.
If you have more places you think we should look I'd love to hear about that.
So I think that the best approach is to start and manage your own fork.
OK - hopefully after we have some more real-world testing we can try again.
First, huge props to the folks at Quansight and everyone else that's taken this on- thank you!
I'll preface my opinion on "how should upstream CFFI handle this change?" with the note that I'm not entirely sure whose decision it will/should ultimately be. I'm in the odd position of "reluctant maintainer-ish" of a project for which I'm not a direct consumer (Ansible uses cryptography, which needs CFFI). Faced with the prospect of CFFI moving to source-only releases, I've taken on packaging and maintenance duties to keep things working and easily installable. My motives were both to give back, but also to stem the inevitable tide of "I can't pip install Ansible!" that would surely follow if CFFI required everyone to build it locally. While I've got plenty of experience building highly concurrent multi-(language|arch|platform) software like CFFI, I'm by no means an expert on the nuances of CFFI itself, and don't currently have the bandwidth to become one to the level that a "proper" review of this change set requires.
That said, I'm +1 for bringing these changes upstream. At first blush, I don't see a lot of risk to existing non-FT usage introduced by these changes. If a more thorough review (which I'll make time for!) bears that out, at worst, FT-flavored extensions could still encounter deadlocks, races requiring synchronization, or other failures in some feature areas, but are on the whole better off than without these changes. Issues can always be fixed. I'd probably want to put some "experimental" caution tape around it in the docs for awhile, but FT appears to be here to stay, so IMO the project should support it. I don't think anyone is served by long-term existence of a fork unless that fork wants to go in a direction that the upstream does not.
The bigger question is really around the project governance limbo- while I will make the call myself if necessary, I feel like the janitor hanging around after-hours with a set of keys being asked to approve changes to the building's electrical system, so I'd be more comfortable with explicit +1's or "don't cares" from some other folks with stakes/interest in this thing (@arigo, @mattip, others?).
Reacted by Ofek Lev and 🇺🇦 Sviatoslav Sydorenko (Святослав Сидоренко)
Thanks for picking up the challenge. I lost my maintainer role in the move to github, but would be willing to rejoin as a maintainer to share the burden.
Reacted by 🇺🇦 Sviatoslav Sydorenko (Святослав Сидоренко) and Nils Werner
would you prefer we don't do the temporary fork and instead open a PR
@ngoldbaum I'm +1 for "file the upstream PR now". Assuming nobody finds anything super-objectionable, would a CFFI 1.18.0 prerelease within the next ~ couple weeks meet the needs for your dependency concerns (at least enough to forgo publishing the fork)? e.g., listing a cffi~=1.18.0b1 dep (possibly with FT env marker - can't recall how that discussion turned out)
In the coming years free-threaded will become the default so I was worried about a required-in-practice fork. I very much appreciate everyone coming together on this!
Yes, +1 on giving @mattip the maintainer role again, or full admin if he wants it. My thanks to Matti and to Matt for their time, and to the team behind Nathan for pushing this forward!
Reacted by Matt Davis, Hynek Schlawack and Nathan Goldbaum
Assuming nobody finds anything super-objectionable, would a CFFI 1.18.0 prerelease within the next ~ couple weeks meet the needs for your dependency concerns (at least enough to forgo publishing the fork)? e.g., listing a cffi~=1.18.0b1 dep (possibly with FT env marker - can't recall how that discussion turned out)
A little over a month later - I think everything is ready. We're now thinking that this is going to be a CFFI 2.0 release and #178 sets that all up.
Is there any chance we can get some signal from @nitzmahone or @arigo that what I quoted above is still the plan, and @mattip can go ahead with merging #178 and preparing a CFFI 2.0 release shipping free-threaded support and 3.14 support?
3.14rc1 came out yesterday and the free-threaded build is no longer considered experimental in 3.14, so this is starting to get a little more acute. cibuildwheel will also enable free-threaded builds by default starting in 3.14: pypa/cibuildwheel#2503
Reacted by stonebig
Reacted by Hynek Schlawack and Daniele Parmeggiani
Is there any chance we can get some signal from @nitzmahone or @arigo that what I quoted above is still the plan
Just to close the loop here for anyone that's not watching the fun over on #178- yep! Some late-breaking 3.13t issues to diagnose (and hopefully fix), but IMO as soon as that's resolved, CFFI 2.0.0b1 can immediately follow.
Reacted by 🇺🇦 Sviatoslav Sydorenko (Святослав Сидоренко), Hynek Schlawack and Łukasz Langa
Reacted by 🇺🇦 Sviatoslav Sydorenko (Святослав Сидоренко), Hynek Schlawack and Łukasz Langa
Reacted by 🇺🇦 Sviatoslav Sydorenko (Святослав Сидоренко), Hynek Schlawack and Łukasz Langa
Activity
[-]Proper free-threaded API support blockers[/-][+]Proper free-threaded ABI support blockers[/+]colesbury commentedon Nov 2, 2024
Hi @nitzmahone - I'm happy to help out with this if you're okay with reviewing some PRs.
HeHongyeFY commentedon Dec 24, 2024
what's the expect time this issue the can be close?
Is there plan?
ofek commentedon Mar 4, 2025
Is there anything concrete that contributors can assist with here?
ofek commentedon Mar 4, 2025
It looks like the work is happening over here Quansight-Labs#1
ngoldbaum commentedon Jun 17, 2025
Hi @arigo @nitzmahone. As an update, after a lot of hard work, we think we've fixed the thread safety issues in the CFFI implementation and we're currently planning to publish a fork of CFFI named CFFI-ft that exports a
cffi_ftmodule. See Quansight-Labs#16.This will allow @hynek to publish argon2-cffi-bindings wheels that support the free-threaded build, allowing
pip install jupyterto successfully complete on the free-threaded interpreter out of the box. See hynek/argon2-cffi-bindings#67 (comment).Our hope is that the fork is short-lived and we'd like to upstream the changes ASAP. You can see what the changes look like here: main...Quansight-Labs:cffi-ft:c053f17.
The diff I linked to doesn't include subsequent changes to rename the project and modules. It still needs to be cleaned up a little to be upstreamed and a decent fraction of the change is CI configuration. I'd say the full "real" C diff is about 1000 LoC.
The testing is based on the existing CI configuration, with cp313t added to the testing matrix on all platforms. We also set up new
macos-latest,windows-latest, andubuntu-latestCI runs that that run the tests usingpytest-run-parallel- a pytest plugin that batch-runs tests from an existing test suite in a thread pool to trigger thread safety issues due to use of global state in the implementation. We also set up a similar CI run using thecpython_sanitydocker images running a thread sanitizer-instrumented CPython and CFFI build.The code supports cp313t and the current beta cp314t, with CI enabled on all platforms for cp313t and the Linux TSAN build running on cp314t to avoid triggering known races in CPython that have been fixed in 3.14. While we've added a suppression file for some races in CPython that still happen under 3.14, our implementation does not trigger any races under TSAN inside CFFI in our testing.
We've also manually tested both
argon2-cffiandpynaclusingpytest-run-paralleland TSAN and have not seen any race reports on either an ARM Mac or on the x86 Linux docker image. Theargon2-cffitests also include an explicitly multithreaded test that doesn't trigger any races.We're doing the fork both to fix a common annoyance users hit when they set up an environment and to get real-world testing of our code. We're happy to deal with teething issues or have any free-threading related bugs or feature requests directed to our fork.
On the other hand, this approach does impose real costs on users of CFFI who would like to experiment with free-threading. It also forces those users to depend on CFFI-ft for all Python 3.13 and newer builds due to limitations of the current environment marker standard. To mitigate that, would you prefer we don't do the temporary fork and instead open a PR with our changes for you to review right now? Or do you agree that forking is a reasonable way for us to test this without putting a lot of burden on you and the broader CFFI ecosystem and give you confidence in our changes? Ultimately we want to upstream the changes in a manner that makes you feel the most comfortable.
arigo commentedon Jun 17, 2025
Hi Nathan,
I can immediately see places that are not safe (as far as I understand it, so I may be wrong) but aren't mentioned in the diff---for example, any usage of
unique_cachein_cffi_backend.c. But that's besides the point I want to make: cffi is at this point a bit moribund, and even reviewing 1000 lines of diff to make sure there is no new subtle bug in the non-freethreading case is more than I can promise. So I think that the best approach is to start and manage your own fork.ngoldbaum commentedon Jun 17, 2025
See the
LOCK_UNIQUE_CACHE()andUNLOCK_UNIQUE_CACHE()macros - there's a global lock that prevents concurrent access. There's no locking during the module initialization because the interpreter holds a per-module lock during import.If you have more places you think we should look I'd love to hear about that.
OK - hopefully after we have some more real-world testing we can try again.
colesbury commentedon Jun 17, 2025
arigo commentedon Jun 17, 2025
Oh yes, sorry about that. I think github gave me a very partial view of the diff of
_cffi_backend.cfor some reason.nitzmahone commentedon Jun 18, 2025
First, huge props to the folks at Quansight and everyone else that's taken this on- thank you!
I'll preface my opinion on "how should upstream CFFI handle this change?" with the note that I'm not entirely sure whose decision it will/should ultimately be. I'm in the odd position of "reluctant maintainer-ish" of a project for which I'm not a direct consumer (Ansible uses
cryptography, which needs CFFI). Faced with the prospect of CFFI moving to source-only releases, I've taken on packaging and maintenance duties to keep things working and easily installable. My motives were both to give back, but also to stem the inevitable tide of "I can't pip install Ansible!" that would surely follow if CFFI required everyone to build it locally. While I've got plenty of experience building highly concurrent multi-(language|arch|platform) software like CFFI, I'm by no means an expert on the nuances of CFFI itself, and don't currently have the bandwidth to become one to the level that a "proper" review of this change set requires.That said, I'm +1 for bringing these changes upstream. At first blush, I don't see a lot of risk to existing non-FT usage introduced by these changes. If a more thorough review (which I'll make time for!) bears that out, at worst, FT-flavored extensions could still encounter deadlocks, races requiring synchronization, or other failures in some feature areas, but are on the whole better off than without these changes. Issues can always be fixed. I'd probably want to put some "experimental" caution tape around it in the docs for awhile, but FT appears to be here to stay, so IMO the project should support it. I don't think anyone is served by long-term existence of a fork unless that fork wants to go in a direction that the upstream does not.
The bigger question is really around the project governance limbo- while I will make the call myself if necessary, I feel like the janitor hanging around after-hours with a set of keys being asked to approve changes to the building's electrical system, so I'd be more comfortable with explicit +1's or "don't cares" from some other folks with stakes/interest in this thing (@arigo, @mattip, others?).
mattip commentedon Jun 18, 2025
Thanks for picking up the challenge. I lost my maintainer role in the move to github, but would be willing to rejoin as a maintainer to share the burden.
nitzmahone commentedon Jun 18, 2025
@mattip with a +1 (or a few days of silence 😉 ) from @arigo, I'd very much welcome that!
mattip commentedon Jun 18, 2025
If not clear, I am +1 on getting FT into CFFI
nitzmahone commentedon Jun 18, 2025
@ngoldbaum I'm +1 for "file the upstream PR now". Assuming nobody finds anything super-objectionable, would a CFFI 1.18.0 prerelease within the next ~ couple weeks meet the needs for your dependency concerns (at least enough to forgo publishing the fork)? e.g., listing a
cffi~=1.18.0b1dep (possibly with FT env marker - can't recall how that discussion turned out)ngoldbaum commentedon Jun 18, 2025
I think that's very reasonable. I'll try to tidy the diff a little and propose an upstream PR ASAP.
ofek commentedon Jun 18, 2025
In the coming years free-threaded will become the default so I was worried about a required-in-practice fork. I very much appreciate everyone coming together on this!
arigo commentedon Jun 19, 2025
Yes, +1 on giving @mattip the maintainer role again, or full admin if he wants it. My thanks to Matti and to Matt for their time, and to the team behind Nathan for pushing this forward!
nitzmahone commentedon Jun 19, 2025
@mattip you've got mail 😉
ngoldbaum commentedon Jun 19, 2025
See #178
ngoldbaum commentedon Jul 23, 2025
A little over a month later - I think everything is ready. We're now thinking that this is going to be a CFFI 2.0 release and #178 sets that all up.
Is there any chance we can get some signal from @nitzmahone or @arigo that what I quoted above is still the plan, and @mattip can go ahead with merging #178 and preparing a CFFI 2.0 release shipping free-threaded support and 3.14 support?
3.14rc1 came out yesterday and the free-threaded build is no longer considered experimental in 3.14, so this is starting to get a little more acute. cibuildwheel will also enable free-threaded builds by default starting in 3.14: pypa/cibuildwheel#2503
nitzmahone commentedon Jul 25, 2025
Just to close the loop here for anyone that's not watching the fun over on #178- yep! Some late-breaking 3.13t issues to diagnose (and hopefully fix), but IMO as soon as that's resolved, CFFI 2.0.0b1 can immediately follow.
ngoldbaum commentedon Aug 6, 2025
pyca/cryptography#12555 and pyca/pynacl#880 are now fully green and ready to go whenever CFFI 2.0.0 final is released.
mattip commentedon Sep 9, 2025
Can we close this?
mattip commentedon Feb 4, 2026
Closing, please open new issues if problems with free-threaded python are detected.