Uh oh!
There was an error while loading. Please reload this page.
Stop shipping free-threaded (cp314t) wheels - #155
Conversation
v2.5.0 published cp314t wheels. Those advertise free-threading, but _pyforefire declares no py::mod_gil_not_used(), so importing it makes the interpreter re-enable the GIL: the wheel promises something it then turns off. The core could not honour the promise anyway. There is not one mutex, atomic or lock guard in src/. SimulationParameters::GetInstance() is an unguarded lazy singleton, ForeFireAtom::instanceNRCount hands out object IDs through a non-atomic ++, FireDomain::propModelsTable is a process-wide array of 50 slots mutated at runtime, and FireNode keeps its scheme and smoothing settings in mutable statics. The binding never releases the GIL, which is what keeps all of this safe today. Also adds the 3.14 classifier, since non-free-threaded cp314 wheels do build and pass CI.
filippi
commented
Aug 11, 2026
via email
Yes a real problem.. singleton is best i could do for coupling with MesoNH
fortran and MPI, i needed a staticcreference in memory, sovit is indeed
deep inside then Command struct.. so a bit like having a second kernel if
ipython like use.
********************************************
Jean-Baptiste Filippi
Chargé de Recherches
SPE - UMR 6134 CNRS
Université de Corse
Quartier grossetti
BP 52, 20250 Corte
Tel. +33 495 450 158
******************************************
Le mar. 11 août 2026, 18:56, Hugo ***@***.***> a écrit : … v2.5.0 shipped free-threaded wheels. It should not have, and this stops it.
forefire-2.5.0-cp314-cp314t-manylinux_2_27_x86_64...whl
forefire-2.5.0-cp314-cp314t-macosx_14_0_arm64.whl
cibuildwheel built cp314t because nothing in skip excluded it. My
oversight in #151 <#151>: I
assumed free-threaded builds were opt-in.
Why that is a problem
A free-threaded wheel tells users the extension is safe without the GIL.
_pyforefire.cpp uses a plain PYBIND11_MODULE with no
py::mod_gil_not_used(), so CPython re-enables the GIL when it is
imported. The wheel advertises free-threading and then silently switches it
off. Users get a slower interpreter and a promise that was never kept.
The core could not honour that promise regardless. Searching src/ for
std::mutex, std::atomic, lock_guard, pthread_mutex or OpenMP critical
sections returns *zero matches* across roughly 33,000 lines. Concretely:
Shared state Where Problem without the GIL
SimulationParameters::instance SimulationParameters.cpp:28 if (instance
== 0) instance = new SimulationParameters; Two threads can both allocate,
then diverge with different parameter objects.
ForeFireAtom::instanceNRCount ForeFireAtom.h:106 Every object's ID comes
from instanceNRCount++, non-atomic. Concurrent construction races and can
duplicate IDs.
FireDomain::propModelsTable FireDomain.cpp:58,697,859 A process-wide
array of 50 slots, scanned for a free index and written at runtime. Two
domains compete for the same slots.
FireNode::nmlScheme, smoothing, relax, minSpeed, minFrontDepth
FireNode.cpp:22-30 Per-class mutable settings shared by every node in the
process.
None of this is a bug today. The binding never calls gil_scoped_release,
so the GIL serialises every entry point, and ForeFire is a
single-simulation-per-process design. The GIL is exactly what makes it
safe, which is why a wheel built to run without one is the wrong thing to
publish.
Changes
- cp314t-* added to [tool.cibuildwheel] skip, with a comment recording
why, so it is not removed casually.
- Programming Language :: Python :: 3.14 added to the classifiers. The
regular cp314 wheels do build and pass CI, and the classifier list stopped
at 3.13, so this closes the gap raised in #151
<#151>.
Regular CPython 3.14 wheels are unaffected and keep shipping.
If free-threading is wanted later
It is a real piece of work, not a flag: give the singleton a thread-safe
initialiser, make the ID counter atomic, move the model table and the
FireNode settings off class-wide storage, then audit FireDomain and
DataBroker for shared mutable state, and only then declare
py::mod_gil_not_used(). Worth its own issue if anyone wants it.
------------------------------
*This pull request, including its code changes and this description, was
generated by Claude Opus 5.*
------------------------------
You can view, comment on, or merge this pull request online at:
#155
Commit Summary
- 5be0cfd
<5be0cfd>
fix(packaging): stop shipping free-threaded wheels, declare 3.14
File Changes
(1 file <https://github.com/forefireAPI/forefire/pull/155/files>)
- *M* pyproject.toml
<https://github.com/forefireAPI/forefire/pull/155/files#diff-50c86b7ed8ac2cf95bd48334961bf0530cdc77b5a56f852c5c61b89d735fd711>
(9)
Patch Links:
- https://github.com/forefireAPI/forefire/pull/155.patch
- https://github.com/forefireAPI/forefire/pull/155.diff
—
Reply to this email directly, view it on GitHub
<#155?email_source=notifications&email_token=AAUZ7CXADVCL5BAZKN55SHD5JMCXDA5CNFSNUABEM5UWIORPF5TWS5BNNB2WEL2QOVWGYUTFOF2WK43UF42DENJSHEZDIMJYGSTHEZLBONXW5KTTOVRHGY3SNFRGKZFFMV3GK3TUVRTG633UMVZF6Y3MNFRWW>,
or unsubscribe
<https://github.com/notifications/unsubscribe-auth/AAUZ7CVLJE3NVMSHDQ26MRD5JMCXDAVCNFSNUABEKJSXA33TNF2G64TZHMYTOMRUHE3TKMJ3JFZXG5LFHM2TCMJZHA3TSNZRHGQXMAQ>
.
You are receiving this because you are subscribed to this thread.Message
ID: ***@***.***>
|
HugoFara
commented
Aug 11, 2026
Thanks for the explanation @filippi I am digging into this rabbit hole, as I am trying to unlock free-threaded processes, but there is more changes than expected. For now the small workaround of this PR is a clean way to fix a working Python version, before I touch the core engine and risk regressions. |
HugoFara
commented
Aug 11, 2026
Update: my free-threading branch fixes the issue but its a big change. I had to move It works end-to-end, but I had to change 35 files. Let me know if you prefer to merge this PR, or if you prefer to close this one and I open a new PR for the new feature. |
filippi
commented
Aug 12, 2026
via email
Hi
With such changes it is highly likelt that it broke the weather FORTRAN and
MPI bindings. This cannot be merged withiut further test i cabbot do right
now.. sorry
Python bindings works if therevis only one new ForeFire per python
process.. the singleton.. can't this be seen just as a limitation ?
********************************************
Jean-Baptiste Filippi
Chargé de Recherches
SPE - UMR 6134 CNRS
Université de Corse
Quartier grossetti
BP 52, 20250 Corte
Tel. +33 495 450 158
******************************************
Le mer. 12 août 2026, 03:02, Hugo ***@***.***> a écrit : … *HugoFara* left a comment (forefireAPI/forefire#155)
<#155 (comment)>
Update: my free-threading branch
<https://github.com/HugoFara/forefire/tree/feat/free-threading> fixes the
issue but its a big change. I had to move Command, SimulationParameters,
FireDomain, etc...
It works end-to-end, but I had to change 35 files. Let me know if you
prefer to merge this PR, or if you prefer to close this one and I open a
new PR for the new feature.
—
Reply to this email directly, view it on GitHub
<#155?email_source=notifications&email_token=AAUZ7CTMI7VUIXNY2MIXP7D5JN3TTA5CNFSNUABFM5UWIORPF5TWS5BNNB2WEL2JONZXKZKDN5WW2ZLOOQXTKMRVHAYTSNRWHEZ2M4TFMFZW63VHNVSW45DJN5XKKZLWMVXHJLDGN5XXIZLSL5RWY2LDNM#issuecomment-5258196693>,
or unsubscribe
<https://github.com/notifications/unsubscribe-auth/AAUZ7CT5JCQJQXDGF77C6N35JN3TTAVCNFSNUABEKJSXA33TNF2G64TZHMYTOMRUHE3TKMJ3JFZXG5LFHM2TCMJZHA3TSNZRHGQXMAQ>
.
You are receiving this because you were mentioned.Message ID:
***@***.***>
|
HugoFara
commented
Aug 12, 2026
Hi @filippi To clarify, this PR is the 1-line change that prevents building a wheel on Python 3.14. It is a temporary solution to avoid falsely advertising that CPython 3.14 does not work. It is safe to merge, as far as I can tell. The refactor I am referring to is the proper adaptation of the codebase, with risk of regressions. I am currently setting up Méso-NH and testing the binding, and I would submit a PR only if I can make sure everything works. I only want to count how much change the codebase would need for adaptation. If you are okay with the idea, I also want to set up unit tests, so that we make sure the interface of ForeFire stays the same, before core changes. That would be an independent PR. |
filippi
commented
Aug 12, 2026
via email
Hi ! Yes !
Ok forcthe 1 liner great
That would be cool
There are already some tests for coupled simulations in the test folder,
see instructions
I haven't ported to mesonh 5.7 or 6.. only 5.6 i think,
If there are a generic packaged way to deliver coupled forecast in open
source, this will take over any codes available... so please
Sorry.. just in holyday
********************************************
Jean-Baptiste Filippi
Chargé de Recherches
SPE - UMR 6134 CNRS
Université de Corse
Quartier grossetti
BP 52, 20250 Corte
Tel. +33 495 450 158
******************************************
Le mer. 12 août 2026, 17:08, Hugo ***@***.***> a écrit : … *HugoFara* left a comment (forefireAPI/forefire#155)
<#155 (comment)>
Hi @filippi <https://github.com/filippi>
To clarify, this PR is the 1-line change that prevents building a wheel on
Python 3.14. It is a temporary solution to avoid falsely advertising that
CPython 3.14 does not work. It is safe to merge, as far as I can tell.
The refactor I am referring to is the proper adaptation of the codebase,
with risk of regressions. I am currently setting up Méso-NH and testing the
binding, and I would submit a PR only if I can make sure everything works.
I only want to count how much change the codebase would need for adaptation.
If you are okay with the idea, I also want to set up unit tests, so that
we make sure the interface of ForeFire stays the same, before core changes.
That would be an independent PR.
—
Reply to this email directly, view it on GitHub
<#155?email_source=notifications&email_token=AAUZ7CT7MDXBTYAQHNIYSDD5JQ6Z5A5CNFSNUABFM5UWIORPF5TWS5BNNB2WEL2JONZXKZKDN5WW2ZLOOQXTKMRWGUZDSMBTGIZKM4TFMFZW63VHNVSW45DJN5XKKZLWMVXHJLDGN5XXIZLSL5RWY2LDNM#issuecomment-5265290322>,
or unsubscribe
<https://github.com/notifications/unsubscribe-auth/AAUZ7CRKWNSVIP26RX5S3QD5JQ6Z5AVCNFSNUABEKJSXA33TNF2G64TZHMYTOMRUHE3TKMJ3JFZXG5LFHM2TCMJZHA3TSNZRHGQXMAQ>
.
You are receiving this because you were mentioned.Message ID:
***@***.***>
|
HugoFara
commented
Aug 12, 2026
Thanks for the quick answer, especially during your holidays. @antonio-leblanc available to do the merge? |
Uh oh!
There was an error while loading. Please reload this page.
The repository has seven tags and six GitHub releases, and no file that tells a user what changed between them. `pip install forefire` makes that worse: someone pinning a version has the release notes on GitHub and nothing in the tree. CHANGELOG.md reconstructs every release from the release notes and the commit history. Claims that could be checked were checked against the tags: listenHTTP and RothermelAndrews2018 are absent at v1.2 and present at v2.0, the geojson dump mode is absent at v1.1.10. [Unreleased] lists only what is on this branch, #154 and #155. The dev branch carries a longer list in its own copy, which supersedes this one when dev is merged. CONTRIBUTING.md now asks for an entry, so the file stays current instead of being reconstructed again in a year. Its link to a testing page pointed at a Read the Docs URL that has never existed; it points at TESTING.md, which nothing in the repository linked to.
The repository has seven tags and six GitHub releases, and no file that tells a user what changed between them. `pip install forefire` makes that worse: someone pinning a version has the release notes on GitHub and nothing in the tree. CHANGELOG.md reconstructs every release from the release notes and the commit history. Claims that could be checked were checked against the tags: listenHTTP and RothermelAndrews2018 are absent at v1.2 and present at v2.0, the geojson dump mode is absent at v1.1.10. [Unreleased] lists only what is on this branch, #154 and #155. The dev branch carries a longer list in its own copy, which supersedes this one when dev is merged. CONTRIBUTING.md now asks for an entry, so the file stays current instead of being reconstructed again in a year. Its link to a testing page pointed at a Read the Docs URL that has never existed; it points at TESTING.md, which nothing in the repository linked to. (cherry picked from commit cc7e1789c66432aec56673993c3b6e198e0525a0)
The CHANGELOG landed on master carries only #154 and #155 under [Unreleased], because that is all master has. This adds the ten pull requests merged into dev since: the unit suite, the moisture invariants, the sanitizer job, the HTTP characterisation tests, the threading reproduction, and the shared-state and double-free fixes. Two things went stale on dev while that work landed, both of them ours. The README's CMake option table stopped at six options; #156 and #180 added FOREFIRE_BUILD_TESTS, FOREFIRE_ENABLE_WARNINGS, FOREFIRE_WARNINGS_AS_ERRORS and FOREFIRE_SANITIZE. And CONTRIBUTING told contributors to run `cd tests && bash run.bash`, which does not reach the C++ unit tests at all; ctest does.
v2.5.0 + CPython 3.14 shipped free-threaded wheels. It should not have, and this stops it until the architecture is changed.
cibuildwheel built
cp314tbecause nothing inskipexcluded it. My oversight in #151: I assumed free-threaded builds were opt-in.Why that is a problem
A free-threaded wheel tells users the extension is safe without the GIL.
_pyforefire.cppuses a plainPYBIND11_MODULEwith nopy::mod_gil_not_used(), so CPython re-enables the GIL when it is imported. The wheel advertises free-threading and then silently switches it off. Users get a slower interpreter and a promise that was never kept.The core could not honour that promise regardless. Searching
src/forstd::mutex,std::atomic,lock_guard,pthread_mutexor OpenMP critical sections returns zero matches across roughly 33,000 lines. Concretely:SimulationParameters::instanceSimulationParameters.cpp:28if (instance == 0) instance = new SimulationParameters;Two threads can both allocate, then diverge with different parameter objects.ForeFireAtom::instanceNRCountForeFireAtom.h:106instanceNRCount++, non-atomic. Concurrent construction races and can duplicate IDs.FireDomain::propModelsTableFireDomain.cpp:58,697,859FireNode::nmlScheme,smoothing,relax,minSpeed,minFrontDepthFireNode.cpp:22-30None of this is a bug today. The binding never calls
gil_scoped_release, so the GIL serialises every entry point, and ForeFire is a single-simulation-per-process design. The GIL is exactly what makes it safe, which is why a wheel built to run without one is the wrong thing to publish.Changes
cp314t-*added to[tool.cibuildwheel] skip, with a comment recording why, so it is not removed casually.Programming Language :: Python :: 3.14added to the classifiers. The regular cp314 wheels do build and pass CI, and the classifier list stopped at 3.13, so this closes the gap raised in Add pip-installable wheels for Linux and macOS #151.Regular CPython 3.14 wheels are unaffected and keep shipping.
If free-threading is wanted later
It is a real piece of work, not a flag: give the singleton a thread-safe initialiser, make the ID counter atomic, move the model table and the FireNode settings off class-wide storage, then audit
FireDomainandDataBrokerfor shared mutable state, and only then declarepy::mod_gil_not_used(). Worth its own issue if anyone wants it.This pull request, including its code changes and this description, was generated by Claude Opus 5.