net/cqueues.lua
author Kim Alvefur <zash@zash.se>
Fri, 21 Sep 2018 21:19:44 +0200
changeset 9339 9e8d7d461c7d
parent 6541 f1eb66288f60
child 11000 d742095046f9
permissions -rw-r--r--
mod_http: Hook the host-less event if hooked from a global module
Ignore whitespace changes - Everywhere: Within whitespace: At end of lines:
6517
d425fc41e59f net.cqueues: Add module that allows use of cqueues while still using net.server as main loop
daurnimator <quae@daurnimator.com>
parents:
diff changeset
     1
-- Prosody IM
d425fc41e59f net.cqueues: Add module that allows use of cqueues while still using net.server as main loop
daurnimator <quae@daurnimator.com>
parents:
diff changeset
     2
-- Copyright (C) 2014 Daurnimator
d425fc41e59f net.cqueues: Add module that allows use of cqueues while still using net.server as main loop
daurnimator <quae@daurnimator.com>
parents:
diff changeset
     3
--
d425fc41e59f net.cqueues: Add module that allows use of cqueues while still using net.server as main loop
daurnimator <quae@daurnimator.com>
parents:
diff changeset
     4
-- This project is MIT/X11 licensed. Please see the
d425fc41e59f net.cqueues: Add module that allows use of cqueues while still using net.server as main loop
daurnimator <quae@daurnimator.com>
parents:
diff changeset
     5
-- COPYING file in the source package for more information.
d425fc41e59f net.cqueues: Add module that allows use of cqueues while still using net.server as main loop
daurnimator <quae@daurnimator.com>
parents:
diff changeset
     6
--
d425fc41e59f net.cqueues: Add module that allows use of cqueues while still using net.server as main loop
daurnimator <quae@daurnimator.com>
parents:
diff changeset
     7
-- This module allows you to use cqueues with a net.server mainloop
d425fc41e59f net.cqueues: Add module that allows use of cqueues while still using net.server as main loop
daurnimator <quae@daurnimator.com>
parents:
diff changeset
     8
--
d425fc41e59f net.cqueues: Add module that allows use of cqueues while still using net.server as main loop
daurnimator <quae@daurnimator.com>
parents:
diff changeset
     9
d425fc41e59f net.cqueues: Add module that allows use of cqueues while still using net.server as main loop
daurnimator <quae@daurnimator.com>
parents:
diff changeset
    10
local server = require "net.server";
d425fc41e59f net.cqueues: Add module that allows use of cqueues while still using net.server as main loop
daurnimator <quae@daurnimator.com>
parents:
diff changeset
    11
local cqueues = require "cqueues";
6541
f1eb66288f60 net.cqueues: Fix incorrect version check
daurnimator <quae@daurnimator.com>
parents: 6540
diff changeset
    12
assert(cqueues.VERSION >= 20150113, "cqueues newer than 20150113 required")
6517
d425fc41e59f net.cqueues: Add module that allows use of cqueues while still using net.server as main loop
daurnimator <quae@daurnimator.com>
parents:
diff changeset
    13
d425fc41e59f net.cqueues: Add module that allows use of cqueues while still using net.server as main loop
daurnimator <quae@daurnimator.com>
parents:
diff changeset
    14
-- Create a single top level cqueue
d425fc41e59f net.cqueues: Add module that allows use of cqueues while still using net.server as main loop
daurnimator <quae@daurnimator.com>
parents:
diff changeset
    15
local cq;
d425fc41e59f net.cqueues: Add module that allows use of cqueues while still using net.server as main loop
daurnimator <quae@daurnimator.com>
parents:
diff changeset
    16
d425fc41e59f net.cqueues: Add module that allows use of cqueues while still using net.server as main loop
daurnimator <quae@daurnimator.com>
parents:
diff changeset
    17
if server.cq then -- server provides cqueues object
d425fc41e59f net.cqueues: Add module that allows use of cqueues while still using net.server as main loop
daurnimator <quae@daurnimator.com>
parents:
diff changeset
    18
	cq = server.cq;
d425fc41e59f net.cqueues: Add module that allows use of cqueues while still using net.server as main loop
daurnimator <quae@daurnimator.com>
parents:
diff changeset
    19
elseif server.get_backend() == "select" and server._addtimer then -- server_select
d425fc41e59f net.cqueues: Add module that allows use of cqueues while still using net.server as main loop
daurnimator <quae@daurnimator.com>
parents:
diff changeset
    20
	cq = cqueues.new();
d425fc41e59f net.cqueues: Add module that allows use of cqueues while still using net.server as main loop
daurnimator <quae@daurnimator.com>
parents:
diff changeset
    21
	local function step()
d425fc41e59f net.cqueues: Add module that allows use of cqueues while still using net.server as main loop
daurnimator <quae@daurnimator.com>
parents:
diff changeset
    22
		assert(cq:loop(0));
d425fc41e59f net.cqueues: Add module that allows use of cqueues while still using net.server as main loop
daurnimator <quae@daurnimator.com>
parents:
diff changeset
    23
	end
d425fc41e59f net.cqueues: Add module that allows use of cqueues while still using net.server as main loop
daurnimator <quae@daurnimator.com>
parents:
diff changeset
    24
d425fc41e59f net.cqueues: Add module that allows use of cqueues while still using net.server as main loop
daurnimator <quae@daurnimator.com>
parents:
diff changeset
    25
	-- Use wrapclient (as wrapconnection isn't exported) to get server_select to watch cq fd
d425fc41e59f net.cqueues: Add module that allows use of cqueues while still using net.server as main loop
daurnimator <quae@daurnimator.com>
parents:
diff changeset
    26
	local handler = server.wrapclient({
d425fc41e59f net.cqueues: Add module that allows use of cqueues while still using net.server as main loop
daurnimator <quae@daurnimator.com>
parents:
diff changeset
    27
		getfd = function() return cq:pollfd(); end;
d425fc41e59f net.cqueues: Add module that allows use of cqueues while still using net.server as main loop
daurnimator <quae@daurnimator.com>
parents:
diff changeset
    28
		settimeout = function() end; -- Method just needs to exist
d425fc41e59f net.cqueues: Add module that allows use of cqueues while still using net.server as main loop
daurnimator <quae@daurnimator.com>
parents:
diff changeset
    29
		close = function() end; -- Need close method for 'closeall'
d425fc41e59f net.cqueues: Add module that allows use of cqueues while still using net.server as main loop
daurnimator <quae@daurnimator.com>
parents:
diff changeset
    30
	}, nil, nil, {});
d425fc41e59f net.cqueues: Add module that allows use of cqueues while still using net.server as main loop
daurnimator <quae@daurnimator.com>
parents:
diff changeset
    31
d425fc41e59f net.cqueues: Add module that allows use of cqueues while still using net.server as main loop
daurnimator <quae@daurnimator.com>
parents:
diff changeset
    32
	-- Only need to listen for readable; cqueues handles everything under the hood
d425fc41e59f net.cqueues: Add module that allows use of cqueues while still using net.server as main loop
daurnimator <quae@daurnimator.com>
parents:
diff changeset
    33
	-- readbuffer is called when `select` notes an fd as readable
d425fc41e59f net.cqueues: Add module that allows use of cqueues while still using net.server as main loop
daurnimator <quae@daurnimator.com>
parents:
diff changeset
    34
	handler.readbuffer = step;
d425fc41e59f net.cqueues: Add module that allows use of cqueues while still using net.server as main loop
daurnimator <quae@daurnimator.com>
parents:
diff changeset
    35
d425fc41e59f net.cqueues: Add module that allows use of cqueues while still using net.server as main loop
daurnimator <quae@daurnimator.com>
parents:
diff changeset
    36
	-- Use server_select low lever timer facility,
d425fc41e59f net.cqueues: Add module that allows use of cqueues while still using net.server as main loop
daurnimator <quae@daurnimator.com>
parents:
diff changeset
    37
	-- this callback gets called *every* time there is a timeout in the main loop
d425fc41e59f net.cqueues: Add module that allows use of cqueues while still using net.server as main loop
daurnimator <quae@daurnimator.com>
parents:
diff changeset
    38
	server._addtimer(function(current_time)
d425fc41e59f net.cqueues: Add module that allows use of cqueues while still using net.server as main loop
daurnimator <quae@daurnimator.com>
parents:
diff changeset
    39
		-- This may end up in extra step()'s, but cqueues handles it for us.
d425fc41e59f net.cqueues: Add module that allows use of cqueues while still using net.server as main loop
daurnimator <quae@daurnimator.com>
parents:
diff changeset
    40
		step();
d425fc41e59f net.cqueues: Add module that allows use of cqueues while still using net.server as main loop
daurnimator <quae@daurnimator.com>
parents:
diff changeset
    41
		return cq:timeout();
d425fc41e59f net.cqueues: Add module that allows use of cqueues while still using net.server as main loop
daurnimator <quae@daurnimator.com>
parents:
diff changeset
    42
	end);
d425fc41e59f net.cqueues: Add module that allows use of cqueues while still using net.server as main loop
daurnimator <quae@daurnimator.com>
parents:
diff changeset
    43
elseif server.event and server.base then -- server_event
d425fc41e59f net.cqueues: Add module that allows use of cqueues while still using net.server as main loop
daurnimator <quae@daurnimator.com>
parents:
diff changeset
    44
	cq = cqueues.new();
d425fc41e59f net.cqueues: Add module that allows use of cqueues while still using net.server as main loop
daurnimator <quae@daurnimator.com>
parents:
diff changeset
    45
	-- Only need to listen for readable; cqueues handles everything under the hood
d425fc41e59f net.cqueues: Add module that allows use of cqueues while still using net.server as main loop
daurnimator <quae@daurnimator.com>
parents:
diff changeset
    46
	local EV_READ = server.event.EV_READ;
6540
e4d443d05626 net.cqueues: Fixes hardcoded timeout for first iteration
daurnimator <quae@daurnimator.com>
parents: 6539
diff changeset
    47
	-- Convert a cqueues timeout to an acceptable timeout for luaevent
e4d443d05626 net.cqueues: Fixes hardcoded timeout for first iteration
daurnimator <quae@daurnimator.com>
parents: 6539
diff changeset
    48
	local function luaevent_safe_timeout(cq)
e4d443d05626 net.cqueues: Fixes hardcoded timeout for first iteration
daurnimator <quae@daurnimator.com>
parents: 6539
diff changeset
    49
		local t = cq:timeout();
e4d443d05626 net.cqueues: Fixes hardcoded timeout for first iteration
daurnimator <quae@daurnimator.com>
parents: 6539
diff changeset
    50
		-- if you give luaevent 0 or nil, it re-uses the previous timeout.
e4d443d05626 net.cqueues: Fixes hardcoded timeout for first iteration
daurnimator <quae@daurnimator.com>
parents: 6539
diff changeset
    51
		if t == 0 then
e4d443d05626 net.cqueues: Fixes hardcoded timeout for first iteration
daurnimator <quae@daurnimator.com>
parents: 6539
diff changeset
    52
			t = 0.000001; -- 1 microsecond is the smallest that works (goes into a `struct timeval`)
e4d443d05626 net.cqueues: Fixes hardcoded timeout for first iteration
daurnimator <quae@daurnimator.com>
parents: 6539
diff changeset
    53
		elseif t == nil then -- pick something big if we don't have one
e4d443d05626 net.cqueues: Fixes hardcoded timeout for first iteration
daurnimator <quae@daurnimator.com>
parents: 6539
diff changeset
    54
			t = 0x7FFFFFFF; -- largest 32bit int
e4d443d05626 net.cqueues: Fixes hardcoded timeout for first iteration
daurnimator <quae@daurnimator.com>
parents: 6539
diff changeset
    55
		end
e4d443d05626 net.cqueues: Fixes hardcoded timeout for first iteration
daurnimator <quae@daurnimator.com>
parents: 6539
diff changeset
    56
		return t
e4d443d05626 net.cqueues: Fixes hardcoded timeout for first iteration
daurnimator <quae@daurnimator.com>
parents: 6539
diff changeset
    57
	end
6539
605a87e90e27 net.cqueues: Add workaround for luaevent callback getting collected
daurnimator <quae@daurnimator.com>
parents: 6517
diff changeset
    58
	local event_handle;
605a87e90e27 net.cqueues: Add workaround for luaevent callback getting collected
daurnimator <quae@daurnimator.com>
parents: 6517
diff changeset
    59
	event_handle = server.base:addevent(cq:pollfd(), EV_READ, function(e)
605a87e90e27 net.cqueues: Add workaround for luaevent callback getting collected
daurnimator <quae@daurnimator.com>
parents: 6517
diff changeset
    60
			-- Need to reference event_handle or this callback will get collected
605a87e90e27 net.cqueues: Add workaround for luaevent callback getting collected
daurnimator <quae@daurnimator.com>
parents: 6517
diff changeset
    61
			-- This creates a circular reference that can only be broken if event_handle is manually :close()'d
605a87e90e27 net.cqueues: Add workaround for luaevent callback getting collected
daurnimator <quae@daurnimator.com>
parents: 6517
diff changeset
    62
			local _ = event_handle;
6540
e4d443d05626 net.cqueues: Fixes hardcoded timeout for first iteration
daurnimator <quae@daurnimator.com>
parents: 6539
diff changeset
    63
			-- Run as many cqueues things as possible (with a timeout of 0)
e4d443d05626 net.cqueues: Fixes hardcoded timeout for first iteration
daurnimator <quae@daurnimator.com>
parents: 6539
diff changeset
    64
			-- If an error is thrown, it will break the libevent loop; but prosody resumes after logging a top level error
6517
d425fc41e59f net.cqueues: Add module that allows use of cqueues while still using net.server as main loop
daurnimator <quae@daurnimator.com>
parents:
diff changeset
    65
			assert(cq:loop(0));
6540
e4d443d05626 net.cqueues: Fixes hardcoded timeout for first iteration
daurnimator <quae@daurnimator.com>
parents: 6539
diff changeset
    66
			return EV_READ, luaevent_safe_timeout(cq);
e4d443d05626 net.cqueues: Fixes hardcoded timeout for first iteration
daurnimator <quae@daurnimator.com>
parents: 6539
diff changeset
    67
		end, luaevent_safe_timeout(cq));
6517
d425fc41e59f net.cqueues: Add module that allows use of cqueues while still using net.server as main loop
daurnimator <quae@daurnimator.com>
parents:
diff changeset
    68
else
d425fc41e59f net.cqueues: Add module that allows use of cqueues while still using net.server as main loop
daurnimator <quae@daurnimator.com>
parents:
diff changeset
    69
	error "NYI"
d425fc41e59f net.cqueues: Add module that allows use of cqueues while still using net.server as main loop
daurnimator <quae@daurnimator.com>
parents:
diff changeset
    70
end
d425fc41e59f net.cqueues: Add module that allows use of cqueues while still using net.server as main loop
daurnimator <quae@daurnimator.com>
parents:
diff changeset
    71
d425fc41e59f net.cqueues: Add module that allows use of cqueues while still using net.server as main loop
daurnimator <quae@daurnimator.com>
parents:
diff changeset
    72
return {
d425fc41e59f net.cqueues: Add module that allows use of cqueues while still using net.server as main loop
daurnimator <quae@daurnimator.com>
parents:
diff changeset
    73
	cq = cq;
d425fc41e59f net.cqueues: Add module that allows use of cqueues while still using net.server as main loop
daurnimator <quae@daurnimator.com>
parents:
diff changeset
    74
}