-
Notifications
You must be signed in to change notification settings - Fork 242
Adding Embedded Linux platform #1480
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Open
linfan68
wants to merge
10
commits into
Moddable-OpenSource:public
Choose a base branch
from
linfan68:linemb-demo
base: public
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Open
Changes from all commits
Commits
Show all changes
10 commits
Select commit
Hold shift + click to select a range
90e1336
Linux Embeded demo
2b384fe
Merge branch 'Moddable-OpenSource:public' into linemb-demo
linfan68 f5aec72
adding linemb support and documents
2c2dba0
Guide for handling "module not found" issue. And add support for test…
6652284
using fxPrepareMachine
faeec84
Fixed busy waiting issue by using blocked g_main_context_iteration() …
b345ce5
Merge remote-tracking branch 'origin/public' into linemb-demo
63a8c40
move "strip": [] into manifest_base.json
d092525
using strsignal()
71209e5
typo in linemb.md
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,14 @@ | ||
{ | ||
"modules": { | ||
"*": [ | ||
"$(MODULES)/base/timer/*" | ||
, "$(MODULES)/base/timer/lin/*" | ||
, "$(MODULES)/base/time/*" | ||
, "$(MODULES)/base/time/lin/*" | ||
] | ||
}, | ||
"preload": [ | ||
"timer", | ||
"time" | ||
] | ||
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,220 @@ | ||
#include "xsAll.h" | ||
#include "mc.xs.h" | ||
#include "xs.h" | ||
#include "xsAll.h" | ||
#include "xsHost.h" | ||
#include <fcntl.h> | ||
#include <unistd.h> | ||
#include <execinfo.h> // Add header file for retrieving call stack | ||
#include <signal.h> // Add header file for signal handling | ||
#include <pthread.h> // Add pthread header file | ||
#include <string.h> // Add string.h for strsignal | ||
|
||
#define ITERATION_TIMEOUT_US 5000000 // Set 5 second timeout threshold | ||
#define FATAL_ERROR_TOKEN "\n\n!!!FATAL ERROR!!!\n\n" | ||
extern txPreparation *xsPreparation; | ||
|
||
// Use thread-local storage to save txMachine pointer | ||
static __thread txMachine *gxMachine = NULL; | ||
|
||
#if mxInstrument | ||
gboolean on_instrumentation_timeout(gpointer data) | ||
{ | ||
// Execute your code here | ||
// Return TRUE if you want to continue calling, or FALSE if you want to stop after executing once | ||
txMachine *the = (void *)data; | ||
fxSampleInstrumentation(the, 0, NULL); | ||
// Reset | ||
the->garbageCollectionCount = 0; | ||
the->stackPeak = the->stack; | ||
the->peakParserSize = 0; | ||
the->floatingPointOps = 0; | ||
the->promisesSettledCount = 0; | ||
|
||
return TRUE; // Continue calling | ||
} | ||
#endif | ||
|
||
// Modify dump_js_stack function, add thread check | ||
void dump_js_stack(txMachine* the) { | ||
fprintf(stderr, "JavaScript stack trace:\n"); | ||
txSlot *aFrame = the->frame; | ||
while (aFrame) { | ||
char name[128] = ""; | ||
fxBufferFrameName(the, name, sizeof(name), aFrame, ""); | ||
|
||
txSlot* environment = mxFrameToEnvironment(aFrame); | ||
if (environment->ID != XS_NO_ID) | ||
printf("%s: %s:%d\n", name, fxGetKeyName(the, environment->ID), environment->value.environment.line); | ||
else | ||
printf("%s\n", name); | ||
|
||
aFrame = aFrame->next; | ||
} | ||
} | ||
|
||
static void fatal_error_exit() { | ||
void *buffer[50]; | ||
int nptrs = backtrace(buffer, 50); | ||
char **strings = backtrace_symbols(buffer, nptrs); | ||
printf("==== Native stack trace: =====\n"); | ||
for (int i = 0; i < nptrs; i++) | ||
{ | ||
printf("%s\n", strings[i]); | ||
} | ||
free(strings); | ||
printf("==============================\n"); | ||
printf(FATAL_ERROR_TOKEN); | ||
|
||
signal(SIGQUIT, SIG_DFL); | ||
exit(1); | ||
} | ||
|
||
static void fatal_error_handler(int signum) { | ||
|
||
printf("!!!! Signal %s (%d) caught. Stack trace:\n", strsignal(signum), signum); | ||
// Reset signal handler to allow default behavior to terminate program | ||
signal(signum, SIG_DFL); | ||
fatal_error_exit(); | ||
} | ||
|
||
// Modified: Unified signal handling function | ||
static void signal_handler(int signum) { | ||
fatal_error_handler(signum); | ||
} | ||
|
||
static void timeout_handler(int signum) { | ||
if (gxMachine) { | ||
printf("!!!! Execution timeout !!!!\n"); | ||
dump_js_stack(gxMachine); | ||
fatal_error_exit(); | ||
} | ||
} | ||
|
||
int main(int argc, char *argv[]) { | ||
// Use setvbuf to disable buffering | ||
setvbuf(stdout, NULL, _IONBF, 0); | ||
setvbuf(stderr, NULL, _IONBF, 0); | ||
|
||
// Register all signals to be captured | ||
signal(SIGABRT, signal_handler); | ||
signal(SIGFPE, signal_handler); | ||
signal(SIGILL, signal_handler); | ||
signal(SIGQUIT, signal_handler); | ||
signal(SIGSEGV, signal_handler); | ||
signal(SIGTERM, signal_handler); | ||
signal(SIGBUS, signal_handler); | ||
signal(SIGPIPE, signal_handler); | ||
signal(SIGALRM, timeout_handler); // Used for timeout | ||
|
||
int error = 0; | ||
txPreparation *preparation = xsPreparation(); | ||
|
||
txMachine *the = fxPrepareMachine(NULL, preparation, "linemb", NULL, NULL); | ||
|
||
setvbuf(stdout, NULL, _IONBF, 0); | ||
|
||
gxMachine = the; // Save to thread-local storage | ||
#if mxInstrument | ||
fxDescribeInstrumentation(the, 0, NULL, NULL); | ||
#endif | ||
xsBeginHost(the); | ||
{ | ||
xsVars(2); | ||
{ | ||
// XS: set global string array argv, and put input string into it | ||
xsTry | ||
{ | ||
xsResult = xsNewArray(0); | ||
xsSet(xsGlobal, xsID("argv"), xsResult); | ||
for (int i = 0; i < argc; i++) | ||
{ | ||
xsVar(0) = xsString(argv[i]); | ||
xsCall1(xsResult, xsID("push"), xsVar(0)); | ||
} | ||
} | ||
xsCatch | ||
{ | ||
xsStringValue message = xsToString(xsException); | ||
fprintf(stderr, "### %s\n", message); | ||
error = 1; | ||
} | ||
} | ||
{ | ||
xsResult = xsAwaitImport("main", XS_IMPORT_NAMESPACE); | ||
} | ||
} | ||
xsEndHost(the); | ||
|
||
// Start event loop | ||
GMainContext *main_context = g_main_context_default(); | ||
g_main_loop_new(main_context, FALSE); | ||
|
||
#if mxInstrument | ||
g_timeout_add_seconds(1, on_instrumentation_timeout, (void *)the); | ||
#endif | ||
|
||
// g_main_loop_run(main_loop); | ||
while (TRUE) | ||
{ | ||
// Set timer: trigger SIGALRM on timeout | ||
struct itimerval timer; | ||
timer.it_value.tv_sec = ITERATION_TIMEOUT_US / 1000000; | ||
timer.it_value.tv_usec = ITERATION_TIMEOUT_US % 1000000; | ||
timer.it_interval.tv_sec = 0; | ||
timer.it_interval.tv_usec = 0; | ||
setitimer(ITIMER_REAL, &timer, NULL); | ||
|
||
// Process one event blocking | ||
g_main_context_iteration(NULL, TRUE); | ||
|
||
// Disable timer | ||
timer.it_value.tv_sec = 0; | ||
timer.it_value.tv_usec = 0; | ||
setitimer(ITIMER_REAL, &timer, NULL); | ||
} | ||
|
||
xsDeleteMachine(the); | ||
|
||
return error; | ||
} | ||
|
||
|
||
void fxAbort(xsMachine *the, int status) | ||
{ | ||
xsStringValue msg = (char*)fxAbortString(status); | ||
#if MODDEF_XS_ABORTHOOK | ||
if ((XS_JAVASCRIPT_STACK_OVERFLOW_EXIT != status) && (XS_NATIVE_STACK_OVERFLOW_EXIT != status) & (XS_DEBUGGER_EXIT != status)) { | ||
xsBooleanValue ignore = false; | ||
|
||
fxBeginHost(the); | ||
{ | ||
mxPush(mxException); | ||
txSlot *exception = the->stack; | ||
mxException = xsUndefined; | ||
mxTry(the) { | ||
txID abortID = fxFindName(the, "abort"); | ||
mxOverflow(-8); | ||
mxPush(mxGlobal); | ||
if (fxHasID(the, abortID)) { | ||
mxPush(mxGlobal); | ||
fxCallID(the, abortID); | ||
mxPushStringC((char *)msg); | ||
mxPushSlot(exception); | ||
fxRunCount(the, 2); | ||
ignore = (XS_BOOLEAN_KIND == the->stack->kind) && !the->stack->value.boolean; | ||
mxPop(); | ||
} | ||
} | ||
mxCatch(the) { | ||
} | ||
} | ||
fxEndHost(the); | ||
if (ignore) | ||
return; | ||
} | ||
#endif | ||
xsLog("XS abort: %s\n", msg); | ||
|
||
fatal_error_exit(); | ||
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,129 @@ | ||
# Using the Moddable SDK with embedded Linux (Raspberry Pi Zero) | ||
This is a demo document to demostrate how to bring up an embedded Linux device with the Moddable SDK. | ||
|
||
# Prepare | ||
check the general get started guide [Moddable SDK - Getting Started](../Moddable SDK - Getting Started.md) | ||
Notice this is only tested with Ubuntu 22.04 for the host machine. | ||
|
||
Key steps: | ||
```bash | ||
sudo | ||
export MODDABLE=[your moddalbe root folder] | ||
export PATH=$PATH:$MODDABLE/build/bin/lin/release | ||
cd $MODDABLE/build/makefiles/lin | ||
make | ||
``` | ||
|
||
# Install toolchain | ||
There are several CPU types supported. Use the following commands to install the corresponding toolchain: | ||
|
||
## ARM(32-bit) - armhf | ||
```bash | ||
sudo apt-get update | ||
sudo apt-get install gcc-arm-linux-gnueabihf g++-arm-linux-gnueabihf | ||
``` | ||
|
||
## ARM(64-bit) - arm64 | ||
```bash | ||
sudo apt-get update | ||
sudo apt-get install gcc-aarch64-linux-gnu g++-aarch64-linux-gnu | ||
``` | ||
|
||
## amd64(x86_64, the host) - x86_64 | ||
```bash | ||
sudo apt-get install build-essential | ||
``` | ||
|
||
# Sample project | ||
Below are the build commands for different CPU types: | ||
|
||
## x86_64 example | ||
```bash | ||
cd $MODDABLE/examples/helloworld | ||
mcconfig -d -m -p linemb/x86_64 | ||
``` | ||
|
||
The generated executable can be found at: | ||
`$MODDABLE/build/bin/linemb/x86_64/debug/helloworld/helloworld` | ||
|
||
## Running on ARM devices | ||
### ARM(32-bit) | ||
```bash | ||
cd $MODDABLE/examples/helloworld | ||
mcconfig -d -m -p linemb/armhf | ||
``` | ||
|
||
The generated executable can be found at: | ||
`$MODDABLE/build/bin/linemb/armhf/debug/helloworld/helloworld` | ||
|
||
### ARM(64-bit) | ||
```bash | ||
cd $MODDABLE/examples/helloworld | ||
mcconfig -d -m -p linemb/arm64 | ||
``` | ||
|
||
The generated executable can be found at: | ||
`$MODDABLE/build/bin/linemb/arm64/debug/helloworld/helloworld` | ||
|
||
### Copy to device | ||
Find a way to copy this file to the target board (e.g., using scp): | ||
|
||
```bash | ||
scp $MODDABLE/build/bin/linemb/armhf/debug/helloworld/helloworld [email protected]:/root/ | ||
``` | ||
|
||
You should see output like this: | ||
``` | ||
# ./helloworld | ||
instruments key: Chunk used,Chunk available,Slot used,Slot available,Stack used,Stack available,Garbage collections,Keys used,Modules loaded,Parser used,Floating Point,Promises settled | ||
Hello, world - sample | ||
instruments: 248,32768,2432,65504,1344,12288,0,2,1,0,0,0 | ||
instruments: 248,32768,2432,65504,416,12288,0,2,1,0,0,0 | ||
instruments: 248,32768,2432,65504,416,12288,0,2,1,0,0,0 | ||
``` | ||
|
||
# Fix "module unsupported" issue | ||
|
||
If you encounter an error like "XXX module unsupported" when using the linemb platform, it's because the module's `manifest.json` file doesn't specify a C language implementation for the linemb platform. | ||
|
||
The simplest solution is to copy the implementation from the "lin" platform. Follow these steps: | ||
|
||
1. Open the module's `manifest.json` file (e.g., `modules/files/file/manifest.json` for file module) | ||
2. Ensure the linemb platform configuration includes the module implementation, for example: | ||
|
||
```json | ||
"linemb": { | ||
"modules": { | ||
"*": "$(MODULES)/files/file/lin/*" | ||
}, | ||
"config": { | ||
"file": { | ||
"root": "/tmp/" | ||
} | ||
} | ||
} | ||
``` | ||
|
||
Please note that many modules for the `lin` platform (especially hardware-related ones) have not been thoroughly tested. It's recommended to enable modules according to your specific needs and perform adequate testing to ensure proper functionality. | ||
|
||
If you encounter issues with the `lin` platform implementation, a better approach is to create a linemb-specific implementation: | ||
|
||
1. Create a new folder for the linemb platform implementation (e.g., `modules/files/file/linemb/`) | ||
2. Implement the necessary C files specifically for the linemb platform | ||
3. Update the manifest.json to use this implementation: | ||
|
||
```json | ||
"linemb": { | ||
"modules": { | ||
"*": "$(MODULES)/files/file/linemb/*" | ||
}, | ||
"config": { | ||
"file": { | ||
"root": "/tmp/" | ||
} | ||
} | ||
} | ||
``` | ||
|
||
This approach allows you to create optimized implementations tailored to the linemb platform. | ||
|
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.