ngui: clarify and handle concurrency during screen sleep/standby
ci/woodpecker/pr/woodpecker Pipeline was successful Details
ci/woodpecker/push/woodpecker Pipeline was successful Details

the screen.sleep fn was actually called in concurrent-unsafe mode,
i.e without acquiring UI mutex. in conjuction with commThreadLoopCycle
this would have eventually led to LVGL primitives concurrent access.

so, screen.sleep now takes UI mutex to hold during LVGL calls.
a bit ugly but certainly better than relying on luck.
alex 1 year ago
parent 1d8d869629
commit 7fc04cb5ec
Signed by: x1ddos
GPG Key ID: FDEFB4A63CBD8460

@ -220,7 +220,6 @@ fn uiThreadLoop() void {
comm.write(gpa, stdout, comm.Message.standby) catch |err| { comm.write(gpa, stdout, comm.Message.standby) catch |err| {
logger.err("comm.write standby: {any}", .{err}); logger.err("comm.write standby: {any}", .{err});
}; };
// MUTEX???????????????????????????????????
screen.sleep(&ui_mutex, &wakeup); // blocking screen.sleep(&ui_mutex, &wakeup); // blocking
// wake up due to touch screen activity or wakeup event is set // wake up due to touch screen activity or wakeup event is set

@ -13,18 +13,21 @@ const logger = std.log.scoped(.screen);
/// a touch screen activity or wake event is triggered. /// a touch screen activity or wake event is triggered.
/// sleep removes all input devices at enter and reinstates them at exit so that /// sleep removes all input devices at enter and reinstates them at exit so that
/// a touch event triggers no accidental action. /// a touch event triggers no accidental action.
pub fn sleep(mu: *std.Thread.Mutex, wake: *const Thread.ResetEvent) void { ///
/// the UI mutex is held while calling LVGL UI functions, and released during
/// idling or waiting for wake event.
/// although sleep is safe for concurrent use, the input drivers init/deinit
/// implementation used on entry and exit might not be.
pub fn sleep(ui: *std.Thread.Mutex, wake: *const Thread.ResetEvent) void {
ui.lock();
drv.deinitInput(); drv.deinitInput();
mu.lock();
widget.topdrop(.show); widget.topdrop(.show);
mu.unlock(); ui.unlock();
defer { defer {
ui.lock();
defer ui.unlock();
drv.initInput() catch |err| logger.err("drv.initInput: {any}", .{err}); drv.initInput() catch |err| logger.err("drv.initInput: {any}", .{err});
mu.lock();
widget.topdrop(.remove); widget.topdrop(.remove);
mu.unlock();
} }
const watcher = drv.InputWatcher() catch |err| { const watcher = drv.InputWatcher() catch |err| {