Checklist
How often does this bug occurs?
often
Expected behavior
Stopping or replacing a running LVGL application (e.g., switching from one LVGL game to another) should cleanly tear down the current LVGL runtime and start the new one, without crashing.
Actual behavior (suspected bug)
When lua_lvgl_deinit_runtime() is called while an LVGL app is actively rendering, the device panics and reboots with a FreeRTOS assertion failure:
assert failed: vTaskPriorityDisinheritAfterTimeout tasks.c:5270 (pxTCB != pxCurrentTCBs[xPortGetCoreID()])
Root cause: in lua_lvgl_deinit_runtime() (lua_lvgl_runtime.c), lua_lvgl_quiesce_runtime() is called BEFORE lua_lvgl_stop_task(). At that point the LVGL render task (lua_lvgl_task) is still alive and also acquiring the same s_lvgl.mutex in its loop. Two tasks then contend on a priority-inheriting mutex taken with a timeout (xSemaphoreTake(s_lvgl.mutex, 1000ms) in lua_lvgl_lock), which under dual-core timing trips the kernel's priority-inheritance-disinherit assertion and panics.
I verified the latest version still has this order (quiesce before stop_task), so the issue is present on current code.
Possible fix: stop the LVGL task FIRST, then quiesce. Once the render task has exited (it releases the lock and self-deletes), the cleanup path is the sole holder of the mutex and there is no contention. Reordering to: stop tick timer -> lua_lvgl_stop_task() -> lua_lvgl_quiesce_runtime() resolves the crash. Tested locally; stopping/switching running LVGL apps repeatedly no longer crashes.
Error logs or terminal output
assert failed: vTaskPriorityDisinheritAfterTimeout tasks.c:5270 (pxTCB != pxCurrentTCBs[ xPortGetCoreID() ])
Backtrace: 0x403853dd:... 0x40389035:... 0x40385fbc:... 0x420c4f22:... 0x420c4f57:... 0x420c5011:... 0x420c50c9:...
--- 0x40389035: vTaskPriorityDisinheritAfterTimeout at FreeRTOS-Kernel/tasks.c:5270
--- 0x40385fbc: xQueueSemaphoreTake at FreeRTOS-Kernel/queue.c:1842
--- 0x420c4f22: lua_lvgl_lock at components/lua_modules/lua_module_lvgl/src/lua_lvgl_runtime.c:19
--- 0x420c4f57: lua_lvgl_quiesce_runtime at lua_lvgl_runtime.c:221
--- 0x420c5011: lua_lvgl_deinit_runtime at lua_lvgl_runtime.c:304
--- 0x420c50c9: lua_lvgl_deinit at lua_lvgl_runtime.c:519
--- 0x42112791: cap_lua_runtime_execute_file at cap_lua/src/cap_lua_runtime.c:448
--- 0x42113339: cap_lua_job_task at cap_lua/src/cap_lua_async.c:412
Rebooting...
rst:0xc (RTC_SW_CPU_RST),boot:0x8 (SPI_FAST_FLASH_BOOT)
Steps to reproduce the behavior
- Start an LVGL-based async task that renders continuously at high frequency (e.g., a game script that updates the UI every frame via lv_timer_handler).
- While the LVGL render task is actively running, trigger lua_lvgl_deinit() — e.g., stop the current LVGL job and start a new LVGL app
- The device panics and reboots within seconds.
Environment:
Hardware: ESP32-S3
ESP-IDF: v5.5.4
Component: lua_module_lvgl
Project release version
Cloned on June 18th
System architecture
ARM 32-bit (Raspberry Pi 32-bit)
Operating system
Windows
Operating system version
Windows 11
Shell
other (details in Additional context)
Additional context
Why it only triggers when stopping a running app: during normal operation only the render task uses s_lvgl.mutex (no contention). The race window opens the moment deinit is triggered while the render task is still looping — both tasks then contend on the timeout mutex for the first time.
This was discovered while using an on-device LLM agent to build LVGL games, where users frequently ask to "stop the current game and make a new one" while the previous game is still actively rendering — which consistently triggers the crash.
The fix is a small, localized reordering in lua_lvgl_deinit_runtime() (stop task before quiesce). Happy to open a PR if helpful.
Checklist
How often does this bug occurs?
often
Expected behavior
Stopping or replacing a running LVGL application (e.g., switching from one LVGL game to another) should cleanly tear down the current LVGL runtime and start the new one, without crashing.
Actual behavior (suspected bug)
When
lua_lvgl_deinit_runtime()is called while an LVGL app is actively rendering, the device panics and reboots with a FreeRTOS assertion failure:assert failed: vTaskPriorityDisinheritAfterTimeout tasks.c:5270 (pxTCB != pxCurrentTCBs[xPortGetCoreID()])
Root cause: in
lua_lvgl_deinit_runtime()(lua_lvgl_runtime.c),lua_lvgl_quiesce_runtime()is called BEFORElua_lvgl_stop_task(). At that point the LVGL render task (lua_lvgl_task) is still alive and also acquiring the sames_lvgl.mutexin its loop. Two tasks then contend on a priority-inheriting mutex taken with a timeout (xSemaphoreTake(s_lvgl.mutex, 1000ms)inlua_lvgl_lock), which under dual-core timing trips the kernel's priority-inheritance-disinherit assertion and panics.I verified the latest version still has this order (quiesce before stop_task), so the issue is present on current code.
Possible fix: stop the LVGL task FIRST, then quiesce. Once the render task has exited (it releases the lock and self-deletes), the cleanup path is the sole holder of the mutex and there is no contention. Reordering to: stop tick timer -> lua_lvgl_stop_task() -> lua_lvgl_quiesce_runtime() resolves the crash. Tested locally; stopping/switching running LVGL apps repeatedly no longer crashes.
Error logs or terminal output
Steps to reproduce the behavior
Environment:
Hardware: ESP32-S3
ESP-IDF: v5.5.4
Component: lua_module_lvgl
Project release version
Cloned on June 18th
System architecture
ARM 32-bit (Raspberry Pi 32-bit)
Operating system
Windows
Operating system version
Windows 11
Shell
other (details in Additional context)
Additional context
Why it only triggers when stopping a running app: during normal operation only the render task uses s_lvgl.mutex (no contention). The race window opens the moment deinit is triggered while the render task is still looping — both tasks then contend on the timeout mutex for the first time.
This was discovered while using an on-device LLM agent to build LVGL games, where users frequently ask to "stop the current game and make a new one" while the previous game is still actively rendering — which consistently triggers the crash.
The fix is a small, localized reordering in lua_lvgl_deinit_runtime() (stop task before quiesce). Happy to open a PR if helpful.