Skip to content

Commit 124df6f

Browse files
committed
py: Add mp_pending_exception global variable, for VM soft interrupt.
This allows to implement KeyboardInterrupt on unix, and a much safer ctrl-C in stmhal port. First ctrl-C is a soft one, with hope that VM will notice it; second ctrl-C is a hard one that kills anything (for both unix and stmhal). One needs to check for a pending exception in the VM only for jump opcodes. Others can't produce an infinite loop (infinite recursion is caught by stack check).
1 parent d7353fe commit 124df6f

File tree

10 files changed

+71
-14
lines changed

10 files changed

+71
-14
lines changed

py/obj.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -330,6 +330,7 @@ extern const mp_obj_type_t mp_type_GeneratorExit;
330330
extern const mp_obj_type_t mp_type_ImportError;
331331
extern const mp_obj_type_t mp_type_IndentationError;
332332
extern const mp_obj_type_t mp_type_IndexError;
333+
extern const mp_obj_type_t mp_type_KeyboardInterrupt;
333334
extern const mp_obj_type_t mp_type_KeyError;
334335
extern const mp_obj_type_t mp_type_LookupError;
335336
extern const mp_obj_type_t mp_type_MemoryError;

py/objexcept.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -211,7 +211,7 @@ const mp_obj_type_t mp_type_ ## exc_name = { \
211211
// http://docs.python.org/3/library/exceptions.html
212212
MP_DEFINE_EXCEPTION_BASE(BaseException)
213213
MP_DEFINE_EXCEPTION(SystemExit, BaseException)
214-
//MP_DEFINE_EXCEPTION(KeyboardInterrupt, BaseException)
214+
MP_DEFINE_EXCEPTION(KeyboardInterrupt, BaseException)
215215
MP_DEFINE_EXCEPTION(GeneratorExit, BaseException)
216216
MP_DEFINE_EXCEPTION(Exception, BaseException)
217217
MP_DEFINE_EXCEPTION_BASE(Exception)

py/qstrdefs.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -108,6 +108,7 @@ Q(GeneratorExit)
108108
Q(ImportError)
109109
Q(IndentationError)
110110
Q(IndexError)
111+
Q(KeyboardInterrupt)
111112
Q(KeyError)
112113
Q(LookupError)
113114
Q(MemoryError)

py/runtime.c

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,9 @@
6262
#define DEBUG_OP_printf(...) (void)0
6363
#endif
6464

65+
// pending exception object (MP_OBJ_NULL if not pending)
66+
mp_obj_t mp_pending_exception;
67+
6568
// locals and globals need to be pointers because they can be the same in outer module scope
6669
STATIC mp_obj_dict_t *dict_locals;
6770
STATIC mp_obj_dict_t *dict_globals;
@@ -79,6 +82,9 @@ void mp_init(void) {
7982
qstr_init();
8083
mp_stack_ctrl_init();
8184

85+
// no pending exceptions to start with
86+
mp_pending_exception = MP_OBJ_NULL;
87+
8288
#if MICROPY_ENABLE_EMERGENCY_EXCEPTION_BUF
8389
mp_init_emergency_exception_buf();
8490
#endif

py/runtime.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -116,6 +116,7 @@ mp_obj_t mp_convert_native_to_obj(mp_uint_t val, mp_uint_t type);
116116
mp_obj_t mp_native_call_function_n_kw(mp_obj_t fun_in, mp_uint_t n_args_kw, const mp_obj_t *args);
117117
NORETURN void mp_native_raise(mp_obj_t o);
118118

119+
extern mp_obj_t mp_pending_exception;
119120
extern struct _mp_obj_list_t mp_sys_path_obj;
120121
extern struct _mp_obj_list_t mp_sys_argv_obj;
121122
#define mp_sys_path ((mp_obj_t)&mp_sys_path_obj)

py/vm.c

Lines changed: 17 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -110,10 +110,12 @@ mp_vm_return_kind_t mp_execute_bytecode(mp_code_state *code_state, volatile mp_o
110110
code_state->ip = ip; \
111111
goto *entry_table[*ip++]; \
112112
} while(0)
113+
#define DISPATCH_WITH_PEND_EXC_CHECK() goto pending_exception_check
113114
#define ENTRY(op) entry_##op
114115
#define ENTRY_DEFAULT entry_default
115116
#else
116117
#define DISPATCH() break
118+
#define DISPATCH_WITH_PEND_EXC_CHECK() goto pending_exception_check
117119
#define ENTRY(op) case op
118120
#define ENTRY_DEFAULT default
119121
#endif
@@ -372,21 +374,21 @@ mp_vm_return_kind_t mp_execute_bytecode(mp_code_state *code_state, volatile mp_o
372374
ENTRY(MP_BC_JUMP):
373375
DECODE_SLABEL;
374376
ip += unum;
375-
DISPATCH();
377+
DISPATCH_WITH_PEND_EXC_CHECK();
376378

377379
ENTRY(MP_BC_POP_JUMP_IF_TRUE):
378380
DECODE_SLABEL;
379381
if (mp_obj_is_true(POP())) {
380382
ip += unum;
381383
}
382-
DISPATCH();
384+
DISPATCH_WITH_PEND_EXC_CHECK();
383385

384386
ENTRY(MP_BC_POP_JUMP_IF_FALSE):
385387
DECODE_SLABEL;
386388
if (!mp_obj_is_true(POP())) {
387389
ip += unum;
388390
}
389-
DISPATCH();
391+
DISPATCH_WITH_PEND_EXC_CHECK();
390392

391393
ENTRY(MP_BC_JUMP_IF_TRUE_OR_POP):
392394
DECODE_SLABEL;
@@ -395,7 +397,7 @@ mp_vm_return_kind_t mp_execute_bytecode(mp_code_state *code_state, volatile mp_o
395397
} else {
396398
sp--;
397399
}
398-
DISPATCH();
400+
DISPATCH_WITH_PEND_EXC_CHECK();
399401

400402
ENTRY(MP_BC_JUMP_IF_FALSE_OR_POP):
401403
DECODE_SLABEL;
@@ -404,7 +406,7 @@ mp_vm_return_kind_t mp_execute_bytecode(mp_code_state *code_state, volatile mp_o
404406
} else {
405407
ip += unum;
406408
}
407-
DISPATCH();
409+
DISPATCH_WITH_PEND_EXC_CHECK();
408410

409411
ENTRY(MP_BC_SETUP_WITH): {
410412
mp_obj_t obj = TOP();
@@ -502,7 +504,7 @@ mp_vm_return_kind_t mp_execute_bytecode(mp_code_state *code_state, volatile mp_o
502504
if (unum != 0) {
503505
sp--;
504506
}
505-
DISPATCH();
507+
DISPATCH_WITH_PEND_EXC_CHECK();
506508

507509
// matched against: POP_BLOCK or POP_EXCEPT (anything else?)
508510
ENTRY(MP_BC_SETUP_EXCEPT):
@@ -909,6 +911,15 @@ mp_vm_return_kind_t mp_execute_bytecode(mp_code_state *code_state, volatile mp_o
909911
#if !MICROPY_OPT_COMPUTED_GOTO
910912
} // switch
911913
#endif
914+
915+
pending_exception_check:
916+
if (mp_pending_exception != MP_OBJ_NULL) {
917+
mp_obj_t obj = mp_pending_exception;
918+
mp_pending_exception = MP_OBJ_NULL;
919+
RAISE(obj);
920+
}
921+
DISPATCH();
922+
912923
} // for loop
913924

914925
} else {

stmhal/pendsv.c

Lines changed: 16 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@
3131
#include "misc.h"
3232
#include "qstr.h"
3333
#include "obj.h"
34+
#include "runtime.h"
3435
#include "pendsv.h"
3536

3637
static void *pendsv_object = NULL;
@@ -40,12 +41,22 @@ void pendsv_init(void) {
4041
HAL_NVIC_SetPriority(PendSV_IRQn, 0xf, 0xf);
4142
}
4243

43-
// call this function to raise a pending exception during an interrupt
44-
// it will wait until all interrupts are finished then raise the given
45-
// exception object using nlr_jump in the context of the top-level thread
44+
// Call this function to raise a pending exception during an interrupt.
45+
// It will first try to raise the exception "softly" by setting the
46+
// mp_pending_exception variable and hoping that the VM will notice it.
47+
// If this function is called a second time (ie with the mp_pending_exception
48+
// variable already set) then it will force the exception by using the hardware
49+
// PENDSV feature. This will wait until all interrupts are finished then raise
50+
// the given exception object using nlr_jump in the context of the top-level
51+
// thread.
4652
void pendsv_nlr_jump(void *o) {
47-
pendsv_object = o;
48-
SCB->ICSR = SCB_ICSR_PENDSVSET_Msk;
53+
if (mp_pending_exception == MP_OBJ_NULL) {
54+
mp_pending_exception = o;
55+
} else {
56+
mp_pending_exception = MP_OBJ_NULL;
57+
pendsv_object = o;
58+
SCB->ICSR = SCB_ICSR_PENDSVSET_Msk;
59+
}
4960
}
5061

5162
// since we play tricks with the stack, the compiler must not generate a

stmhal/usb.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,7 @@ STATIC mp_obj_t mp_const_vcp_interrupt = MP_OBJ_NULL;
5050

5151
void pyb_usb_init0(void) {
5252
// create an exception object for interrupting by VCP
53-
mp_const_vcp_interrupt = mp_obj_new_exception_msg(&mp_type_OSError, "VCPInterrupt");
53+
mp_const_vcp_interrupt = mp_obj_new_exception(&mp_type_KeyboardInterrupt);
5454
USBD_CDC_SetInterrupt(VCP_CHAR_NONE, mp_const_vcp_interrupt);
5555
}
5656

stmhal/usbd_cdc_interface.c

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -374,7 +374,6 @@ static int8_t CDC_Itf_Receive(uint8_t* Buf, uint32_t *Len) {
374374

375375
if (char_found) {
376376
// raise exception when interrupts are finished
377-
user_interrupt_char = VCP_CHAR_NONE;
378377
pendsv_nlr_jump(user_interrupt_data);
379378
}
380379

unix/main.c

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@
3434
#include <sys/stat.h>
3535
#include <sys/types.h>
3636
#include <errno.h>
37+
#include <signal.h>
3738

3839
#include "mpconfig.h"
3940
#include "nlr.h"
@@ -64,6 +65,20 @@ mp_uint_t mp_verbose_flag = 0;
6465
long heap_size = 128*1024 * (sizeof(mp_uint_t) / 4);
6566
#endif
6667

68+
STATIC mp_obj_t keyboard_interrupt_obj;
69+
70+
STATIC void sighandler(int signum) {
71+
if (signum == SIGINT) {
72+
mp_obj_exception_clear_traceback(keyboard_interrupt_obj);
73+
mp_pending_exception = keyboard_interrupt_obj;
74+
// disable our handler so next we really die
75+
struct sigaction sa;
76+
sa.sa_handler = SIG_DFL;
77+
sigemptyset(&sa.sa_mask);
78+
sigaction(SIGINT, &sa, NULL);
79+
}
80+
}
81+
6782
#define FORCED_EXIT (0x100)
6883
// returns standard error codes: 0 for success, 1 for all other errors
6984
// if FORCED_EXIT bit is set then script raised SystemExit and the
@@ -119,14 +134,23 @@ STATIC int execute_from_lexer(mp_lexer_t *lex, mp_parse_input_kind_t input_kind,
119134
return 0;
120135
}
121136

137+
// enable signal handler
138+
struct sigaction sa;
139+
sa.sa_handler = sighandler;
140+
sigemptyset(&sa.sa_mask);
141+
sigaction(SIGINT, &sa, NULL);
142+
sa.sa_handler = SIG_DFL;
143+
122144
// execute it
123145
nlr_buf_t nlr;
124146
if (nlr_push(&nlr) == 0) {
125147
mp_call_function_0(module_fun);
148+
sigaction(SIGINT, &sa, NULL);
126149
nlr_pop();
127150
return 0;
128151
} else {
129152
// uncaught exception
153+
sigaction(SIGINT, &sa, NULL);
130154
// check for SystemExit
131155
mp_obj_t exc = (mp_obj_t)nlr.ret_val;
132156
if (mp_obj_is_subclass_fast(mp_obj_get_type(exc), &mp_type_SystemExit)) {
@@ -305,6 +329,9 @@ int main(int argc, char **argv) {
305329

306330
mp_init();
307331

332+
// create keyboard interrupt object
333+
keyboard_interrupt_obj = mp_obj_new_exception(&mp_type_KeyboardInterrupt);
334+
308335
char *home = getenv("HOME");
309336
char *path = getenv("MICROPYPATH");
310337
if (path == NULL) {

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy