aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAlex Auvolat <alex@adnab.me>2017-04-21 16:57:00 +0200
committerAlex Auvolat <alex@adnab.me>2017-04-21 16:57:00 +0200
commitf8334e283c5eb0efeb4bb8a134041e18388d5f01 (patch)
tree508bc475133262afee1d4a1d9fe7af3f576e2ee9
parentec08d0410730a16836eb40f5e46082b3bbaf45f6 (diff)
downloadkogata-f8334e283c5eb0efeb4bb8a134041e18388d5f01.tar.gz
kogata-f8334e283c5eb0efeb4bb8a134041e18388d5f01.zip
Lua init
-rwxr-xr-xmake_cdrom.sh5
-rw-r--r--src/lib/libc/stdio.c6
-rw-r--r--src/sysapp/login/example.lua68
-rw-r--r--src/sysapp/login/main.lua74
-rw-r--r--src/sysbin/init/main.c164
-rw-r--r--src/sysbin/lx/lxinit.c1
-rw-r--r--src/sysbin/lx/lxioctllib.c62
-rw-r--r--src/sysbin/lx/lxlib.c41
-rw-r--r--src/sysbin/lx/lxlib.h10
-rw-r--r--src/sysbin/lx/lxsyslib.c43
-rw-r--r--src/sysbin/lx/main.c38
-rw-r--r--src/syslua/lx/mainloop.lua85
12 files changed, 453 insertions, 144 deletions
diff --git a/make_cdrom.sh b/make_cdrom.sh
index 170d117..46cd47f 100755
--- a/make_cdrom.sh
+++ b/make_cdrom.sh
@@ -64,8 +64,11 @@ cat > cdrom/boot/grub/menu.lst <<EOF
timeout 10
default 0
-title kogata OS
+title kogata OS, C terminal
kernel /boot/kernel.bin root=io:/disk/atapi0 root_opts=l init=root:/boot/init.bin config=default
+
+title kogata OS, Lua init
+kernel /boot/kernel.bin root=io:/disk/atapi0 root_opts=l init=root:/boot/init.bin config=default lx_init_app=login loop_exec=false
EOF
# Generate CDROM image
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