@@ -182,8 +182,10 @@ const signals = {
182182} ;
183183
184184const sigtrap_codes = {
185- BLINK_PREEMPT : 40 ,
186- BLINK_STEP : 41 ,
185+ BLINK_SIGTRAP : 0 ,
186+ BLINK_PREEMPT : 40 ,
187+ BLINK_STEP : 41 ,
188+ BLINK_FAKE_TTY : 42 ,
187189} ;
188190
189191const signals_info = {
@@ -253,6 +255,7 @@ export class Blink {
253255 LINKING : "LINKING" ,
254256 PROGRAM_LOADED : "PROGRAM_LOADED" ,
255257 PROGRAM_RUNNING : "PROGRAM_RUNNING" ,
258+ PROGRAM_READLINE_PAUSE : "PROGRAM_READLINE_PAUSE" ,
256259 PROGRAM_STOPPED : "PROGRAM_STOPPED" ,
257260 } as const ;
258261
@@ -279,6 +282,9 @@ export class Blink {
279282 //assembler diagnostic errors
280283 assembler_errors = [ ] ;
281284
285+ //fake TTY readline
286+ stdin_bytes = [ ] ;
287+
282288 /**
283289 * Initialize the emscripten blink module.
284290 */
@@ -306,7 +312,22 @@ export class Blink {
306312 noInitialRun : true ,
307313 preRun : ( M : any ) => {
308314 M . FS . init (
309- this . #stdinHandler,
315+ ( ) => {
316+ //stdin read
317+
318+ // TODO: use this when in pipe mode.
319+ // right now, libblink supports only
320+ // a fake TTY mode for reading input
321+ // return this.#stdinHandler()
322+
323+ // Fake tty mode: return the data that was inserted via
324+ // blink.readLineEnter(string)
325+ if ( this . stdin_bytes . length ) {
326+ return this . stdin_bytes . pop ( )
327+ } else {
328+ return null //EOF
329+ }
330+ } ,
310331 ( charcode : number ) => {
311332 this . #assembler_logcollector( charcode ) ;
312333 this . #stdoutHandler( charcode ) ;
@@ -389,14 +410,23 @@ export class Blink {
389410 }
390411
391412 /**
392- * This callback is called from the wasm code
393- * when the guest process is stopped by a terminating signal
413+ * This callback is called from the wasm code when
414+ * the guest process is stopped/paused by a signal
415+ *
416+ * If this callback got called, the execution loop
417+ * emulating the cpu on the wasm side is no longer
418+ * running.
394419 *
395- * SIGTRAP is the only signal that does not indicate
420+ * SIGTRAP is the only signal that doesnt indicate
396421 * a program stop.
422+ * SIGTRAP is not necessarily a real POSIX SIGTRAP
423+ * There is an additional code parameter passed to
424+ * the callback, which indicates the actual reason
425+ * for the program pause.
397426 */
398427 #extern_c__signal_callback( sig : number , code : number ) {
399- if ( sig !== signals . SIGTRAP ) {
428+ // signals != SIGTRAP ---> program exit
429+ if ( sig !== signals . SIGTRAP ) {
400430 const exitCode = 128 + sig ;
401431 let details = `Program terminated with Exit(${ exitCode } ) Due to signal ${ sig } ` ;
402432 if ( Object . prototype . hasOwnProperty . call ( signals_info , sig ) ) {
@@ -406,23 +436,34 @@ export class Blink {
406436 }
407437 this . stopReason = {
408438 loadFail : false ,
409- exitCode : exitCode ,
410- details : details ,
411- } ;
412- this . #setState( this . states . PROGRAM_STOPPED ) ;
413- this . #signalHandler( sig , code ) ;
414- } else if (
415- sig === signals . SIGTRAP &&
416- code === sigtrap_codes . BLINK_PREEMPT
417- ) {
418- console . log ( "preempt" ) ;
419- requestAnimationFrame ( ( ) => {
420- this . Module . _blinkenlib_preempt_resume ( ) ;
421- } ) ;
422- } else {
423- this . #signalHandler( sig , code ) ;
424- }
425- }
439+ exitCode : exitCode ,
440+ details : details ,
441+ } ;
442+ this . #setState( this . states . PROGRAM_STOPPED ) ;
443+ this . #signalHandler( sig , code ) ;
444+ return ;
445+ }
446+
447+ // fake SIGTRAP. it actually indicates preemption.
448+ // The emulator paused to free the js event loop.
449+ if ( code === sigtrap_codes . BLINK_PREEMPT ) {
450+ console . log ( "preempt" ) ;
451+ requestAnimationFrame ( ( ) => {
452+ this . Module . _blinkenlib_preempt_resume ( ) ;
453+ } ) ;
454+ }
455+ // fake SIGTRAP: it actually indicates a tty line read.
456+ // Emulator paused on a read syscall, waiting for
457+ // the user to enter one line on the fake js tty.
458+ else if ( code === sigtrap_codes . BLINK_FAKE_TTY ) {
459+ this . #setState( this . states . PROGRAM_READLINE_PAUSE ) ;
460+ this . #signalHandler( sig , code ) ;
461+ }
462+ // an actual SIGTRAP
463+ else {
464+ this . #signalHandler( sig , code ) ;
465+ }
466+ }
426467
427468 /**
428469 * This callback is called from the wasm code
@@ -670,6 +711,19 @@ export class Blink {
670711 }
671712 }
672713
714+ readLineEnter ( line : string ) {
715+ //Note: validation should be handled on the UI side,
716+ //e.g.: if user enters an emoji, a message shoul appear
717+ //explaining the implications of that - multiple bytes,
718+ //utf-8 encoding, need to manually handle that in the
719+ //assembly side, etc.
720+ //Note: the bytes are stored in reverse order.
721+ //the stdin handler will pop bytes from this array.
722+ this . stdin_bytes = Array . from ( new TextEncoder ( ) . encode ( line ) ) . reverse ( ) ;
723+ this . #setState( this . states . PROGRAM_RUNNING ) ;
724+ this . Module . _blinkenlib_faketty_resume ( ) ;
725+ }
726+
673727 stepi ( ) {
674728 this . Module . _blinkenlib_stepi ( ) ;
675729 }
0 commit comments