Skip to content

Commit a2b2e9d

Browse files
dpgeorgepi-anl
authored andcommitted
shared/runtime/pyexec: Call mp_hal_stdio_mode_orig/raw as appropriate.
This ensures that ctrl-C works on the unix port when executing code at the REPL. Signed-off-by: Damien George <[email protected]>
1 parent 1e46c4c commit a2b2e9d

File tree

3 files changed

+36
-2
lines changed

3 files changed

+36
-2
lines changed

ports/unix/main.c

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -191,7 +191,6 @@ static int do_repl(void) {
191191
int ret = 0;
192192
#if MICROPY_USE_READLINE == 1
193193
// use MicroPython supplied readline based repl
194-
mp_hal_stdio_mode_raw();
195194
for (;;) {
196195
if (pyexec_mode_kind == PYEXEC_MODE_RAW_REPL) {
197196
if ((ret = pyexec_raw_repl()) != 0) {
@@ -203,7 +202,6 @@ static int do_repl(void) {
203202
}
204203
}
205204
}
206-
mp_hal_stdio_mode_orig();
207205
#else
208206
// use simple readline
209207
mp_hal_stdout_tx_str(MICROPY_BANNER_NAME_AND_VERSION);

ports/unix/mphalport.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,9 @@
4848
MP_THREAD_GIL_ENTER(); \
4949
} while (0)
5050

51+
// The port provides `mp_hal_stdio_mode_raw()` and `mp_hal_stdio_mode_orig()`.
52+
#define MICROPY_HAL_HAS_STDIO_MODE_SWITCH (1)
53+
5154
void mp_hal_set_interrupt_char(char c);
5255

5356
#define mp_hal_stdio_poll unused // this is not implemented, nor needed

shared/runtime/pyexec.c

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -537,10 +537,20 @@ MP_REGISTER_ROOT_POINTER(vstr_t * repl_line);
537537

538538
#else // MICROPY_REPL_EVENT_DRIVEN
539539

540+
#if !MICROPY_HAL_HAS_STDIO_MODE_SWITCH
541+
// If the port doesn't need any stdio mode switching calls then provide trivial ones.
542+
static inline void mp_hal_stdio_mode_raw(void) {
543+
}
544+
static inline void mp_hal_stdio_mode_orig(void) {
545+
}
546+
#endif
547+
540548
int pyexec_raw_repl(void) {
541549
vstr_t line;
542550
vstr_init(&line, 32);
543551

552+
mp_hal_stdio_mode_raw();
553+
544554
raw_repl_reset:
545555
mp_hal_stdout_tx_str("raw REPL; CTRL-B to exit\r\n");
546556

@@ -554,6 +564,7 @@ int pyexec_raw_repl(void) {
554564
if (vstr_len(&line) == 2 && vstr_str(&line)[0] == CHAR_CTRL_E) {
555565
int ret = do_reader_stdin(vstr_str(&line)[1]);
556566
if (ret & PYEXEC_FORCED_EXIT) {
567+
mp_hal_stdio_mode_orig();
557568
return ret;
558569
}
559570
vstr_reset(&line);
@@ -566,6 +577,7 @@ int pyexec_raw_repl(void) {
566577
mp_hal_stdout_tx_str("\r\n");
567578
vstr_clear(&line);
568579
pyexec_mode_kind = PYEXEC_MODE_FRIENDLY_REPL;
580+
mp_hal_stdio_mode_orig();
569581
return 0;
570582
} else if (c == CHAR_CTRL_C) {
571583
// clear line
@@ -586,10 +598,19 @@ int pyexec_raw_repl(void) {
586598
// exit for a soft reset
587599
mp_hal_stdout_tx_str("\r\n");
588600
vstr_clear(&line);
601+
mp_hal_stdio_mode_orig();
589602
return PYEXEC_FORCED_EXIT;
590603
}
591604

605+
// Execute code with terminal mode switching for keyboard interrupt support.
606+
// Switches to original mode (ISIG enabled) so Ctrl-C generates SIGINT during execution,
607+
// then restores raw mode (ISIG disabled) for REPL input to support paste mode with arbitrary
608+
// data including byte 0x03 without triggering interrupts.
609+
mp_hal_stdio_mode_orig();
592610
int ret = parse_compile_execute(&line, MP_PARSE_FILE_INPUT, EXEC_FLAG_PRINT_EOF | EXEC_FLAG_SOURCE_IS_VSTR);
611+
if (!(ret & PYEXEC_FORCED_EXIT)) {
612+
mp_hal_stdio_mode_raw();
613+
}
593614
if (ret & PYEXEC_FORCED_EXIT) {
594615
return ret;
595616
}
@@ -600,6 +621,8 @@ int pyexec_friendly_repl(void) {
600621
vstr_t line;
601622
vstr_init(&line, 32);
602623

624+
mp_hal_stdio_mode_raw();
625+
603626
friendly_repl_reset:
604627
mp_hal_stdout_tx_str(MICROPY_BANNER_NAME_AND_VERSION);
605628
mp_hal_stdout_tx_str("; " MICROPY_BANNER_MACHINE);
@@ -641,6 +664,7 @@ int pyexec_friendly_repl(void) {
641664
mp_hal_stdout_tx_str("\r\n");
642665
vstr_clear(&line);
643666
pyexec_mode_kind = PYEXEC_MODE_RAW_REPL;
667+
mp_hal_stdio_mode_orig();
644668
return 0;
645669
} else if (ret == CHAR_CTRL_B) {
646670
// reset friendly REPL
@@ -654,6 +678,7 @@ int pyexec_friendly_repl(void) {
654678
// exit for a soft reset
655679
mp_hal_stdout_tx_str("\r\n");
656680
vstr_clear(&line);
681+
mp_hal_stdio_mode_orig();
657682
return PYEXEC_FORCED_EXIT;
658683
} else if (ret == CHAR_CTRL_E) {
659684
// paste mode
@@ -698,7 +723,15 @@ int pyexec_friendly_repl(void) {
698723
}
699724
}
700725

726+
// Execute code with terminal mode switching for keyboard interrupt support.
727+
// Switches to original mode (ISIG enabled) so Ctrl-C generates SIGINT during execution,
728+
// then restores raw mode (ISIG disabled) for REPL input to support paste mode with arbitrary
729+
// data including byte 0x03 without triggering interrupts.
730+
mp_hal_stdio_mode_orig();
701731
ret = parse_compile_execute(&line, parse_input_kind, EXEC_FLAG_ALLOW_DEBUGGING | EXEC_FLAG_IS_REPL | EXEC_FLAG_SOURCE_IS_VSTR);
732+
if (!(ret & PYEXEC_FORCED_EXIT)) {
733+
mp_hal_stdio_mode_raw();
734+
}
702735
if (ret & PYEXEC_FORCED_EXIT) {
703736
return ret;
704737
}

0 commit comments

Comments
 (0)