From 79a788279b75083b065785793822bcf38aad1a62 Mon Sep 17 00:00:00 2001 From: Hayley Patton Date: Mon, 13 Nov 2023 15:18:49 +1100 Subject: [PATCH 01/12] Add Emscripten/WASM support --- .gitignore | 2 ++ bin/makefile-emscripten.wasm-wasm | 19 +++++++++++++++++++ bin/makeright | 5 +++++ inc/maiko/platform.h | 13 +++++++++++++ src/timer.c | 5 +++++ src/unixfork.c | 5 +++++ src/xc.c | 10 ++++++++++ 7 files changed, 59 insertions(+) create mode 100644 bin/makefile-emscripten.wasm-wasm diff --git a/.gitignore b/.gitignore index 0111213..306defa 100644 --- a/.gitignore +++ b/.gitignore @@ -19,6 +19,8 @@ cmake-build-*/** *.x86_64-x/** *.x86_64-sdl/** *.x86_64/** +*.wasm/** +*.wasm-wasm/** *.armv7l-x/** *.armv7l/** *.aarch64-x/** diff --git a/bin/makefile-emscripten.wasm-wasm b/bin/makefile-emscripten.wasm-wasm new file mode 100644 index 0000000..2007eec --- /dev/null +++ b/bin/makefile-emscripten.wasm-wasm @@ -0,0 +1,19 @@ +# Options for Emscripten, WASM and SDL + +CC = emcc -sUSE_SDL=2 -sASYNCIFY -sALLOW_MEMORY_GROWTH $(CLANG_CFLAGS) + +XFILES = $(OBJECTDIR)sdl.o + +XFLAGS = -DSDL + +# OPTFLAGS is normally -O2. +OPTFLAGS = -O2 -g3 +DFLAGS = $(XFLAGS) -DRELEASE=351 + +LD = emcc +LDFLAGS = -sUSE_SDL=2 --preload-file $(SYSOUT)@full.sysout +LDELDFLAGS = + +OBJECTDIR = ../$(RELEASENAME)/ + +default : ../$(OSARCHNAME)/lde ../$(OSARCHNAME)/ldesdl.js diff --git a/bin/makeright b/bin/makeright index 1fde522..156685c 100755 --- a/bin/makeright +++ b/bin/makeright @@ -74,6 +74,11 @@ case "$display" in sdl) releasename=${osversion}.${architecture}-${display} ldename=ldesdl ;; + wasm) osversion=emscripten + architecture=wasm + releasename=${osversion}.${architecture}-${display} + ldename=ldesdl.js + ;; *) echo "display-option: $display is not supported." exit ;; diff --git a/inc/maiko/platform.h b/inc/maiko/platform.h index 2fa747e..a69b21f 100644 --- a/inc/maiko/platform.h +++ b/inc/maiko/platform.h @@ -83,6 +83,19 @@ # define MAIKO_OS_DETECTED 1 #endif +#ifdef __EMSCRIPTEN__ +# define MAIKO_OS_LINUX 1 +# define MAIKO_OS_EMSCRIPTEN 1 +# define MAIKO_OS_NAME "Emscripten" +# define MAIKO_EMULATE_TIMER_INTERRUPTS 1 +# define MAIKO_EMULATE_ASYNC_INTERRUPTS 1 +# define MAIKO_OS_UNIX_LIKE 1 +# define MAIKO_OS_DETECTED +# define MAIKO_ARCH_NAME "WebAssembly" +# define MAIKO_ARCH_WORD_BITS 32 +# define MAIKO_ARCH_DETECTED 1 +#endif + /* __x86_64__: GNU C, __x86_64: Sun Studio, _M_AMD64: Visual Studio */ #if defined(__x86_64__) || defined(__x86_64) || defined(_M_AMD64) # define MAIKO_ARCH_X86_64 1 diff --git a/src/timer.c b/src/timer.c index 5d75bb2..2cb14c2 100644 --- a/src/timer.c +++ b/src/timer.c @@ -73,6 +73,11 @@ extern int ether_fd; extern DspInterface currentdsp; #endif /* XWINDOW */ +#ifdef MAIKO_OS_EMSCRIPTEN +/* We can't touch the system clock */ +#define settimeofday(tv, tz) +#endif + #define LISP_UNIX_TIME_DIFF 29969152 #define LISP_ALTO_TIME_MASK 0x80000000 #define UNIX_ALTO_TIME_DIFF 2177452800U diff --git a/src/unixfork.c b/src/unixfork.c index 3b9dce1..b35f1ef 100644 --- a/src/unixfork.c +++ b/src/unixfork.c @@ -45,6 +45,11 @@ int flushing = 0; #endif +#ifdef MAIKO_OS_EMSCRIPTEN +/* We don't have any shell */ +#define getusershell() NULL +#endif + /* Used to communicate between Unix subprocesses and LISP */ static long StartTime; /* Time, for creating pipe filenames */ diff --git a/src/xc.c b/src/xc.c index 5140042..644e00d 100644 --- a/src/xc.c +++ b/src/xc.c @@ -33,6 +33,10 @@ #include #endif /* DOS */ +#ifdef __EMSCRIPTEN__ +#include /* Defines emscripten_sleep */ +#endif /* __EMSCRIPTEN__ */ + #include "lispemul.h" #include "emlglob.h" #include "address.h" @@ -183,6 +187,9 @@ static int pseudoTimerAsyncCountdown = MAIKO_TIMER_ASYNC_EMULATION_INSNS_COUNTDO void dispatch(void) { InstPtr pccache; +#ifdef __EMSCRIPTEN__ + int cycles = 0; +#endif #if defined(OPDISP) static const void* optable[256] = { @@ -261,6 +268,9 @@ op_ufn : { /* DISPATCH "LOOP" */ nextopcode: +#ifdef __EMSCRIPTEN__ + if (++cycles % 1000000 == 0) emscripten_sleep(1); +#endif #ifdef MYOPTRACE if ((struct fnhead *)NativeAligned4FromLAddr(0x2ed600) == FuncObj) { quick_stack_check(); From 7b2cf44c7cca62e5faf2efa5b4912da79cee0ffc Mon Sep 17 00:00:00 2001 From: Hayley Patton Date: Mon, 13 Nov 2023 15:30:19 +1100 Subject: [PATCH 02/12] Add ldesdl.html --- .gitignore | 1 + emscripten.wasm/ldesdl.html | 20 ++++++++++++++++++++ 2 files changed, 21 insertions(+) create mode 100644 emscripten.wasm/ldesdl.html diff --git a/.gitignore b/.gitignore index 306defa..8e0d861 100644 --- a/.gitignore +++ b/.gitignore @@ -20,6 +20,7 @@ cmake-build-*/** *.x86_64-sdl/** *.x86_64/** *.wasm/** +!emscripten.wasm/ldesdl.html *.wasm-wasm/** *.armv7l-x/** *.armv7l/** diff --git a/emscripten.wasm/ldesdl.html b/emscripten.wasm/ldesdl.html new file mode 100644 index 0000000..3ddffcd --- /dev/null +++ b/emscripten.wasm/ldesdl.html @@ -0,0 +1,20 @@ + + + + + + + + +
+ +
+ + + + From e82b47a9e73ee31ba3d493b18c4705a7edcf2657 Mon Sep 17 00:00:00 2001 From: Nick Briggs Date: Fri, 22 Dec 2023 13:13:32 -0800 Subject: [PATCH 03/12] Give emcc link-time flags only to the link phase not the compile phase --- bin/makefile-emscripten.wasm-wasm | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/bin/makefile-emscripten.wasm-wasm b/bin/makefile-emscripten.wasm-wasm index 2007eec..f092375 100644 --- a/bin/makefile-emscripten.wasm-wasm +++ b/bin/makefile-emscripten.wasm-wasm @@ -1,6 +1,6 @@ # Options for Emscripten, WASM and SDL -CC = emcc -sUSE_SDL=2 -sASYNCIFY -sALLOW_MEMORY_GROWTH $(CLANG_CFLAGS) +CC = emcc $(CLANG_CFLAGS) XFILES = $(OBJECTDIR)sdl.o @@ -11,9 +11,9 @@ OPTFLAGS = -O2 -g3 DFLAGS = $(XFLAGS) -DRELEASE=351 LD = emcc -LDFLAGS = -sUSE_SDL=2 --preload-file $(SYSOUT)@full.sysout +LDFLAGS = -sUSE_SDL=2 -sASYNCIFY -sALLOW_MEMORY_GROWTH --preload-file $(SYSOUT)@full.sysout LDELDFLAGS = OBJECTDIR = ../$(RELEASENAME)/ -default : ../$(OSARCHNAME)/lde ../$(OSARCHNAME)/ldesdl.js +default : ../$(OSARCHNAME)/ldesdl.js From f208fd33028d25220ea43916dccc371ff05fe83a Mon Sep 17 00:00:00 2001 From: Nick Briggs Date: Fri, 22 Dec 2023 13:18:20 -0800 Subject: [PATCH 04/12] Rename/move ldesdl.html out of emscripten.wasm (which gets cleared on rebuild) to src/lde.html --- emscripten.wasm/ldesdl.html => src/lde.html | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename emscripten.wasm/ldesdl.html => src/lde.html (100%) diff --git a/emscripten.wasm/ldesdl.html b/src/lde.html similarity index 100% rename from emscripten.wasm/ldesdl.html rename to src/lde.html From 0cc8e4d71c51663590537d92466b5b1c0d9b0f81 Mon Sep 17 00:00:00 2001 From: Nick Briggs Date: Fri, 22 Dec 2023 13:35:33 -0800 Subject: [PATCH 06/12] Revert/update unixfork.c since it is no longer used in emscripten based builds --- src/unixfork.c | 21 +++++++++------------ 1 file changed, 9 insertions(+), 12 deletions(-) diff --git a/src/unixfork.c b/src/unixfork.c index b35f1ef..366495f 100644 --- a/src/unixfork.c +++ b/src/unixfork.c @@ -45,11 +45,6 @@ int flushing = 0; #endif -#ifdef MAIKO_OS_EMSCRIPTEN -/* We don't have any shell */ -#define getusershell() NULL -#endif - /* Used to communicate between Unix subprocesses and LISP */ static long StartTime; /* Time, for creating pipe filenames */ @@ -103,7 +98,7 @@ static int ForkUnixShell(int slot, char *PtySlave, char *termtype, char *shellar if (SlaveFD == -1) { perror("Slave Open"); perror(PtySlave); - exit(0); + exit(1); } #ifdef OS5 @@ -137,7 +132,7 @@ static int ForkUnixShell(int slot, char *PtySlave, char *termtype, char *shellar for (userShell = getusershell(); userShell != NULL && strcmp(shell, userShell) != 0; userShell = getusershell()); if (userShell == NULL) { perror("$(SHELL) not found in /etc/shells"); - exit(0); + exit(1); } /* argvec entries initialized to NULL */ @@ -151,7 +146,7 @@ static int ForkUnixShell(int slot, char *PtySlave, char *termtype, char *shellar /* Should never get here */ perror("execv"); - exit(0); + exit(1); } /* fork_Unix is the secondary process spawned right after LISP is @@ -269,12 +264,14 @@ int fork_Unix(void) { while (1) { ssize_t len; len = SAFEREAD(LispPipeIn, IOBuf, 6); + if (len == 0) + exit(0); if (len < 0) { perror("Error reading packet by slave"); - exit(0); + exit(1); } else if (len != 6) { DBPRINT(("Input packet wrong length: %zd", len)); - exit(0); + exit(1); } slot = IOBuf[3]; IOBuf[3] = 1; /* Start by signalling success in return-code */ @@ -350,7 +347,7 @@ int fork_Unix(void) { sock = socket(AF_UNIX, SOCK_STREAM, 0); if (sock < 0) { perror("slave socket"); - exit(0); + exit(1); } sprintf(PipeName, "/tmp/LPU%ld-%d", StartTime, slot); memset(&addr, 0, sizeof(struct sockaddr_un)); @@ -362,7 +359,7 @@ int fork_Unix(void) { perror("slave connect"); printf("Name = %s.\n", PipeName); fflush(stdout); - exit(0); + exit(1); } else { DBPRINT(("Slave connected on %s.\n", PipeName)); } From b21fbcbcb1ad5907675b59cf1001c5a9f4f3928f Mon Sep 17 00:00:00 2001 From: Nick Briggs Date: Fri, 22 Dec 2023 18:15:18 -0800 Subject: [PATCH 07/12] subr_settime should avoid settimeofday() completely in Emscripten environment --- src/timer.c | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/src/timer.c b/src/timer.c index 2cb14c2..08a5874 100644 --- a/src/timer.c +++ b/src/timer.c @@ -73,11 +73,6 @@ extern int ether_fd; extern DspInterface currentdsp; #endif /* XWINDOW */ -#ifdef MAIKO_OS_EMSCRIPTEN -/* We can't touch the system clock */ -#define settimeofday(tv, tz) -#endif - #define LISP_UNIX_TIME_DIFF 29969152 #define LISP_ALTO_TIME_MASK 0x80000000 #define UNIX_ALTO_TIME_DIFF 2177452800U @@ -293,6 +288,8 @@ void subr_settime(LispPTR args[]) dosday.year = uxtime.tm_year; dosday.dayofweek = uxtime.tm_wday; _dos_setdate(&dosday); +#elif defined(MAIKO_OS_EMSCRIPTEN) + (void)args[0]; #else struct timeval timev; timev.tv_sec = *((int *)NativeAligned4FromLAddr(args[0])) - UNIX_ALTO_TIME_DIFF; From 4b0032e1b60ac191d23beb072ac7c5fdea31d826 Mon Sep 17 00:00:00 2001 From: Nick Briggs Date: Fri, 22 Dec 2023 18:17:02 -0800 Subject: [PATCH 08/12] Piggyback on existing async timer emulation instruction countdown for periodic emscripten_sleep() call. There is no need for an additional Emscripten-specific counter to periodically call emscripten_sleep(). Make test for Emscripten environment check MAIKO_OS_EMSCRIPTEN rather than checking __EMSCRIPTEN__, which is localized in the maiko/platform.h include. --- src/xc.c | 16 ++++++---------- 1 file changed, 6 insertions(+), 10 deletions(-) diff --git a/src/xc.c b/src/xc.c index 644e00d..907b16b 100644 --- a/src/xc.c +++ b/src/xc.c @@ -20,6 +20,9 @@ /* */ /************************************************************************/ +#ifdef MAIKO_OS_EMSCRIPTEN +#include +#endif #include #include #include @@ -33,10 +36,6 @@ #include #endif /* DOS */ -#ifdef __EMSCRIPTEN__ -#include /* Defines emscripten_sleep */ -#endif /* __EMSCRIPTEN__ */ - #include "lispemul.h" #include "emlglob.h" #include "address.h" @@ -187,9 +186,6 @@ static int pseudoTimerAsyncCountdown = MAIKO_TIMER_ASYNC_EMULATION_INSNS_COUNTDO void dispatch(void) { InstPtr pccache; -#ifdef __EMSCRIPTEN__ - int cycles = 0; -#endif #if defined(OPDISP) static const void* optable[256] = { @@ -268,9 +264,6 @@ op_ufn : { /* DISPATCH "LOOP" */ nextopcode: -#ifdef __EMSCRIPTEN__ - if (++cycles % 1000000 == 0) emscripten_sleep(1); -#endif #ifdef MYOPTRACE if ((struct fnhead *)NativeAligned4FromLAddr(0x2ed600) == FuncObj) { quick_stack_check(); @@ -296,6 +289,9 @@ nextopcode: Irq_Stk_End = 0; #if defined(MAIKO_EMULATE_ASYNC_INTERRUPTS) IO_Signalled = TRUE; +#endif +#ifdef MAIKO_OS_EMSCRIPTEN + emscripten_sleep(1); #endif pseudoTimerAsyncCountdown = insnsCountdownForTimerAsyncEmulation; } From 7c1d2081c850101d41c61b1174e0296c3554e036 Mon Sep 17 00:00:00 2001 From: Nick Briggs Date: Fri, 22 Dec 2023 19:21:59 -0800 Subject: [PATCH 09/12] Ignore all wasm generated directories, lde[sdl].html has moved to src directory --- .gitignore | 1 - 1 file changed, 1 deletion(-) diff --git a/.gitignore b/.gitignore index 8e0d861..306defa 100644 --- a/.gitignore +++ b/.gitignore @@ -20,7 +20,6 @@ cmake-build-*/** *.x86_64-sdl/** *.x86_64/** *.wasm/** -!emscripten.wasm/ldesdl.html *.wasm-wasm/** *.armv7l-x/** *.armv7l/** From 7bb23936375de78eba7c9d37494bfe6787cde691 Mon Sep 17 00:00:00 2001 From: Nick Briggs Date: Wed, 27 Dec 2023 17:20:11 -0800 Subject: [PATCH 10/12] Adjustments to WAsm file system layout and compilation options Moves the full.sysout from the root of tle system to /medley/loadups/full.sysout, adds /medley/lispusers/BACKGROUND-YIELD.LCOM and an Emscripten/WAsm specific site init file at /usr/local/lde/site-init.lisp Adjusts options so that the options are in the correct place for the compiler and loader. --- bin/makefile-emscripten.wasm-wasm | 12 +++++++++--- src/lde.html | 2 +- 2 files changed, 10 insertions(+), 4 deletions(-) diff --git a/bin/makefile-emscripten.wasm-wasm b/bin/makefile-emscripten.wasm-wasm index f092375..64b631a 100644 --- a/bin/makefile-emscripten.wasm-wasm +++ b/bin/makefile-emscripten.wasm-wasm @@ -4,14 +4,20 @@ CC = emcc $(CLANG_CFLAGS) XFILES = $(OBJECTDIR)sdl.o -XFLAGS = -DSDL +XFLAGS = -DSDL -sUSE_SDL=2 # OPTFLAGS is normally -O2. -OPTFLAGS = -O2 -g3 +OPTFLAGS = -O2 DFLAGS = $(XFLAGS) -DRELEASE=351 +MEDLEY?=../../medley +SYSOUT?=$(MEDLEY)/loadups/full.sysout + LD = emcc -LDFLAGS = -sUSE_SDL=2 -sASYNCIFY -sALLOW_MEMORY_GROWTH --preload-file $(SYSOUT)@full.sysout +LDFLAGS = -sUSE_SDL=2 -sASYNCIFY -sALLOW_MEMORY_GROWTH \ + --preload-file $(SYSOUT)@medley/loadups/full.sysout \ + --preload-file $(MEDLEY)/greetfiles/EMSCRIPTEN-INIT.LCOM@usr/local/lde/site-init.lisp \ + --preload-file $(MEDLEY)/lispusers/BACKGROUND-YIELD.LCOM@medley/lispusers/BACKGROUND-YIELD.LCOM LDELDFLAGS = OBJECTDIR = ../$(RELEASENAME)/ diff --git a/src/lde.html b/src/lde.html index 3ddffcd..3c7f8cc 100644 --- a/src/lde.html +++ b/src/lde.html @@ -11,7 +11,7 @@ From 29fdf4c40be7c84acfd4f235358313daa849a06a Mon Sep 17 00:00:00 2001 From: Nick Briggs Date: Mon, 1 Jan 2024 16:58:23 -0800 Subject: [PATCH 11/12] Adapt to window geometry, set up a fake environment variable MEDLEYDIR Passes the window width/height as the requested geometry to lde at startup. Since we control the directory structure of the file-system, we can pass the known fixed location of the Medley directories in the MEDLEYDIR environment variable. Sets up the NetHub host as localhost - not currenty functional, but a WebSocket server could be added to communicate with the NetHub gateway to enable local networking from the browser version of Medley. --- src/lde.html | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/lde.html b/src/lde.html index 3c7f8cc..d429eb4 100644 --- a/src/lde.html +++ b/src/lde.html @@ -1,5 +1,6 @@ + @@ -10,8 +11,11 @@ From e93e3c895e968f21ff1e5a815f652fe37c52cd77 Mon Sep 17 00:00:00 2001 From: Nick Briggs Date: Mon, 1 Jan 2024 17:30:01 -0800 Subject: [PATCH 12/12] Update preloaded directories, allow Emscripten runtime to exit, set MAIKO_ENABLE_NETHUB Compiling with -DMAIKO_ENABLE_NETHUB makes it possible to test out having a WebSocket server that could pass packets back and forth to the Dodo NetHub. Setting Emscripten link-time option for EXIT_RUNTIME allows the runtime code to shutdown when you exit Medley via a (LOGOUT) Set up preloads for all the parts of the Medley directory that MEDLEYDIR-INIT expects to be there. The resulting ldesdl.data is (at this time) 128 MB. It can be installed gzipped if using nginx or some other web server that supports pre-zipped static files. It would be better to have these as lazy-loading files, but the setup for that is complicated. Another alternative to embedding all the data would be if a WebSocket to XNS/Nethub gateway were written and deployed. --- bin/makefile-emscripten.wasm-wasm | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) diff --git a/bin/makefile-emscripten.wasm-wasm b/bin/makefile-emscripten.wasm-wasm index 64b631a..8d88423 100644 --- a/bin/makefile-emscripten.wasm-wasm +++ b/bin/makefile-emscripten.wasm-wasm @@ -8,16 +8,25 @@ XFLAGS = -DSDL -sUSE_SDL=2 # OPTFLAGS is normally -O2. OPTFLAGS = -O2 -DFLAGS = $(XFLAGS) -DRELEASE=351 +DFLAGS = $(XFLAGS) -DRELEASE=351 -DMAIKO_ENABLE_NETHUB MEDLEY?=../../medley SYSOUT?=$(MEDLEY)/loadups/full.sysout LD = emcc -LDFLAGS = -sUSE_SDL=2 -sASYNCIFY -sALLOW_MEMORY_GROWTH \ +LDFLAGS = -sUSE_SDL=2 -sASYNCIFY -sALLOW_MEMORY_GROWTH -sEXIT_RUNTIME=1 \ --preload-file $(SYSOUT)@medley/loadups/full.sysout \ - --preload-file $(MEDLEY)/greetfiles/EMSCRIPTEN-INIT.LCOM@usr/local/lde/site-init.lisp \ - --preload-file $(MEDLEY)/lispusers/BACKGROUND-YIELD.LCOM@medley/lispusers/BACKGROUND-YIELD.LCOM + --preload-file $(MEDLEY)/loadups/whereis.hash@medley/loadups/whereis.hash \ + --preload-file $(MEDLEY)/greetfiles/MEDLEYDIR-INIT.LCOM@usr/local/lde/site-init.lisp \ + --preload-file $(MEDLEY)/docs/@medley/docs \ + --preload-file $(MEDLEY)/doctools/@medley/doctools \ + --preload-file $(MEDLEY)/greetfiles/@medley/greetfiles \ + --preload-file $(MEDLEY)/internal/@medley/internal \ + --preload-file $(MEDLEY)/sources/@medley/sources \ + --preload-file $(MEDLEY)/library/@medley/library \ + --preload-file $(MEDLEY)/lispusers/@medley/lispusers \ + --preload-file $(MEDLEY)/fonts/@medley/fonts + LDELDFLAGS = OBJECTDIR = ../$(RELEASENAME)/