Skip to content

CPython: declare the module GIL-free on free-threaded builds - #36

Merged
bdbarnett merged 1 commit into
mainfrom
ostinato/gil-free
Oct 15, 2026
Merged

bdbarnett merged 1 commit into
mainfrom
ostinato/gil-free

Conversation

@bdbarnett

Copy link
Copy Markdown
Contributor

On a free-threaded Python (3.13t and later), importing an extension that doesn't declare itself GIL-free turns the GIL back on for the whole process, with a RuntimeWarning. lvgl did, so a program on 3.15t lost its parallel threads the moment it imported lvgl.

PyInit_lvgl now calls PyUnstable_Module_SetGIL(m, Py_MOD_GIL_NOT_USED) right after PyModule_Create (binding/emit_cpython_glue.py), guarded by Py_GIL_DISABLED so every other build compiles the same source unchanged.

The rule that makes this safe: LVGL isn't thread-safe, and the CPython runtime keeps unlocked shared state of its own (static scratch structs for struct conversion, the callback-dict registry and the pending-release array, both grown with realloc, and an LVGL lock released while Python callbacks run). So every lvgl call, and every lvgl object's release, has to happen on one thread. Other threads can run any Python that doesn't touch lvgl, in parallel. lvgl-python documents this for users and tests it on 3.15t: frames drawn on one thread while other threads run Python match frames drawn alone.

generated/lvgl_python.c is regenerated (6 lines). tests/test_cpython_gil_declaration.py checks the declaration in the generated module init; it fails with the guard planted wrong (since undone), and the generator suite passes (107 tests).

Releasing it needs nothing new: lvgl-python's usual sync to this commit carries the declaration, and its cp315t wheels pick it up.

PyInit_lvgl calls PyUnstable_Module_SetGIL(m, Py_MOD_GIL_NOT_USED) after
PyModule_Create, guarded by Py_GIL_DISABLED, so importing lvgl on 3.13t
and later no longer turns the GIL back on. LVGL isn't thread-safe: this
holds because every lvgl call, and every lvgl object's release, happens
on one thread.
@bdbarnett
bdbarnett merged commit 22f8383 into main Oct 15, 2026
4 checks passed
@bdbarnett
bdbarnett deleted the ostinato/gil-free branch October 15, 2026 21:49
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Development

Successfully merging this pull request may close these issues.

1 participant