mirror of
https://github.com/koreader/koreader.git
synced 2025-08-10 00:52:38 +00:00
Make UIManager track prevent/allowStandby state. (#6558)
Conversely, Trapper and plugins report standby interruptibility.
This commit is contained in:
@@ -306,6 +306,11 @@ function Device:info()
|
||||
return self.model
|
||||
end
|
||||
|
||||
-- Hardware specific method for UI to signal allowed/disallowed standby.
|
||||
-- The device is allowed to enter standby only from within waitForEvents,
|
||||
-- and only if allowed state is true at the time of waitForEvents() invocation.
|
||||
function Device:setAutoStandby(isAllowed) end
|
||||
|
||||
-- Hardware specific method to handle usb plug in event
|
||||
function Device:usbPlugIn() end
|
||||
|
||||
|
||||
@@ -43,8 +43,10 @@ function Trapper:wrap(func)
|
||||
-- Catch and log any error happening in func (an error happening
|
||||
-- in a coroutine just aborts silently the coroutine)
|
||||
local pcalled_func = function()
|
||||
UIManager:preventStandby()
|
||||
-- we use xpcall as it can give a whole stacktrace, unlike pcall
|
||||
local ok, err = xpcall(func, debug.traceback)
|
||||
UIManager:allowStandby()
|
||||
if not ok then
|
||||
logger.warn("error in wrapped function:", err)
|
||||
return false
|
||||
|
||||
@@ -37,6 +37,8 @@ local UIManager = {
|
||||
_refresh_func_stack = {},
|
||||
_entered_poweroff_stage = false,
|
||||
_exit_code = nil,
|
||||
_prevent_standby_count = 0,
|
||||
_prev_prevent_standby_count = 0,
|
||||
|
||||
event_hook = require("ui/hook_container"):new()
|
||||
}
|
||||
@@ -80,12 +82,11 @@ function UIManager:init()
|
||||
end)
|
||||
end
|
||||
if Device:isPocketBook() then
|
||||
-- Only fg/bg state plugin notifiers, not real power event.
|
||||
self.event_handlers["Suspend"] = function()
|
||||
self:_beforeSuspend()
|
||||
Device:onPowerEvent("Power")
|
||||
end
|
||||
self.event_handlers["Resume"] = function()
|
||||
Device:onPowerEvent("Power")
|
||||
self:_afterResume()
|
||||
end
|
||||
end
|
||||
@@ -1198,6 +1199,11 @@ function UIManager:handleInput()
|
||||
wait_us = math.min(wait_us or math.huge, self.ZMQ_TIMEOUT)
|
||||
end
|
||||
|
||||
-- If allowed, entering standby (from which we can wake by input) must trigger in response to event
|
||||
-- this function emits (plugin), or within waitEvent() right after (hardware).
|
||||
-- Anywhere else breaks preventStandby/allowStandby invariants used by background jobs while UI is left running.
|
||||
self:_standbyTransition()
|
||||
|
||||
-- wait for next event
|
||||
local input_event = Input:waitEvent(wait_us)
|
||||
|
||||
@@ -1301,6 +1307,35 @@ function UIManager:resume()
|
||||
end
|
||||
end
|
||||
|
||||
-- Release standby lock once. We're done with whatever we were doing in the background.
|
||||
-- Standby is re-enabled only after all issued prevents are paired with allowStandby for each one.
|
||||
function UIManager:allowStandby()
|
||||
assert(self._prevent_standby_count > 0, "allowing standby that isn't prevented; you have an allow/prevent mismatch somewhere")
|
||||
self._prevent_standby_count = self._prevent_standby_count - 1
|
||||
end
|
||||
|
||||
-- Prevent standby, ie something is happening in background, yet UI may tick.
|
||||
function UIManager:preventStandby()
|
||||
self._prevent_standby_count = self._prevent_standby_count + 1
|
||||
end
|
||||
|
||||
-- Allow/prevent calls above can interminently allow standbys, but we're not interested until
|
||||
-- the state change crosses UI tick boundary, which is what self._prev_prevent_standby_count is tracking.
|
||||
function UIManager:_standbyTransition()
|
||||
if self._prevent_standby_count == 0 and self._prev_prevent_standby_count > 0 then
|
||||
-- edge prevent->allow
|
||||
logger.dbg("allow standby")
|
||||
Device:setAutoStandby(true)
|
||||
self:broadcastEvent(Event:new("AllowStandby"))
|
||||
elseif self._prevent_standby_count > 0 and self._prev_prevent_standby_count == 0 then
|
||||
-- edge allow->prevent
|
||||
logger.dbg("prevent standby")
|
||||
Device:setAutoStandby(false)
|
||||
self:broadcastEvent(Event:new("PreventStandby"))
|
||||
end
|
||||
self._prev_prevent_standby_count = self._prevent_standby_count
|
||||
end
|
||||
|
||||
function UIManager:flushSettings()
|
||||
self:broadcastEvent(Event:new("FlushSettings"))
|
||||
end
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
local logger = require("logger")
|
||||
local UIManager = require("ui/uimanager")
|
||||
|
||||
local CommandRunner = {
|
||||
pio = nil,
|
||||
@@ -41,6 +42,7 @@ function CommandRunner:start(job)
|
||||
"sh plugins/backgroundrunner.koplugin/luawrapper.sh " ..
|
||||
"\"" .. self.job.executable .. "\""
|
||||
logger.dbg("CommandRunner: Will execute command " .. command)
|
||||
UIManager:preventStandby()
|
||||
self.pio = io.popen(command)
|
||||
end
|
||||
|
||||
@@ -71,6 +73,7 @@ function CommandRunner:poll()
|
||||
self.job.result = 222
|
||||
end
|
||||
end
|
||||
UIManager:allowStandby()
|
||||
self.pio:close()
|
||||
self.pio = nil
|
||||
self.job.end_sec = os.time()
|
||||
|
||||
@@ -544,6 +544,8 @@ function BookInfoManager:collectSubprocesses()
|
||||
local pid = self.subprocesses_pids[i]
|
||||
if util.isSubProcessDone(pid) then
|
||||
table.remove(self.subprocesses_pids, i)
|
||||
-- Prevent has been issued for each bg task spawn, we must allow for each death too.
|
||||
UIManager:allowStandby()
|
||||
else
|
||||
i = i + 1
|
||||
end
|
||||
@@ -621,6 +623,9 @@ function BookInfoManager:extractInBackground(files)
|
||||
logger.warn("Failed lauching background extraction sub-process (fork failed)")
|
||||
return false -- let caller know it failed
|
||||
end
|
||||
-- No straight control flow exists for background task completion here, so we bump prevent
|
||||
-- counter on each task, and undo that inside collectSubprocesses() zombie reaper.
|
||||
UIManager:preventStandby()
|
||||
table.insert(self.subprocesses_pids, task_pid)
|
||||
self.subprocesses_last_added_ts = util.gettime()
|
||||
|
||||
|
||||
Reference in New Issue
Block a user