summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAvi Halachmi (:avih) <avihpit@yahoo.com>2021-06-22 15:18:19 +0300
committeravih <avih@users.noreply.github.com>2021-06-23 23:47:08 +0300
commitf73814b180ad4616ac1d21a729eb9dda4af040cc (patch)
treeca4eadfc605d460e46eac22185274a41e494ccd6
parent11423acf3048445620bf1e8987b3f7aa04887cf0 (diff)
downloadmpv-f73814b180ad4616ac1d21a729eb9dda4af040cc.tar.bz2
mpv-f73814b180ad4616ac1d21a729eb9dda4af040cc.tar.xz
lua: timers: don't block forever with slow callbacks
Previously, process_timers() kept going as long as there were due timers, which could be for extended periods of time or even forever if there were slow timer callbacks with either periodic timers or if timers were added repeatedly. This prevented dequeuing mpv events, and subsequently, among others, prevented mpv from quitting until process_timers() completed. For instance, this caused process_timers() to never return: function render() <longer than 1/60 s on a slow system> end mp.add_periodic_timer(1/60, render) Similarly, it never returned if a timer callback always added a new one-shot which was already due by the time the callback completed. This commit ensures that process_timers() only executes callbacks which were due when it started, so that timers which are added (or repeated) during process_timers() will wait for the next iteration - after mpv events are dequeued. This has no performance impact under normal conditions (when callbacks complete before the next timer is due). Additionally, previously idle-observers were executed unconditionally after the timers because indeed there was nothing due when (if...) process_timers() completed. However, now process_timers() can return even if there are due timers, so skip idle-observers on such case.
-rw-r--r--player/lua/defaults.lua15
1 files changed, 13 insertions, 2 deletions
diff --git a/player/lua/defaults.lua b/player/lua/defaults.lua
index 0fe90977e6..5e56c4fb4e 100644
--- a/player/lua/defaults.lua
+++ b/player/lua/defaults.lua
@@ -333,6 +333,7 @@ end
-- Run timers that have met their deadline.
-- Return: next absolute time a timer expires as number, or nil if no timers
local function process_timers()
+ local t0 = nil
while true do
local timer = get_next_timer()
if not timer then
@@ -343,6 +344,14 @@ local function process_timers()
if wait > 0 then
return wait
else
+ if not t0 then
+ t0 = now -- first due callback: always executes, remember t0
+ elseif timer.next_deadline > t0 then
+ -- don't block forever with slow callbacks and endless timers.
+ -- we'll continue right after checking mpv events.
+ return 0
+ end
+
if timer.oneshot then
timer:kill()
else
@@ -518,8 +527,10 @@ function mp.dispatch_events(allow_wait)
local wait = 0
if not more_events then
wait = process_timers() or 1e20 -- infinity for all practical purposes
- for _, handler in ipairs(idle_handlers) do
- handler()
+ if wait ~= 0 then
+ for _, handler in ipairs(idle_handlers) do
+ handler()
+ end
end
-- Resume playloop - important especially if an error happened while
-- suspended, and the error was handled, but no resume was done.