1+ #include "xsAll.h"
2+ #include "mc.xs.h"
3+ #include "xs.h"
4+ #include "xsAll.h"
5+ #include "xsHost.h"
6+ #include <fcntl.h>
7+ #include <unistd.h>
8+ #include <execinfo.h> // Add header file for retrieving call stack
9+ #include <signal.h> // Add header file for signal handling
10+ #include <pthread.h> // Add pthread header file
11+
12+ #define ITERATION_TIMEOUT_US 5000000 // Set 5 second timeout threshold
13+ #define FATAL_ERROR_TOKEN "\n\n!!!FATAL ERROR!!!\n\n"
14+ extern txPreparation * xsPreparation ;
15+
16+ // Use thread-local storage to save txMachine pointer
17+ static __thread txMachine * gxMachine = NULL ;
18+
19+ #if mxInstrument
20+ gboolean on_instrumentation_timeout (gpointer data )
21+ {
22+ // Execute your code here
23+ // Return TRUE if you want to continue calling, or FALSE if you want to stop after executing once
24+ txMachine * the = (void * )data ;
25+ fxSampleInstrumentation (the , 0 , NULL );
26+ // Reset
27+ the -> garbageCollectionCount = 0 ;
28+ the -> stackPeak = the -> stack ;
29+ the -> peakParserSize = 0 ;
30+ the -> floatingPointOps = 0 ;
31+ the -> promisesSettledCount = 0 ;
32+
33+ return TRUE; // Continue calling
34+ }
35+ #endif
36+
37+ // Modify dump_js_stack function, add thread check
38+ void dump_js_stack (txMachine * the ) {
39+ fprintf (stderr , "JavaScript stack trace:\n" );
40+ txSlot * aFrame = the -> frame ;
41+ while (aFrame ) {
42+ char name [128 ] = "" ;
43+ fxBufferFrameName (the , name , sizeof (name ), aFrame , "" );
44+
45+ txSlot * environment = mxFrameToEnvironment (aFrame );
46+ if (environment -> ID != XS_NO_ID )
47+ printf ("%s: %s:%d\n" , name , fxGetKeyName (the , environment -> ID ), environment -> value .environment .line );
48+ else
49+ printf ("%s\n" , name );
50+
51+ aFrame = aFrame -> next ;
52+ }
53+ }
54+
55+ static void fatal_error_exit () {
56+ void * buffer [50 ];
57+ int nptrs = backtrace (buffer , 50 );
58+ char * * strings = backtrace_symbols (buffer , nptrs );
59+ printf ("==== Native stack trace: =====\n" );
60+ for (int i = 0 ; i < nptrs ; i ++ )
61+ {
62+ printf ("%s\n" , strings [i ]);
63+ }
64+ free (strings );
65+ printf ("==============================\n" );
66+ printf (FATAL_ERROR_TOKEN );
67+
68+ signal (SIGQUIT , SIG_DFL );
69+ exit (1 );
70+ }
71+
72+ static void fatal_error_handler (int signum ) {
73+ const char * signame = "UNKNOWN" ;
74+ switch (signum ) {
75+ case SIGABRT : signame = "SIGABRT" ; break ;
76+ case SIGFPE : signame = "SIGFPE" ; break ;
77+ case SIGILL : signame = "SIGILL" ; break ;
78+ case SIGINT : signame = "SIGINT" ; break ;
79+ case SIGQUIT : signame = "SIGQUIT" ; break ;
80+ case SIGSEGV : signame = "SIGSEGV" ; break ;
81+ case SIGTERM : signame = "SIGTERM" ; break ;
82+ case SIGBUS : signame = "SIGBUS" ; break ;
83+ case SIGPIPE : signame = "SIGPIPE" ; break ;
84+ }
85+
86+ printf ("!!!! Signal %s (%d) caught. Stack trace:\n" , signame , signum );
87+ // Reset signal handler to allow default behavior to terminate program
88+ signal (signum , SIG_DFL );
89+ fatal_error_exit ();
90+ }
91+
92+ // Modified: Unified signal handling function
93+ static void signal_handler (int signum ) {
94+ fatal_error_handler (signum );
95+ }
96+
97+ static void timeout_handler (int signum ) {
98+ if (gxMachine ) {
99+ printf ("!!!! Execution timeout !!!!\n" );
100+ dump_js_stack (gxMachine );
101+ fatal_error_exit ();
102+ }
103+ }
104+
105+ int main (int argc , char * argv []) {
106+ // Use setvbuf to disable buffering
107+ setvbuf (stdout , NULL , _IONBF , 0 );
108+ setvbuf (stderr , NULL , _IONBF , 0 );
109+
110+ // Register all signals to be captured
111+ signal (SIGABRT , signal_handler );
112+ signal (SIGFPE , signal_handler );
113+ signal (SIGILL , signal_handler );
114+ signal (SIGQUIT , signal_handler );
115+ signal (SIGSEGV , signal_handler );
116+ signal (SIGTERM , signal_handler );
117+ signal (SIGBUS , signal_handler );
118+ signal (SIGPIPE , signal_handler );
119+ signal (SIGALRM , timeout_handler ); // Used for timeout
120+
121+ int error = 0 ;
122+ static txMachine _root ;
123+ txMachine * the = & _root ;
124+ txPreparation * preparation = xsPreparation ();
125+
126+ c_memset (the , 0 , sizeof (txMachine ));
127+ the -> preparation = preparation ;
128+ the -> keyArray = preparation -> keys ;
129+ the -> keyCount = (txID )preparation -> keyCount + (txID )preparation -> creation .initialKeyCount ;
130+ the -> keyIndex = (txID )preparation -> keyCount ;
131+ the -> nameModulo = preparation -> nameModulo ;
132+ the -> nameTable = preparation -> names ;
133+ the -> symbolModulo = preparation -> symbolModulo ;
134+ the -> symbolTable = preparation -> symbols ;
135+
136+ the -> stack = & preparation -> stack [0 ];
137+ the -> stackBottom = & preparation -> stack [0 ];
138+ the -> stackTop = & preparation -> stack [preparation -> stackCount ];
139+
140+ the -> firstHeap = & preparation -> heap [0 ];
141+ the -> freeHeap = & preparation -> heap [preparation -> heapCount - 1 ];
142+ the -> aliasCount = (txID )preparation -> aliasCount ;
143+
144+ setvbuf (stdout , NULL , _IONBF , 0 );
145+ the = fxCloneMachine (& preparation -> creation , the , "linemb" , NULL );
146+ gxMachine = the ; // Save to thread-local storage
147+ #if mxInstrument
148+ fxDescribeInstrumentation (the , 0 , NULL , NULL );
149+ #endif
150+ xsBeginHost (the );
151+ {
152+ xsVars (2 );
153+ {
154+ // XS: set global string array argv, and put input string into it
155+ xsTry
156+ {
157+ xsResult = xsNewArray (0 );
158+ xsSet (xsGlobal , xsID ("argv" ), xsResult );
159+ for (int i = 0 ; i < argc ; i ++ )
160+ {
161+ xsVar (0 ) = xsString (argv [i ]);
162+ xsCall1 (xsResult , xsID ("push" ), xsVar (0 ));
163+ }
164+ }
165+ xsCatch
166+ {
167+ xsStringValue message = xsToString (xsException );
168+ fprintf (stderr , "### %s\n" , message );
169+ error = 1 ;
170+ }
171+ }
172+ {
173+ xsResult = xsAwaitImport ("main" , XS_IMPORT_NAMESPACE );
174+ }
175+ }
176+ xsEndHost (the );
177+
178+ // Start event loop
179+ GMainContext * main_context = g_main_context_default ();
180+ GMainLoop * main_loop = g_main_loop_new (main_context , FALSE);
181+
182+ #if mxInstrument
183+ g_timeout_add_seconds (1 , on_instrumentation_timeout , (void * )the );
184+ #endif
185+
186+ // g_main_loop_run(main_loop);
187+ int testTime = 0 ;
188+ while (TRUE)
189+ {
190+ // Set timer: trigger SIGALRM on timeout
191+ struct itimerval timer ;
192+ timer .it_value .tv_sec = ITERATION_TIMEOUT_US / 1000000 ;
193+ timer .it_value .tv_usec = ITERATION_TIMEOUT_US % 1000000 ;
194+ timer .it_interval .tv_sec = 0 ;
195+ timer .it_interval .tv_usec = 0 ;
196+ setitimer (ITIMER_REAL , & timer , NULL );
197+
198+ // Record time before event handling
199+ guint64 start = g_get_monotonic_time ();
200+ // Process one event non-blocking
201+ gboolean processed = g_main_context_iteration (NULL , FALSE);
202+ // Record time after event handling
203+ guint64 end = g_get_monotonic_time ();
204+
205+ // Disable timer
206+ timer .it_value .tv_sec = 0 ;
207+ timer .it_value .tv_usec = 0 ;
208+ setitimer (ITIMER_REAL , & timer , NULL );
209+
210+ if (processed )
211+ {
212+ // printf("process time: %" G_GUINT64_FORMAT " us\n", end - start);
213+ }
214+ }
215+
216+ xsDeleteMachine (the );
217+
218+ return error ;
219+ }
220+
221+ const char * gXSAbortStrings [] ICACHE_FLASH_ATTR = {
222+ "debugger" ,
223+ "memory full" ,
224+ "stack overflow" ,
225+ "fatal" ,
226+ "dead strip" ,
227+ "unhandled exception" ,
228+ "not enough keys" ,
229+ "too much computation" ,
230+ "unhandled rejection"
231+ };
232+
233+ void fxAbort (xsMachine * the , int status )
234+ {
235+ const char * msg = (status <= XS_UNHANDLED_REJECTION_EXIT ) ? gXSAbortStrings [status ] : "unknown" ;
236+ #if 0 // MODDEF_XS_ABORTHOOK
237+
238+ if ((XS_STACK_OVERFLOW_EXIT != status ) && (XS_DEBUGGER_EXIT != status )) {
239+ xsBooleanValue ignore = false;
240+
241+ fxBeginHost (the );
242+ {
243+ mxPush (mxException );
244+ txSlot * exception = the -> stack ;
245+ mxException = xsUndefined ;
246+ mxTry (the ) {
247+ txID abortID = fxFindName (the , "abort" );
248+ mxOverflow (-8 );
249+ mxPush (mxGlobal );
250+ if (fxHasID (the , abortID )) {
251+ mxPush (mxGlobal );
252+ fxCallID (the , abortID );
253+ mxPushStringC ((char * )msg );
254+ mxPushSlot (exception );
255+ fxRunCount (the , 2 );
256+ ignore = (XS_BOOLEAN_KIND == the -> stack -> kind ) && !the -> stack -> value .boolean ;
257+ mxPop ();
258+ }
259+ }
260+ mxCatch (the ) {
261+ }
262+ }
263+ fxEndHost (the );
264+ if (ignore )
265+ return ;
266+ }
267+ #endif
268+ printf ("Aborting with status %d, %s\n" , status , msg );
269+
270+ fatal_error_exit ();
271+ }
0 commit comments