Mercurial > prosody-hg
comparison net/cqueues.lua @ 6514:d425fc41e59f
net.cqueues: Add module that allows use of cqueues while still using net.server as main loop
| author | daurnimator <quae@daurnimator.com> |
|---|---|
| date | Tue, 18 Nov 2014 14:14:41 -0500 |
| parents | |
| children | 605a87e90e27 |
comparison
equal
deleted
inserted
replaced
| 6513:3bbd59c03aeb | 6514:d425fc41e59f |
|---|---|
| 1 -- Prosody IM | |
| 2 -- Copyright (C) 2014 Daurnimator | |
| 3 -- | |
| 4 -- This project is MIT/X11 licensed. Please see the | |
| 5 -- COPYING file in the source package for more information. | |
| 6 -- | |
| 7 -- This module allows you to use cqueues with a net.server mainloop | |
| 8 -- | |
| 9 | |
| 10 local server = require "net.server"; | |
| 11 local cqueues = require "cqueues"; | |
| 12 | |
| 13 -- Create a single top level cqueue | |
| 14 local cq; | |
| 15 | |
| 16 if server.cq then -- server provides cqueues object | |
| 17 cq = server.cq; | |
| 18 elseif server.get_backend() == "select" and server._addtimer then -- server_select | |
| 19 cq = cqueues.new(); | |
| 20 local function step() | |
| 21 assert(cq:loop(0)); | |
| 22 end | |
| 23 | |
| 24 -- Use wrapclient (as wrapconnection isn't exported) to get server_select to watch cq fd | |
| 25 local handler = server.wrapclient({ | |
| 26 getfd = function() return cq:pollfd(); end; | |
| 27 settimeout = function() end; -- Method just needs to exist | |
| 28 close = function() end; -- Need close method for 'closeall' | |
| 29 }, nil, nil, {}); | |
| 30 | |
| 31 -- Only need to listen for readable; cqueues handles everything under the hood | |
| 32 -- readbuffer is called when `select` notes an fd as readable | |
| 33 handler.readbuffer = step; | |
| 34 | |
| 35 -- Use server_select low lever timer facility, | |
| 36 -- this callback gets called *every* time there is a timeout in the main loop | |
| 37 server._addtimer(function(current_time) | |
| 38 -- This may end up in extra step()'s, but cqueues handles it for us. | |
| 39 step(); | |
| 40 return cq:timeout(); | |
| 41 end); | |
| 42 elseif server.event and server.base then -- server_event | |
| 43 cq = cqueues.new(); | |
| 44 -- Only need to listen for readable; cqueues handles everything under the hood | |
| 45 local EV_READ = server.event.EV_READ; | |
| 46 server.base:addevent(cq:pollfd(), EV_READ, function(e) | |
| 47 assert(cq:loop(0)); | |
| 48 -- Convert a cq timeout to an acceptable timeout for luaevent | |
| 49 local t = cq:timeout(); | |
| 50 if t == 0 then -- if you give luaevent 0, it won't call this callback again | |
| 51 t = 0.000001; -- 1 microsecond is the smallest that works (goes into a `struct timeval`) | |
| 52 elseif t == nil then -- you always need to give a timeout, pick something big if we don't have one | |
| 53 t = 0x7FFFFFFF; -- largest 32bit int | |
| 54 end | |
| 55 return EV_READ, t; | |
| 56 end, | |
| 57 -- Schedule the callback to fire on first tick to ensure any cq:wrap calls that happen during start-up are serviced. | |
| 58 0.000001); | |
| 59 else | |
| 60 error "NYI" | |
| 61 end | |
| 62 | |
| 63 return { | |
| 64 cq = cq; | |
| 65 } |
