1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156
|
-- serve test results, in case operating in an environemnt with no console
local S = require "syscall"
-- exit will cause issues, override
os.exit = function() end
-- open output file
local outname = "output"
local fd = S.creat(outname, "rwxu")
-- set stdio to file, keep handle so not garbage collected
local stdin = S.dup2(fd, 0)
local stdout = S.dup2(fd, 1)
local stderr = S.dup2(fd, 2)
-- run tests
require "test.test"
local st = fd:stat()
-- close file
fd:close()
local results = S.util.readfile(outname, nil, st.size)
-- serve file - this code is borrowed from examples/epoll.lua
local t, c = S.t, S.c
local function assert(cond, s, ...)
if cond == nil then error(tostring(s)) end -- annoyingly, assert does not call tostring!
return cond, s, ...
end
local maxevents = 1024
local poll
-- this is somewhat working toward a common API but needs a lot more work, but has resulted in some improvements
if S.epoll_create then
poll = {
init = function(this)
return setmetatable({fd = assert(S.epoll_create())}, {__index = this})
end,
event = t.epoll_event(),
add = function(this, s)
local event = this.event
event.events = c.EPOLL.IN
event.data.fd = s:getfd()
assert(this.fd:epoll_ctl("add", s, event))
end,
events = t.epoll_events(maxevents),
get = function(this)
return this.fd:epoll_wait(this.events)
end,
eof = function(ev) return ev.HUP or ev.ERR or ev.RDHUP end,
}
elseif S.kqueue then
poll = {
init = function(this)
return setmetatable({fd = assert(S.kqueue())}, {__index = this})
end,
event = t.kevents(1),
add = function(this, s)
local event = this.event[1]
event.fd = s
event.setfilter = "read"
event.setflags = "add"
assert(this.fd:kevent(this.event, nil, 0))
end,
events = t.kevents(maxevents),
get = function(this)
return this.fd:kevent(nil, this.events)
end,
eof = function(ev) return ev.EOF or ev.ERROR end,
}
else
error("no epoll or kqueue support")
end
local s = assert(S.socket("inet", "stream, nonblock"))
s:setsockopt("socket", "reuseaddr", true)
local sa = assert(t.sockaddr_in(80, "0.0.0.0"))
assert(s:bind(sa))
assert(s:listen(128))
ep = poll:init()
ep:add(s)
local w = {}
local msg = [[
<html>
<head>
<title>performance test</title>
</head>
<body>
]] .. results .. [[
</body>
</html>
]]
local reply = table.concat({
"HTTP/1.0 200 OK",
"Content-type: text/html",
"Connection: close",
"Content-Length: " .. #msg,
"",
"",
}, "\r\n") .. msg
local bufsize = 4096
local buffer = t.buffer(bufsize)
local ss = t.sockaddr_storage()
local addrlen = t.socklen1(#ss)
local function loop()
for i, ev in ep:get() do
if ep.eof(ev) then
fd:close()
w[ev.fileno] = nil
end
if ev.fd == s.filenum then -- server socket, accept
repeat
local a, err = s:accept("nonblock", ss, addrlen)
if a then
ep:add(a.fd)
w[a.fd:getfd()] = a.fd
end
until not a
else
local fd = w[ev.fd]
fd:read(buffer, bufsize)
local n = fd:write(reply)
assert(n == #reply)
assert(fd:close())
w[ev.fd] = nil
end
end
return loop()
end
loop()
|