posix_io.lua (2526B)
1 local base = string.match(..., "(.-)[^%.]+%.[^%.]+$") 2 local ffi = require("ffi") 3 local e_assert = require(base.."helper.errno").assert 4 5 local ffi_string = ffi.string 6 7 ffi.cdef[[ 8 int open(const char* file, int oflag, ...); 9 int open64(const char* file, int oflag, ...); 10 11 ssize_t read(int fd, void* buf, size_t n); 12 ssize_t write(int fd, const void* buf, size_t n); 13 14 int close(int fd); 15 16 struct pollfd 17 { 18 int fd; 19 short int events; 20 short int revents; 21 }; 22 int poll(struct pollfd* fds, unsigned long int nfds, int timeout); 23 24 // workaround for __gc not working for tables in lua 5.1/luajit 25 struct posix_io_instance { int fd; }; 26 ]] 27 28 local rdonly = 0 29 local wronly = 1 30 local rdwr = 2 31 32 local ffi_c = ffi.C 33 local open_func = ffi_c.open 34 pcall(function() open_func = ffi_c.open64 end) 35 36 local mt = {} 37 mt.__index = mt 38 39 local char_ary = ffi.typeof("char[?]") 40 function mt:read(n) 41 local buf = char_ary(n) 42 local res = ffi_c.read(self.fd, buf, n) 43 e_assert("read", res >= 0, 2) 44 return ffi_string(buf, res) 45 end 46 47 function mt:write(stuff, len) 48 if not len then len = #stuff end 49 local res = ffi_c.write(self.fd, stuff, len) 50 e_assert("write", res == len, 2) 51 end 52 53 function mt:close() 54 if self.fd < 0 then return end 55 local res = ffi_c.close(self.fd) 56 self.fd = -1 57 e_assert("close", res == 0, 2) 58 end 59 mt.__gc = mt.close 60 61 -- Very simple poll wrapper, not intended for real-life usage. 62 local pollfds = ffi.typeof("struct pollfd[?]") 63 local pollin = 1 64 local function poll_read(fds, timeout_s) 65 local arg = pollfds(#fds) 66 for i,v in ipairs(fds) do 67 local fd 68 if type(v) == "number" then fd = v else fd = v.fd end 69 arg[i-1].fd = fd 70 arg[i-1].events = pollin 71 end 72 73 local timeout_ms 74 if timeout_s then timeout_ms = timeout_s / 1000 else timeout_ms = -1 end 75 local res = ffi_c.poll(arg, #fds, timeout_ms) 76 if res == 0 then return end -- timeout 77 e_assert("poll", res >= 0, 2) 78 79 local ret = {} 80 for i=0,#fds-1 do 81 if arg[i].revents == pollin then 82 ret[fds[i+1]] = true 83 elseif arg[i].revents ~= 0 then 84 error("Unhandled revent "..arg[i].revents.." on fd "..fds[i+1].fd) 85 end 86 end 87 return ret 88 end 89 90 local ct = ffi.typeof("struct posix_io_instance") 91 ffi.metatype(ct, mt) 92 93 local function new(fname, flags) 94 local fd = open_func(fname, flags or rdwr) 95 e_assert("open", fd >= 0, 2) 96 return ct({fd=fd}) 97 end 98 mt.new = new 99 100 local module = { rdonly=rdonly, wronly=wronly, rdwr=rdwr, new=new, 101 poll_read = poll_read } 102 return setmetatable(module, {__call=function(_, ...) return new(...) end})