Skip to content

Commit 3551ee7

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 b3da931 commit 3551ee7

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
@@ -516,10 +516,20 @@ MP_REGISTER_ROOT_POINTER(vstr_t * repl_line);
516516

517517
#else // MICROPY_REPL_EVENT_DRIVEN
518518

519+
#if !MICROPY_HAL_HAS_STDIO_MODE_SWITCH
520+
// If the port doesn't need any stdio mode switching calls then provide trivial ones.
521+
static inline void mp_hal_stdio_mode_raw(void) {
522+
}
523+
static inline void mp_hal_stdio_mode_orig(void) {
524+
}
525+
#endif
526+
519527
int pyexec_raw_repl(void) {
520528
vstr_t line;
521529
vstr_init(&line, 32);
522530

531+
mp_hal_stdio_mode_raw();
532+
523533
raw_repl_reset:
524534
mp_hal_stdout_tx_str("raw REPL; CTRL-B to exit\r\n");
525535

@@ -533,6 +543,7 @@ int pyexec_raw_repl(void) {
533543
if (vstr_len(&line) == 2 && vstr_str(&line)[0] == CHAR_CTRL_E) {
534544
int ret = do_reader_stdin(vstr_str(&line)[1]);
535545
if (ret & PYEXEC_FORCED_EXIT) {
546+
mp_hal_stdio_mode_orig();
536547
return ret;
537548
}
538549
vstr_reset(&line);
@@ -545,6 +556,7 @@ int pyexec_raw_repl(void) {
545556
mp_hal_stdout_tx_str("\r\n");
546557
vstr_clear(&line);
547558
pyexec_mode_kind = PYEXEC_MODE_FRIENDLY_REPL;
559+
mp_hal_stdio_mode_orig();
548560
return 0;
549561
} else if (c == CHAR_CTRL_C) {
550562
// clear line
@@ -565,10 +577,19 @@ int pyexec_raw_repl(void) {
565577
// exit for a soft reset
566578
mp_hal_stdout_tx_str("\r\n");
567579
vstr_clear(&line);
580+
mp_hal_stdio_mode_orig();
568581
return PYEXEC_FORCED_EXIT;
569582
}
570583

584+
// Execute code with terminal mode switching for keyboard interrupt support.
585+
// Switches to original mode (ISIG enabled) so Ctrl-C generates SIGINT during execution,
586+
// then restores raw mode (ISIG disabled) for REPL input to support paste mode with arbitrary
587+
// data including byte 0x03 without triggering interrupts.
588+
mp_hal_stdio_mode_orig();
571589
int ret = parse_compile_execute(&line, MP_PARSE_FILE_INPUT, EXEC_FLAG_PRINT_EOF | EXEC_FLAG_SOURCE_IS_VSTR);
590+
if (!(ret & PYEXEC_FORCED_EXIT)) {
591+
mp_hal_stdio_mode_raw();
592+
}
572593
if (ret & PYEXEC_FORCED_EXIT) {
573594
return ret;
574595
}
@@ -579,6 +600,8 @@ int pyexec_friendly_repl(void) {
579600
vstr_t line;
580601
vstr_init(&line, 32);
581602

603+
mp_hal_stdio_mode_raw();
604+
582605
friendly_repl_reset:
583606
mp_hal_stdout_tx_str(MICROPY_BANNER_NAME_AND_VERSION);
584607
mp_hal_stdout_tx_str("; " MICROPY_BANNER_MACHINE);
@@ -634,6 +657,7 @@ int pyexec_friendly_repl(void) {
634657
mp_hal_stdout_tx_str("\r\n");
635658
vstr_clear(&line);
636659
pyexec_mode_kind = PYEXEC_MODE_RAW_REPL;
660+
mp_hal_stdio_mode_orig();
637661
return 0;
638662
} else if (ret == CHAR_CTRL_B) {
639663
// reset friendly REPL
@@ -647,6 +671,7 @@ int pyexec_friendly_repl(void) {
647671
// exit for a soft reset
648672
mp_hal_stdout_tx_str("\r\n");
649673
vstr_clear(&line);
674+
mp_hal_stdio_mode_orig();
650675
return PYEXEC_FORCED_EXIT;
651676
} else if (ret == CHAR_CTRL_E) {
652677
// paste mode
@@ -691,7 +716,15 @@ int pyexec_friendly_repl(void) {
691716
}
692717
}
693718

719+
// Execute code with terminal mode switching for keyboard interrupt support.
720+
// Switches to original mode (ISIG enabled) so Ctrl-C generates SIGINT during execution,
721+
// then restores raw mode (ISIG disabled) for REPL input to support paste mode with arbitrary
722+
// data including byte 0x03 without triggering interrupts.
723+
mp_hal_stdio_mode_orig();
694724
ret = parse_compile_execute(&line, parse_input_kind, EXEC_FLAG_ALLOW_DEBUGGING | EXEC_FLAG_IS_REPL | EXEC_FLAG_SOURCE_IS_VSTR);
725+
if (!(ret & PYEXEC_FORCED_EXIT)) {
726+
mp_hal_stdio_mode_raw();
727+
}
695728
if (ret & PYEXEC_FORCED_EXIT) {
696729
return ret;
697730
}

0 commit comments

Comments
 (0)