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
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})
|