diff options
Diffstat (limited to 'src/syslua/lx/mainloop.lua')
-rw-r--r-- | src/syslua/lx/mainloop.lua | 85 |
1 files changed, 85 insertions, 0 deletions
diff --git a/src/syslua/lx/mainloop.lua b/src/syslua/lx/mainloop.lua new file mode 100644 index 0000000..c2ae88d --- /dev/null +++ b/src/syslua/lx/mainloop.lua @@ -0,0 +1,85 @@ +local sys = require 'lx.sys' +local sysdef = require 'lx.sysdef' + +local mainloop = {} + +local fds = {} +local mainloop_must_exit = false +local mainloop_fds_change = false + +function new_fd(fd, error_cb) + local fd = { + fd = fd, + error_cb = error_cb, + rd_expect = {}, + wr_buf = "", + } + function fd:write(str) + -- TODO: try write immediately when possible + self.wr_buf = self.wr_buf .. str + end + function fd:expect(len, cb) + table.insert(self.rd_expect, {len, "", cb}) + end +end + +function mainloop.add_fd(fd, error_cb) + local fd = new_fd(fd, error_cb) + table.insert(fds, fd) + mainloop_fds_change = true + return fd +end + +function mainloop.run() + mainloop_must_exit = false + sel_fds = {} + while not mainloop_must_exit do + local deadlock = true + for i, fd in pairs(fds) do + if mainloop_fds_change then + sel_fds[i] = {fd.fd} + end + local flags = sysdef.SEL_ERROR + if fd.rd_expect[1] then + flags = flags | sysdef.SEL_READ + deadlock = false + end + if #fd.wr_buf > 0 then + flags = flags | sysdef.SEL_WRITE + deadlock = false + end + sel_fds[i][2] = flags + end + mainloop_fds_change = false + assert(not deadlock, "Mainloop does nothing!") + + local res = sys.select(sel_fds, -1) + assert(res, "select() call failed") + for i, fd = pairs(fds) do + local flags = sel_fds[i][3] + if flags & sysdef.SEL_ERROR ~= 0 then + fd.error_cb(fd) + else + if flags & sysdef.SEL_READ ~= 0 then + local reader = fd.rd_expect[1] + local tmp = sys.read(fd.fd, 0, reader[1] - #reader[2]) + reader[2] = reader[2] .. tmp + if #reader[2] == reader[1] then + reader[3](reader[2]) + table.remove(fd.rd_expect, 1) + end + end + if flags & sysdef.SEL_WRITE ~= 0 then + local r = sys.write(fd.fd, 0, fd.wr_buf) + fd.wr_buf = fd.wr_buf:sub(r+1) + end + end + end + end +end + +function mainloop.exit() + mainloop_must_exit = true +end + +return mainloop |