diff options
author | Alex Auvolat <alex@adnab.me> | 2017-04-21 16:57:00 +0200 |
---|---|---|
committer | Alex Auvolat <alex@adnab.me> | 2017-04-21 16:57:00 +0200 |
commit | f8334e283c5eb0efeb4bb8a134041e18388d5f01 (patch) | |
tree | 508bc475133262afee1d4a1d9fe7af3f576e2ee9 /src | |
parent | ec08d0410730a16836eb40f5e46082b3bbaf45f6 (diff) | |
download | kogata-f8334e283c5eb0efeb4bb8a134041e18388d5f01.tar.gz kogata-f8334e283c5eb0efeb4bb8a134041e18388d5f01.zip |
Lua init
Diffstat (limited to 'src')
-rw-r--r-- | src/lib/libc/stdio.c | 6 | ||||
-rw-r--r-- | src/sysapp/login/example.lua | 68 | ||||
-rw-r--r-- | src/sysapp/login/main.lua | 74 | ||||
-rw-r--r-- | src/sysbin/init/main.c | 164 | ||||
-rw-r--r-- | src/sysbin/lx/lxinit.c | 1 | ||||
-rw-r--r-- | src/sysbin/lx/lxioctllib.c | 62 | ||||
-rw-r--r-- | src/sysbin/lx/lxlib.c | 41 | ||||
-rw-r--r-- | src/sysbin/lx/lxlib.h | 10 | ||||
-rw-r--r-- | src/sysbin/lx/lxsyslib.c | 43 | ||||
-rw-r--r-- | src/sysbin/lx/main.c | 38 | ||||
-rw-r--r-- | src/syslua/lx/mainloop.lua | 85 |
11 files changed, 449 insertions, 143 deletions
diff --git a/src/lib/libc/stdio.c b/src/lib/libc/stdio.c index 864fb34..bfa2f74 100644 --- a/src/lib/libc/stdio.c +++ b/src/lib/libc/stdio.c @@ -225,6 +225,10 @@ size_t fread(void *ptr, size_t size, size_t nmemb, FILE *stream) { } int fgetc(FILE *stream) { + if (stream == NULL) { + return EOF; + } + dbg_printf("FGETC %p\n", stream); // TODO buffering && ungetc @@ -321,10 +325,10 @@ int setvbuf(FILE *stream, char *buf, int mode, size_t size) { int fflush(FILE* stream) { dbg_printf("FFLUSH %p\n", stream); - if (!(stream->file_mode & FM_WRITE)) return 0; if (stream == NULL || stream->fd == 0) { return EOF; } + if (!(stream->file_mode & FM_WRITE)) return 0; if (stream->buf_mode != 0 && stream->out_buf_used > 0) { size_t ret = sc_write(stream->fd, stream->pos, stream->out_buf_used, stream->out_buf); diff --git a/src/sysapp/login/example.lua b/src/sysapp/login/example.lua new file mode 100644 index 0000000..d099ec7 --- /dev/null +++ b/src/sysapp/login/example.lua @@ -0,0 +1,68 @@ +local sys = require 'lx.sys' +local sysdef = require 'lx.sysdef' + +local mainloop = require 'lx.mainloop' +local gip = require 'lx.gip' +local draw = require 'lx.draw' + + +local io = gip.new(sysdef.STD_FD_GIP) + +function io:damage(reg) + if self.features & gipdef.GIPF_DAMAGE_NOTIF ~= 0 then + self:send_buffer_damage(draw.region(0, 0, 256, 256)) + end +end + +function io:on_initiate(arg) + self.flags = arg + + self:async_enumerate_modes(function(modes) + sys.dbg_print("Got mode list:\n") + for i, v in pairs(modes) do + sys.dbg_print(string.format("%d: %dx%d %d\n", i, v.width, v.height, v.bpp)) + end + + for i, v in pairs(modes) do + if v.width == 800 and v.height == 600 and v.bpp == 24 then + sys.dbg_print(string.format("Selecting mode %d\n", i)) + io:send_set_mode(i) + return + end + end + end) +end + +function io:on_buffer_info(arg, tok, geom) + self.surface = draw.surface_from_fd(sys.use_token(tok)) + self.geom = geom + + for x = 0, 255 do + for y = 0, 255 do + self.surface:put(x, y, draw.rgb(x, y, 128)) + end + end + + self:damage(draw.region(0, 0, 256, 256)) +end + +function io:async_enumerate_modes(callback) + local modelist = {} + local function gotmode(cmd, arg) + if arg == nil then + callback(modelist) + else + modelist[#modelist + 1] = arg + io.on_reply[io:send_query_mode(#modelist)] = gotmode + end + end + io.on_reply[io:send_query_mode(#modelist)] = gotmode +end + +mainloop.add(io) + +io:send_reset() +mainloop.run() + + + diff --git a/src/sysapp/login/main.lua b/src/sysapp/login/main.lua index d099ec7..dec8b82 100644 --- a/src/sysapp/login/main.lua +++ b/src/sysapp/login/main.lua @@ -1,68 +1,20 @@ local sys = require 'lx.sys' -local sysdef = require 'lx.sysdef' +local sysdef= require 'lx.sysdef' +local ioctl = require 'lx.ioctl' -local mainloop = require 'lx.mainloop' -local gip = require 'lx.gip' -local draw = require 'lx.draw' +print("Hello, world!") +local vesa_fd = sys.open("io:/display/vesa", sysdef.FM_IOCTL | sysdef.FM_READ | sysdef.FM_WRITE | sysdef.FM_MMAP) +print("vesa_fd = " .. vesa_fd) -local io = gip.new(sysdef.STD_FD_GIP) +local vesa_info = ioctl.fb_get_info(vesa_fd) +print("vesa_info = ", vesa_info) -function io:damage(reg) - if self.features & gipdef.GIPF_DAMAGE_NOTIF ~= 0 then - self:send_buffer_damage(draw.region(0, 0, 256, 256)) - end +local i = 1 +while true do + print(i) + i = i + 1 + sys.usleep(1000000) end -function io:on_initiate(arg) - self.flags = arg - - self:async_enumerate_modes(function(modes) - sys.dbg_print("Got mode list:\n") - for i, v in pairs(modes) do - sys.dbg_print(string.format("%d: %dx%d %d\n", i, v.width, v.height, v.bpp)) - end - - for i, v in pairs(modes) do - if v.width == 800 and v.height == 600 and v.bpp == 24 then - sys.dbg_print(string.format("Selecting mode %d\n", i)) - io:send_set_mode(i) - return - end - end - end) -end - -function io:on_buffer_info(arg, tok, geom) - self.surface = draw.surface_from_fd(sys.use_token(tok)) - self.geom = geom - - for x = 0, 255 do - for y = 0, 255 do - self.surface:put(x, y, draw.rgb(x, y, 128)) - end - end - - self:damage(draw.region(0, 0, 256, 256)) -end - -function io:async_enumerate_modes(callback) - local modelist = {} - local function gotmode(cmd, arg) - if arg == nil then - callback(modelist) - else - modelist[#modelist + 1] = arg - io.on_reply[io:send_query_mode(#modelist)] = gotmode - end - end - io.on_reply[io:send_query_mode(#modelist)] = gotmode -end - -mainloop.add(io) - -io:send_reset() -mainloop.run() - - - +os.exit() diff --git a/src/sysbin/init/main.c b/src/sysbin/init/main.c index ce09f37..e923ab3 100644 --- a/src/sysbin/init/main.c +++ b/src/sysbin/init/main.c @@ -9,8 +9,8 @@ #include <kogata/btree.h> -pid_t giosrv_pid = 0, login_pid = 0; -fd_pair_t root_gip_chan; +bool loop_exec = true; +pid_t giosrv_pid = 0, login_pid = 0, lx_init_pid = 0; void _parse_cmdline_iter(void* a, void* b) { dbg_printf(" '%s' -> '%s'\n", a, b); @@ -90,7 +90,7 @@ void setup_sys() { if (!ok) PANIC("[init] Could not bind root:/sys to sys:/"); } -void launch_giosrv() { +void launch_giosrv(fd_pair_t *root_gip_chan) { if (giosrv_pid != 0) return; giosrv_pid = sc_new_proc(); @@ -111,7 +111,7 @@ void launch_giosrv() { ok = sc_bind_fs(giosrv_pid, "config", "config"); if (!ok) PANIC("[init] Could not bind config:/ to giosrv"); - ok = sc_bind_fd(giosrv_pid, STD_FD_GIOSRV, root_gip_chan.a); + ok = sc_bind_fd(giosrv_pid, STD_FD_GIOSRV, root_gip_chan->a); if (!ok) PANIC("[init] Could not bind root GIP channel FD to giosrv"); ok = sc_proc_exec(giosrv_pid, "sys:/bin/giosrv.bin"); @@ -120,7 +120,7 @@ void launch_giosrv() { dbg_printf("[init] giosrv started.\n"); } -void launch_login() { +void launch_login(fd_pair_t *root_gip_chan) { if (login_pid != 0) return; login_pid = sc_new_proc(); @@ -141,7 +141,7 @@ void launch_login() { ok = sc_bind_fs(login_pid, "config", "config"); if (!ok) PANIC("[init] Could not bind config:/ to login"); - ok = sc_bind_fd(login_pid, STD_FD_GIP, root_gip_chan.b); + ok = sc_bind_fd(login_pid, STD_FD_GIP, root_gip_chan->b); if (!ok) PANIC("[init] Could not bind root GIP channel FD to login"); ok = sc_proc_exec(login_pid, "sys:/bin/login.bin"); @@ -150,30 +150,99 @@ void launch_login() { dbg_printf("[init] login started.\n"); } -int main(int argc, char **argv) { - dbg_print("[init] Starting up!\n"); +void launch_lx_init(const char* lx_init_app, fd_pair_t *io_chan) { + if (lx_init_pid != 0) return; - // Read kernel cmdline - btree_t *cmdline = read_cmdline(); - if (cmdline == 0) PANIC("[init] Could not parse cmdline"); + lx_init_pid = sc_new_proc(); + if (lx_init_pid == 0) { + PANIC("[init] Could not create process for lx_init"); + } - // setup config: - if (btree_find(cmdline, "config") == 0) { - PANIC("[init] No config=xxx option specified on command line"); - } else { - char* config = (char*)btree_find(cmdline, "config"); - dbg_printf("[init] Loading system configuration: %s\n", config); - ASSERT(strlen(config) < 30); + dbg_printf("[init] Setting up lx_init, pid: %d\n", lx_init_pid); - char buf[50]; - snprintf(buf, 50, "/config/%s", config); - bool ok = sc_fs_subfs("config", "root", buf, FM_READ | FM_WRITE | FM_MMAP | FM_READDIR); - if (!ok) PANIC("[init] Could not setup config:"); + bool ok; + + ok = sc_bind_fs(lx_init_pid, "io", "io"); + if (!ok) PANIC("[init] Could not bind io:/ to lx_init"); + + ok = sc_bind_fs(lx_init_pid, "root", "root"); + if (!ok) PANIC("[init] Could not bind root:/ to lx_init"); + + ok = sc_bind_fs(lx_init_pid, "sys", "sys"); + if (!ok) PANIC("[init] Could not bind sys:/ to lx_init"); + + ok = sc_bind_fs(lx_init_pid, "config", "config"); + if (!ok) PANIC("[init] Could not bind config:/ to lx_init"); + + char app_path[256]; + snprintf(app_path, 256, "/app/%s", lx_init_app); + + ok = sc_bind_subfs(lx_init_pid, "app", "sys", app_path, FM_ALL_MODES); + if (!ok) PANIC("[init] Could not bind app:/ to lx_init"); + + ok = sc_bind_fd(lx_init_pid, STD_FD_STDOUT, io_chan->b); + if (!ok) PANIC("[init] Could not bind stdout channel to lx_init"); + + ok = sc_bind_fd(lx_init_pid, STD_FD_STDERR, io_chan->b); + if (!ok) PANIC("[init] Could not bind stderr channel to lx_init"); + + ok = sc_proc_exec(lx_init_pid, "sys:/bin/lx.bin"); + if (!ok) PANIC("[init] Could not run lx.bin"); + + dbg_printf("[init] lx_init started\n"); +} + +void dump_all(fd_t fd) { + char buf[256]; + while(true){ + int n = sc_read(fd, 0, 255, buf); + if (n > 0) { + buf[n] = 0; + sc_dbg_print(buf); + } else { + break; + } } +} - // Setup sys: - setup_sys(); +int run_lua(const char* lx_init_app) { + // Setup a channel for stdout/stderr printing + fd_pair_t io_chan; + io_chan = sc_make_channel(false); + if (io_chan.a == 0 || io_chan.b == 0) { + PANIC("[init] Could not create Lua emergency I/O channel."); + } + + launch_lx_init(lx_init_app, &io_chan); + + while(true) { + dump_all(io_chan.a); + + proc_status_t s; + sc_proc_wait(0, false, &s); + if (s.pid != 0) { + if (s.pid == lx_init_pid) { + if (!loop_exec) { + dump_all(io_chan.a); + PANIC("[init] lx_init died!\n"); + } + + lx_init_pid = 0; + + dbg_printf("[init] lx_init_app died, restarting.\n"); + launch_lx_init(lx_init_app, &io_chan); + } else { + ASSERT(false); + } + } + + sc_usleep(100000); + } +} +int run_no_lua() { + fd_pair_t root_gip_chan; + // Setup GIP channel for communication between giosrv and login root_gip_chan = sc_make_channel(false); if (root_gip_chan.a == 0 || root_gip_chan.b == 0) { @@ -181,8 +250,8 @@ int main(int argc, char **argv) { } // Launch giosrv && login - launch_giosrv(); - launch_login(); + launch_giosrv(&root_gip_chan); + launch_login(&root_gip_chan); // Make sure no one dies while(true) { @@ -190,21 +259,60 @@ int main(int argc, char **argv) { sc_proc_wait(0, false, &s); if (s.pid != 0) { if (s.pid == giosrv_pid) { + if (!loop_exec) PANIC("[init] giosrv died!\n"); + giosrv_pid = 0; dbg_printf("[init] giosrv died, restarting.\n"); - launch_giosrv(); + launch_giosrv(&root_gip_chan); } else if (s.pid == login_pid) { + if (!loop_exec) PANIC("[init] login died!\n"); + login_pid = 0; dbg_printf("[init] login died, restarting.\n"); - launch_login(); + launch_login(&root_gip_chan); } else { ASSERT(false); } } sc_usleep(1000000); } +} + +int main(int argc, char **argv) { + dbg_print("[init] Starting up!\n"); + + // Read kernel cmdline + btree_t *cmdline = read_cmdline(); + if (cmdline == 0) PANIC("[init] Could not parse cmdline"); + + // setup config: + if (btree_find(cmdline, "config") == 0) { + PANIC("[init] No config=xxx option specified on command line"); + } else { + char* config = (char*)btree_find(cmdline, "config"); + dbg_printf("[init] Loading system configuration: %s\n", config); + ASSERT(strlen(config) < 30); + + char buf[50]; + snprintf(buf, 50, "/config/%s", config); + bool ok = sc_fs_subfs("config", "root", buf, FM_READ | FM_WRITE | FM_MMAP | FM_READDIR); + if (!ok) PANIC("[init] Could not setup config:"); + } + + // Setup sys: + setup_sys(); + + if (btree_find(cmdline, "loop_exec") && + strcmp(btree_find(cmdline, "loop_exec"), "true")) + loop_exec = false; + + if (btree_find(cmdline, "lx_init_app")) { + run_lua(btree_find(cmdline, "lx_init_app")); + } else { + run_no_lua(); + } return 0; } diff --git a/src/sysbin/lx/lxinit.c b/src/sysbin/lx/lxinit.c index c185b45..b727ccd 100644 --- a/src/sysbin/lx/lxinit.c +++ b/src/sysbin/lx/lxinit.c @@ -35,6 +35,7 @@ static const luaL_Reg loadedlibs[] = { {LX_SYSLIBNAME, lx_open_sys}, {LX_MSGLIBNAME, lx_open_msg}, + {LX_IOCTLLIBNAME, lx_open_ioctl}, {NULL, NULL} }; diff --git a/src/sysbin/lx/lxioctllib.c b/src/sysbin/lx/lxioctllib.c new file mode 100644 index 0000000..4b9be91 --- /dev/null +++ b/src/sysbin/lx/lxioctllib.c @@ -0,0 +1,62 @@ +/* +** Lua eXtended ioctl library +*/ + +#define lxioctllib_c +#define LUA_LIB + +#include <lua/lprefix.h> + + +#include <errno.h> +#include <locale.h> +#include <stdlib.h> +#include <string.h> +#include <time.h> + +#include <lua/lua.h> + +#include <lua/lauxlib.h> +#include <lua/lualib.h> + +#include <kogata/syscall.h> +#include <kogata/gip.h> + +#include "lxlib.h" + + +static int ioctl_fb_get_info(lua_State *L) { + int fd = luaL_checkinteger(L, 1); + + fb_info_t mode; + int r = sc_ioctl(fd, IOCTL_FB_GET_INFO, &mode); + if (r == 1) { + lua_createtable(L, 0, 5); + setintfield(L, "width", mode.width); + setintfield(L, "height", mode.height); + setintfield(L, "pitch", mode.pitch); + setintfield(L, "bpp", mode.bpp); + setintfield(L, "memory_model", mode.memory_model); + } else { + lua_pushnil(L); + } + + return 1; +} + + +/* }====================================================== */ + +static const luaL_Reg ioctllib[] = { + {"fb_get_info", ioctl_fb_get_info}, + {NULL, NULL} +}; + + +LUAMOD_API int lx_open_ioctl (lua_State *L) { + luaL_newlib(L, ioctllib); + return 1; +} + + +/* vim: set sts=2 ts=2 sw=2 tw=0 et :*/ diff --git a/src/sysbin/lx/lxlib.c b/src/sysbin/lx/lxlib.c new file mode 100644 index 0000000..9f6843b --- /dev/null +++ b/src/sysbin/lx/lxlib.c @@ -0,0 +1,41 @@ +/* +** Lua eXtended library helpers +*/ + +#define lxsyslib_c +#define LUA_LIB + +#include <lua/lprefix.h> + + +#include <errno.h> +#include <locale.h> +#include <stdlib.h> +#include <string.h> +#include <time.h> + +#include <lua/lua.h> + +#include <lua/lauxlib.h> +#include <lua/lualib.h> + +#include "lxlib.h" + + +bool lx_checkboolean(lua_State *L, int arg) { + if (!lua_isboolean(L, arg)) { + luaL_argerror(L, arg, "expected boolean"); + } + return lua_toboolean(L, arg); +} + + +void setintfield (lua_State *L, const char *key, int value) { + lua_pushinteger(L, value); + lua_setfield(L, -2, key); +} + +void setstrfield (lua_State *L, const char *key, const char* value) { + lua_pushstring(L, value); + lua_setfield(L, -2, key); +} diff --git a/src/sysbin/lx/lxlib.h b/src/sysbin/lx/lxlib.h index 199c78d..260db97 100644 --- a/src/sysbin/lx/lxlib.h +++ b/src/sysbin/lx/lxlib.h @@ -6,12 +6,18 @@ #include <lua/lua.h> -#define LX_SYSLIBNAME "lx.sys" -LUAMOD_API int (lx_open_sys) (lua_State *L); +// Helper for libraries +bool lx_checkboolean(lua_State *L, int arg); +void setintfield (lua_State *L, const char *key, int value); +void setstrfield (lua_State *L, const char *key, const char* value); + #define LX_SYSLIBNAME "lx.sys" LUAMOD_API int (lx_open_sys) (lua_State *L); +#define LX_IOCTLLIBNAME "lx.ioctl" +LUAMOD_API int (lx_open_ioctl) (lua_State *L); + #define LX_MSGLIBNAME "lx.msg" LUAMOD_API int (luaopen_cmsgpack) (lua_State *L); #define lx_open_msg luaopen_cmsgpack diff --git a/src/sysbin/lx/lxsyslib.c b/src/sysbin/lx/lxsyslib.c index 52c6978..72c9882 100644 --- a/src/sysbin/lx/lxsyslib.c +++ b/src/sysbin/lx/lxsyslib.c @@ -22,25 +22,6 @@ #include "lxlib.h" -bool lx_checkboolean(lua_State *L, int arg) { - if (!lua_isboolean(L, arg)) { - luaL_argerror(L, arg, "expected boolean"); - } - return lua_toboolean(L, arg); -} - - -static void setintfield (lua_State *L, const char *key, int value) { - lua_pushinteger(L, value); - lua_setfield(L, -2, key); -} - -static void setstrfield (lua_State *L, const char *key, const char* value) { - lua_pushstring(L, value); - lua_setfield(L, -2, key); -} - - static int sys_dbg_print(lua_State *L) { const char *str = luaL_checkstring(L, 1); sc_dbg_print(str); @@ -68,6 +49,7 @@ static int sys_usleep(lua_State *L) { Missing syscalls : - sys_new_thread, exit_thread -> into specific threading library - mmap, mmap_file, mchmap, munmap -> into specific memory-related library ?? + - ioctl, fctl -> into ioctl library */ static int sys_create(lua_State *L) { @@ -180,25 +162,10 @@ static int sys_stat_open(lua_State *L) { return 1; } -static int sys_ioctl(lua_State *L) { - // TODO - return 0; -} - -static int sys_fctl(lua_State *L) { - // TODO - return 0; -} - static int sys_select(lua_State *L) { luaL_checktype(L, 1, LUA_TTABLE); int nfds = luaL_len(L, 1); - int timeout; - if (lua_isinteger(L, 2)) { - timeout = luaL_checkinteger(L, 2); - } else { - timeout = 0; - } + int timeout = luaL_checkinteger(L, 2); sel_fd_t *fds = (sel_fd_t*)malloc(nfds*sizeof(sel_fd_t)); if (fds == NULL) @@ -398,6 +365,7 @@ static int sys_proc_wait(lua_State *L) { return 1; } +/* }====================================================== */ static const luaL_Reg syslib[] = { {"dbg_print", sys_dbg_print}, @@ -414,8 +382,6 @@ static const luaL_Reg syslib[] = { {"write", sys_write}, {"readdir", sys_readdir}, {"stat_open", sys_stat_open}, - {"ioctl", sys_ioctl}, - {"fctl", sys_fctl}, {"select", sys_select}, {"make_channel",sys_make_channel}, {"make_shm", sys_make_shm}, @@ -438,9 +404,6 @@ static const luaL_Reg syslib[] = { {NULL, NULL} }; -/* }====================================================== */ - - LUAMOD_API int lx_open_sys (lua_State *L) { luaL_newlib(L, syslib); diff --git a/src/sysbin/lx/main.c b/src/sysbin/lx/main.c index b7e08d9..573e1bb 100644 --- a/src/sysbin/lx/main.c +++ b/src/sysbin/lx/main.c @@ -346,12 +346,26 @@ int handle_luainit (lua_State *L) { } -/* -** Main body of stand-alone interpreter (to be called in protected mode). -** Reads the options and handles them all. -*/ +bool find_lua_main(lua_State *L) { + lua_getglobal(L, "package"); + if (lua_getfield(L, -1, "searchers") != LUA_TTABLE) + luaL_error(L, "'package.searchers' must be a table"); + lua_remove(L, -2); + for (int i = 1; ; i++) { + if (lua_rawgeti(L, -1, i) == LUA_TNIL) { /* no more searchers? */ + lua_pop(L, 2); // pop nil & searchers table + return false; + } + lua_pushstring(L, "main"); + lua_call(L, 1, 2); /* call it */ + if (lua_isfunction(L, -2)) /* did it find a loader? */ + return true; /* module loader found */ + else + lua_pop(L, 2); /* remove both returns */ + } +} + int pmain (lua_State *L) { - int status; luaL_checkversion(L); /* check that interpreter has correct version */ print_version(); @@ -362,18 +376,20 @@ int pmain (lua_State *L) { if (handle_luainit(L) != LUA_OK) /* run LUA_INIT */ return 0; /* error running LUA_INIT */ - lua_getglobal(L, "require"); - lua_pushstring(L, "main"); - status = docall(L, 1, 1); /* call 'require("main")' */ - if (status != LUA_OK) { + if (find_lua_main(L)) { + // call loader + lua_pushstring(L, "main"); + lua_insert(L, -2); + lua_call(L, 2, 1); + } else { // no main, launch a REPL if (lua_stdin_is_tty()) { /* running in interactive mode? */ doREPL(L); /* do read-eval-print loop */ } else { - dofile(L, NULL); /* executes stdin as a file */ + dofile(L, NULL); /* executes stdin as a file */ } + lua_pushboolean(L, 1); /* signal no errors */ } - lua_pushboolean(L, 1); /* signal no errors */ return 1; } 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 |