mirror of
https://github.com/koreader/koreader.git
synced 2025-08-10 00:52:38 +00:00
Fix a nasty race condition when trying to unschedule a tickAfterNext
task *before* the task actually makes it to the task queue (Because that only happens on the next UI frame, in the current frame, what's in the task queue is the anonymous wrapper function that passes action to nextTick).
This commit is contained in:
@@ -630,6 +630,9 @@ Useful to run UI callbacks ASAP without skipping repaints.
|
||||
|
||||
@func action reference to the task to be scheduled (may be anonymous)
|
||||
@param ... optional arguments passed to action
|
||||
|
||||
@return A reference to the initial nextTick wrapper function,
|
||||
necessary if the caller wants to unschedule action *before* it actually gets inserted in the task queue by nextTick.
|
||||
@see nextTick
|
||||
]]
|
||||
function UIManager:tickAfterNext(action, ...)
|
||||
@@ -637,7 +640,14 @@ function UIManager:tickAfterNext(action, ...)
|
||||
-- c.f., http://lua-users.org/wiki/VarargTheSecondClassCitizen
|
||||
local n = select('#', ...)
|
||||
local va = {...}
|
||||
return self:nextTick(function() self:nextTick(action, unpack(va, 1, n)) end)
|
||||
-- We need to keep a reference to this anonymous function, as it is *NOT* quite `action`,
|
||||
-- and the caller might want to unschedule it early...
|
||||
local delayed_action = function()
|
||||
self:nextTick(action, unpack(va, 1, n))
|
||||
end
|
||||
self:nextTick(delayed_action)
|
||||
|
||||
return delayed_action
|
||||
end
|
||||
--[[
|
||||
-- NOTE: This appears to work *nearly* just as well, but does sometimes go too fast (might depend on kernel HZ & NO_HZ settings?)
|
||||
|
||||
@@ -37,6 +37,7 @@ local AutoSuspend = WidgetContainer:new{
|
||||
task = nil,
|
||||
standby_task = nil,
|
||||
leave_standby_task = nil,
|
||||
wrapped_leave_standby_task = nil,
|
||||
going_to_suspend = nil,
|
||||
}
|
||||
|
||||
@@ -184,6 +185,7 @@ function AutoSuspend:onCloseWidget()
|
||||
|
||||
self:_unschedule_standby()
|
||||
self.standby_task = nil
|
||||
self.wrapped_leave_standby_task = nil
|
||||
self.leave_standby_task = nil
|
||||
end
|
||||
|
||||
@@ -203,7 +205,13 @@ function AutoSuspend:_unschedule_standby()
|
||||
end
|
||||
|
||||
-- Make sure we don't trigger a ghost LeaveStandby event...
|
||||
if self.wrapped_leave_standby_task then
|
||||
logger.dbg("AutoSuspend: unschedule leave standby task wrapper")
|
||||
UIManager:unschedule(self.wrapped_leave_standby_task)
|
||||
end
|
||||
|
||||
if self.leave_standby_task then
|
||||
logger.dbg("AutoSuspend: unschedule leave standby task")
|
||||
UIManager:unschedule(self.leave_standby_task)
|
||||
end
|
||||
end
|
||||
@@ -330,6 +338,8 @@ end
|
||||
|
||||
function AutoSuspend:onLeaveStandby()
|
||||
logger.dbg("AutoSuspend: onLeaveStandby")
|
||||
-- If the Event got through, tickAfterNext did its thing, clear the reference to the initial nextTick wrapper...
|
||||
self.wrapped_leave_standby_task = nil
|
||||
-- Unschedule suspend and shutdown, as the realtime clock has ticked
|
||||
self:_unschedule()
|
||||
-- Reschedule suspend and shutdown (we'll recompute the delay based on the last user input, *not* the current time).
|
||||
@@ -594,7 +604,7 @@ function AutoSuspend:AllowStandbyHandler()
|
||||
-- (in case we were woken up by user input, as opposed to an rtc wake alarm)!
|
||||
-- (This ensures we'll use an up to date last_action_time, and that it only ever gets updated from *user* input).
|
||||
-- NOTE: UIManager consumes scheduled tasks before input events, which is why we can't use nextTick.
|
||||
UIManager:tickAfterNext(self.leave_standby_task)
|
||||
self.wrapped_leave_standby_task = UIManager:tickAfterNext(self.leave_standby_task)
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
Reference in New Issue
Block a user