From 26f741b19be4a9b0d50df4b2e516560c8224a371 Mon Sep 17 00:00:00 2001 From: Kim Alvefur Date: Wed, 8 Jul 2020 20:11:49 +0200 Subject: net.cqueues: Switch to server.watchfd for main loop integration Why? Just look at all that code deleted! watchfd is the prefered way to poll things that expose FDs for this purpose, altho it was added after net.cqueues. --- net/cqueues.lua | 48 ++---------------------------------------------- 1 file changed, 2 insertions(+), 46 deletions(-) (limited to 'net/cqueues.lua') diff --git a/net/cqueues.lua b/net/cqueues.lua index 8c4c756f..84d59f15 100644 --- a/net/cqueues.lua +++ b/net/cqueues.lua @@ -16,55 +16,11 @@ local cq; if server.cq then -- server provides cqueues object cq = server.cq; -elseif server.get_backend() == "select" and server._addtimer then -- server_select +elseif server.watchfd then cq = cqueues.new(); - local function step() + server.watchfd(cq:pollfd(), function () assert(cq:loop(0)); - end - - -- Use wrapclient (as wrapconnection isn't exported) to get server_select to watch cq fd - local handler = server.wrapclient({ - getfd = function() return cq:pollfd(); end; - settimeout = function() end; -- Method just needs to exist - close = function() end; -- Need close method for 'closeall' - }, nil, nil, {}); - - -- Only need to listen for readable; cqueues handles everything under the hood - -- readbuffer is called when `select` notes an fd as readable - handler.readbuffer = step; - - -- Use server_select low lever timer facility, - -- this callback gets called *every* time there is a timeout in the main loop - server._addtimer(function(current_time) - -- This may end up in extra step()'s, but cqueues handles it for us. - step(); - return cq:timeout(); end); -elseif server.event and server.base then -- server_event - cq = cqueues.new(); - -- Only need to listen for readable; cqueues handles everything under the hood - local EV_READ = server.event.EV_READ; - -- Convert a cqueues timeout to an acceptable timeout for luaevent - local function luaevent_safe_timeout(cq) - local t = cq:timeout(); - -- if you give luaevent 0 or nil, it re-uses the previous timeout. - if t == 0 then - t = 0.000001; -- 1 microsecond is the smallest that works (goes into a `struct timeval`) - elseif t == nil then -- pick something big if we don't have one - t = 0x7FFFFFFF; -- largest 32bit int - end - return t - end - local event_handle; - event_handle = server.base:addevent(cq:pollfd(), EV_READ, function(e) - -- Need to reference event_handle or this callback will get collected - -- This creates a circular reference that can only be broken if event_handle is manually :close()'d - local _ = event_handle; - -- Run as many cqueues things as possible (with a timeout of 0) - -- If an error is thrown, it will break the libevent loop; but prosody resumes after logging a top level error - assert(cq:loop(0)); - return EV_READ, luaevent_safe_timeout(cq); - end, luaevent_safe_timeout(cq)); else error "NYI" end -- cgit v1.2.3 From f2ae89296c1f2c4a2b20d259d40ab3fe14b4a87d Mon Sep 17 00:00:00 2001 From: Kim Alvefur Date: Wed, 8 Jul 2020 22:01:19 +0200 Subject: net.cqueues: Fix resuming after timeouts net.cqueues previously relied on timers instead of fd events sometimes. Under net.server_select, it would have called cq:loop() on every iteration of the main loop, which was probably not optimal. --- net/cqueues.lua | 14 ++++++++++++++ 1 file changed, 14 insertions(+) (limited to 'net/cqueues.lua') diff --git a/net/cqueues.lua b/net/cqueues.lua index 84d59f15..65d2a019 100644 --- a/net/cqueues.lua +++ b/net/cqueues.lua @@ -9,6 +9,7 @@ local server = require "net.server"; local cqueues = require "cqueues"; +local timer = require "util.timer"; assert(cqueues.VERSION >= 20150113, "cqueues newer than 20150113 required") -- Create a single top level cqueue @@ -18,8 +19,21 @@ if server.cq then -- server provides cqueues object cq = server.cq; elseif server.watchfd then cq = cqueues.new(); + local timeout = timer.add_task(cq:timeout() or 0, function () + -- FIXME It should be enough to reschedule this timeout instead of replacing it, but this does not work. See https://issues.prosody.im/1572 + assert(cq:loop(0)); + return cq:timeout(); + end); server.watchfd(cq:pollfd(), function () assert(cq:loop(0)); + local t = cq:timeout(); + if t then + timer.stop(timeout); + timeout = timer.add_task(cq:timeout(), function () + assert(cq:loop(0)); + return cq:timeout(); + end); + end end); else error "NYI" -- cgit v1.2.3