Skip to content
This repository was archived by the owner on Oct 30, 2026. It is now read-only.

CPython: a struct is the holder of its callback dict; timers and animations release it - #34

Merged
bdbarnett merged 2 commits into
mainfrom
fix-struct-cb
Oct 12, 2026
Merged

bdbarnett merged 2 commits into
mainfrom
fix-struct-cb

Conversation

@bdbarnett

Copy link
Copy Markdown
Contributor

Generated half of the fix for lvgl-python#31: on CPython a callback set on an animation or a timer was never freed. The runtime half is merged (lvgl-python#32); the sync that follows this brings the test.

  • Struct callback setters pass the struct as containing_struct, so the runtime gives every callback set on one struct a single shared reference instead of one per call.
  • lv_timer_create and lv_timer_set_cb call lvpy_timer_bind; lv_anim_start calls lvpy_anim_bind. They attach LVGL's ext_data free_cb to the timer or to the running copy of the animation, and LVGL calls it on every path that frees them (completion, delete, repeat count, deinit).
  • lv_conf.h enables LV_USE_EXT_DATA for the CPython build only. The generator's PYCPARSER pass does not see it, so api.json, the stub and the MicroPython and CircuitPython outputs are unchanged; those two allocate LVGL memory on the GC heap and reclaim the dict by reachability.

Regenerated with --target cpython; only generated/lvgl_python.c moved (the struct setters' containing_struct argument and the three hook calls). Generator tests: 104 passed. Built into lvgl-python locally with the merged runtime: the new lifetime test passes 9/9 (all 9 fail on 9.5.50; a variant where the running animation copy takes no reference segfaults under MALLOC_PERTURB_), and 50 animation plus 50 timer cycles with 20 KB per callback grow the heap by under 64 KB instead of 3 MB.

…ations release it

On CPython a callback set on an animation or a timer was never freed
(lvgl-python#31): the dict holding it lives in the struct's user_data,
and nothing released it when the animation completed or the timer was
deleted. The runtime half is lvgl-python#32; this is the generated half.

- Struct callback setters pass the struct as containing_struct, so the
  runtime gives every callback set on one struct a single shared
  reference instead of one per call.
- lv_timer_create and lv_timer_set_cb call lvpy_timer_bind, and
  lv_anim_start calls lvpy_anim_bind, which attach LVGL's ext_data
  free_cb to the timer or the running copy of the animation; LVGL calls
  it on every path that frees them.
- lv_conf.h enables LV_USE_EXT_DATA for the CPython build only. The
  generator's PYCPARSER pass does not see it, so the API model, stub
  and the other two targets are unchanged; MicroPython and
  CircuitPython allocate LVGL memory on the GC heap and reclaim the
  dict by reachability.

Regenerated with --target cpython; only generated/lvgl_python.c moved.
…runtime half (lvgl-python#32)

The integration job pins the lvgl-python commit it syncs into. The
generated code now calls lvpy_timer_bind and lvpy_anim_bind, which that
runtime provides; the old pin failed to import the extension.
@bdbarnett
bdbarnett merged commit 2137b6c into main Oct 12, 2026
4 checks passed
@bdbarnett
bdbarnett deleted the fix-struct-cb branch October 12, 2026 07:21
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

None yet

Development

Successfully merging this pull request may close these issues.

1 participant