You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

103 lines
2.5 KiB
Lua

local base = string.match(..., "(.-)[^%.]+%.[^%.]+$")
local ffi = require("ffi")
local e_assert = require(base.."helper.errno").assert
local ffi_string = ffi.string
ffi.cdef[[
int open(const char* file, int oflag, ...);
int open64(const char* file, int oflag, ...);
ssize_t read(int fd, void* buf, size_t n);
ssize_t write(int fd, const void* buf, size_t n);
int close(int fd);
struct pollfd
{
int fd;
short int events;
short int revents;
};
int poll(struct pollfd* fds, unsigned long int nfds, int timeout);
// workaround for __gc not working for tables in lua 5.1/luajit
struct posix_io_instance { int fd; };
]]
local rdonly = 0
local wronly = 1
local rdwr = 2
local ffi_c = ffi.C
local open_func = ffi_c.open
pcall(function() open_func = ffi_c.open64 end)
local mt = {}
mt.__index = mt
local char_ary = ffi.typeof("char[?]")
function mt:read(n)
local buf = char_ary(n)
local res = ffi_c.read(self.fd, buf, n)
e_assert("read", res >= 0, 2)
return ffi_string(buf, res)
end
function mt:write(stuff, len)
if not len then len = #stuff end
local res = ffi_c.write(self.fd, stuff, len)
e_assert("write", res == len, 2)
end
function mt:close()
if self.fd < 0 then return end
local res = ffi_c.close(self.fd)
self.fd = -1
e_assert("close", res == 0, 2)
end
mt.__gc = mt.close
-- Very simple poll wrapper, not intended for real-life usage.
local pollfds = ffi.typeof("struct pollfd[?]")
local pollin = 1
local function poll_read(fds, timeout_s)
local arg = pollfds(#fds)
for i,v in ipairs(fds) do
local fd
if type(v) == "number" then fd = v else fd = v.fd end
arg[i-1].fd = fd
arg[i-1].events = pollin
end
local timeout_ms
if timeout_s then timeout_ms = timeout_s / 1000 else timeout_ms = -1 end
local res = ffi_c.poll(arg, #fds, timeout_ms)
if res == 0 then return end -- timeout
e_assert("poll", res >= 0, 2)
local ret = {}
for i=0,#fds-1 do
if arg[i].revents == pollin then
ret[fds[i+1]] = true
elseif arg[i].revents ~= 0 then
error("Unhandled revent "..arg[i].revents.." on fd "..fds[i+1].fd)
end
end
return ret
end
local ct = ffi.typeof("struct posix_io_instance")
ffi.metatype(ct, mt)
local function new(fname, flags)
local fd = open_func(fname, flags or rdwr)
e_assert("open", fd >= 0, 2)
return ct({fd=fd})
end
mt.new = new
local module = { rdonly=rdonly, wronly=wronly, rdwr=rdwr, new=new,
poll_read = poll_read }
return setmetatable(module, {__call=function(_, ...) return new(...) end})