allow exception raise inside atexit callback
This commit is contained in:
parent
1c4a6c3667
commit
bdf8bc58ed
|
@ -44,6 +44,10 @@
|
||||||
#include "lib/utils/pyexec.h"
|
#include "lib/utils/pyexec.h"
|
||||||
#include "genhdr/mpversion.h"
|
#include "genhdr/mpversion.h"
|
||||||
|
|
||||||
|
#if CIRCUITPY_ATEXIT
|
||||||
|
#include "shared-module/atexit/__init__.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
pyexec_mode_kind_t pyexec_mode_kind = PYEXEC_MODE_FRIENDLY_REPL;
|
pyexec_mode_kind_t pyexec_mode_kind = PYEXEC_MODE_FRIENDLY_REPL;
|
||||||
int pyexec_system_exit = 0;
|
int pyexec_system_exit = 0;
|
||||||
|
|
||||||
|
@ -58,6 +62,7 @@ STATIC bool repl_display_debugging_info = 0;
|
||||||
#define EXEC_FLAG_SOURCE_IS_VSTR (16)
|
#define EXEC_FLAG_SOURCE_IS_VSTR (16)
|
||||||
#define EXEC_FLAG_SOURCE_IS_FILENAME (32)
|
#define EXEC_FLAG_SOURCE_IS_FILENAME (32)
|
||||||
#define EXEC_FLAG_SOURCE_IS_READER (64)
|
#define EXEC_FLAG_SOURCE_IS_READER (64)
|
||||||
|
#define EXEC_FLAG_SOURCE_IS_ATEXIT (128)
|
||||||
|
|
||||||
// parses, compiles and executes the code in the lexer
|
// parses, compiles and executes the code in the lexer
|
||||||
// frees the lexer before returning
|
// frees the lexer before returning
|
||||||
|
@ -81,44 +86,49 @@ STATIC int parse_compile_execute(const void *source, mp_parse_input_kind_t input
|
||||||
nlr.ret_val = NULL;
|
nlr.ret_val = NULL;
|
||||||
if (nlr_push(&nlr) == 0) {
|
if (nlr_push(&nlr) == 0) {
|
||||||
mp_obj_t module_fun;
|
mp_obj_t module_fun;
|
||||||
#if MICROPY_MODULE_FROZEN_MPY
|
#if CIRCUITPY_ATEXIT
|
||||||
if (exec_flags & EXEC_FLAG_SOURCE_IS_RAW_CODE) {
|
if (!(exec_flags & EXEC_FLAG_SOURCE_IS_ATEXIT))
|
||||||
// source is a raw_code object, create the function
|
|
||||||
module_fun = mp_make_function_from_raw_code(source, MP_OBJ_NULL, MP_OBJ_NULL);
|
|
||||||
} else
|
|
||||||
#endif
|
#endif
|
||||||
{
|
{
|
||||||
#if MICROPY_ENABLE_COMPILER
|
#if MICROPY_MODULE_FROZEN_MPY
|
||||||
mp_lexer_t *lex;
|
if (exec_flags & EXEC_FLAG_SOURCE_IS_RAW_CODE) {
|
||||||
if (exec_flags & EXEC_FLAG_SOURCE_IS_VSTR) {
|
// source is a raw_code object, create the function
|
||||||
const vstr_t *vstr = source;
|
module_fun = mp_make_function_from_raw_code(source, MP_OBJ_NULL, MP_OBJ_NULL);
|
||||||
lex = mp_lexer_new_from_str_len(MP_QSTR__lt_stdin_gt_, vstr->buf, vstr->len, 0);
|
} else
|
||||||
} else if (exec_flags & EXEC_FLAG_SOURCE_IS_READER) {
|
|
||||||
lex = mp_lexer_new(MP_QSTR__lt_stdin_gt_, *(mp_reader_t *)source);
|
|
||||||
} else if (exec_flags & EXEC_FLAG_SOURCE_IS_FILENAME) {
|
|
||||||
lex = mp_lexer_new_from_file(source);
|
|
||||||
} else {
|
|
||||||
lex = (mp_lexer_t *)source;
|
|
||||||
}
|
|
||||||
// source is a lexer, parse and compile the script
|
|
||||||
qstr source_name = lex->source_name;
|
|
||||||
if (input_kind == MP_PARSE_FILE_INPUT) {
|
|
||||||
mp_store_global(MP_QSTR___file__, MP_OBJ_NEW_QSTR(source_name));
|
|
||||||
}
|
|
||||||
mp_parse_tree_t parse_tree = mp_parse(lex, input_kind);
|
|
||||||
module_fun = mp_compile(&parse_tree, source_name, exec_flags & EXEC_FLAG_IS_REPL);
|
|
||||||
// Clear the parse tree because it has a heap pointer we don't need anymore.
|
|
||||||
*((uint32_t volatile *)&parse_tree.chunk) = 0;
|
|
||||||
#else
|
|
||||||
mp_raise_msg(&mp_type_RuntimeError, MP_ERROR_TEXT("script compilation not supported"));
|
|
||||||
#endif
|
#endif
|
||||||
}
|
{
|
||||||
|
#if MICROPY_ENABLE_COMPILER
|
||||||
|
mp_lexer_t *lex;
|
||||||
|
if (exec_flags & EXEC_FLAG_SOURCE_IS_VSTR) {
|
||||||
|
const vstr_t *vstr = source;
|
||||||
|
lex = mp_lexer_new_from_str_len(MP_QSTR__lt_stdin_gt_, vstr->buf, vstr->len, 0);
|
||||||
|
} else if (exec_flags & EXEC_FLAG_SOURCE_IS_READER) {
|
||||||
|
lex = mp_lexer_new(MP_QSTR__lt_stdin_gt_, *(mp_reader_t *)source);
|
||||||
|
} else if (exec_flags & EXEC_FLAG_SOURCE_IS_FILENAME) {
|
||||||
|
lex = mp_lexer_new_from_file(source);
|
||||||
|
} else {
|
||||||
|
lex = (mp_lexer_t *)source;
|
||||||
|
}
|
||||||
|
// source is a lexer, parse and compile the script
|
||||||
|
qstr source_name = lex->source_name;
|
||||||
|
if (input_kind == MP_PARSE_FILE_INPUT) {
|
||||||
|
mp_store_global(MP_QSTR___file__, MP_OBJ_NEW_QSTR(source_name));
|
||||||
|
}
|
||||||
|
mp_parse_tree_t parse_tree = mp_parse(lex, input_kind);
|
||||||
|
module_fun = mp_compile(&parse_tree, source_name, exec_flags & EXEC_FLAG_IS_REPL);
|
||||||
|
// Clear the parse tree because it has a heap pointer we don't need anymore.
|
||||||
|
*((uint32_t volatile *)&parse_tree.chunk) = 0;
|
||||||
|
#else
|
||||||
|
mp_raise_msg(&mp_type_RuntimeError, MP_ERROR_TEXT("script compilation not supported"));
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
// If the code was loaded from a file it's likely to be running for a while so we'll long
|
// If the code was loaded from a file it's likely to be running for a while so we'll long
|
||||||
// live it and collect any garbage before running.
|
// live it and collect any garbage before running.
|
||||||
if (input_kind == MP_PARSE_FILE_INPUT) {
|
if (input_kind == MP_PARSE_FILE_INPUT) {
|
||||||
module_fun = make_obj_long_lived(module_fun, 6);
|
module_fun = make_obj_long_lived(module_fun, 6);
|
||||||
gc_collect();
|
gc_collect();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// execute code
|
// execute code
|
||||||
|
@ -126,7 +136,15 @@ STATIC int parse_compile_execute(const void *source, mp_parse_input_kind_t input
|
||||||
#if MICROPY_REPL_INFO
|
#if MICROPY_REPL_INFO
|
||||||
start = mp_hal_ticks_ms();
|
start = mp_hal_ticks_ms();
|
||||||
#endif
|
#endif
|
||||||
mp_call_function_0(module_fun);
|
#if CIRCUITPY_ATEXIT
|
||||||
|
if (exec_flags & EXEC_FLAG_SOURCE_IS_ATEXIT) {
|
||||||
|
atexit_callback_t *callback = (atexit_callback_t *)source;
|
||||||
|
mp_call_function_n_kw(callback->func, callback->n_pos, callback->n_kw, callback->args);
|
||||||
|
} else
|
||||||
|
#endif
|
||||||
|
{
|
||||||
|
mp_call_function_0(module_fun);
|
||||||
|
}
|
||||||
mp_hal_set_interrupt_char(-1); // disable interrupt
|
mp_hal_set_interrupt_char(-1); // disable interrupt
|
||||||
mp_handle_pending(true); // handle any pending exceptions (and any callbacks)
|
mp_handle_pending(true); // handle any pending exceptions (and any callbacks)
|
||||||
nlr_pop();
|
nlr_pop();
|
||||||
|
@ -741,6 +759,12 @@ int pyexec_frozen_module(const char *name, pyexec_result_t *result) {
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#if CIRCUITPY_ATEXIT
|
||||||
|
int pyexec_exit_handler(const void *source, pyexec_result_t *result) {
|
||||||
|
return parse_compile_execute(source, MP_PARSE_FILE_INPUT, EXEC_FLAG_SOURCE_IS_ATEXIT, result);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
#if MICROPY_REPL_INFO
|
#if MICROPY_REPL_INFO
|
||||||
mp_obj_t pyb_set_repl_info(mp_obj_t o_value) {
|
mp_obj_t pyb_set_repl_info(mp_obj_t o_value) {
|
||||||
repl_display_debugging_info = mp_obj_get_int(o_value);
|
repl_display_debugging_info = mp_obj_get_int(o_value);
|
||||||
|
|
|
@ -59,6 +59,10 @@ void pyexec_event_repl_init(void);
|
||||||
int pyexec_event_repl_process_char(int c);
|
int pyexec_event_repl_process_char(int c);
|
||||||
extern uint8_t pyexec_repl_active;
|
extern uint8_t pyexec_repl_active;
|
||||||
|
|
||||||
|
#if CIRCUITPY_ATEXIT
|
||||||
|
int pyexec_exit_handler(const void *source, pyexec_result_t *result);
|
||||||
|
#endif
|
||||||
|
|
||||||
#if MICROPY_REPL_INFO
|
#if MICROPY_REPL_INFO
|
||||||
mp_obj_t pyb_set_repl_info(mp_obj_t o_value);
|
mp_obj_t pyb_set_repl_info(mp_obj_t o_value);
|
||||||
MP_DECLARE_CONST_FUN_OBJ_1(pyb_set_repl_info_obj);
|
MP_DECLARE_CONST_FUN_OBJ_1(pyb_set_repl_info_obj);
|
||||||
|
|
8
main.c
8
main.c
|
@ -218,7 +218,7 @@ STATIC bool maybe_run_list(const char * const * filenames, pyexec_result_t* exec
|
||||||
mp_hal_stdout_tx_str(decompressed);
|
mp_hal_stdout_tx_str(decompressed);
|
||||||
pyexec_file(filename, exec_result);
|
pyexec_file(filename, exec_result);
|
||||||
#if CIRCUITPY_ATEXIT
|
#if CIRCUITPY_ATEXIT
|
||||||
shared_module_atexit_execute();
|
shared_module_atexit_execute(exec_result);
|
||||||
#endif
|
#endif
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -770,7 +770,11 @@ STATIC int run_repl(void) {
|
||||||
exit_code = pyexec_friendly_repl();
|
exit_code = pyexec_friendly_repl();
|
||||||
}
|
}
|
||||||
#if CIRCUITPY_ATEXIT
|
#if CIRCUITPY_ATEXIT
|
||||||
shared_module_atexit_execute();
|
pyexec_result_t result;
|
||||||
|
shared_module_atexit_execute(&result);
|
||||||
|
if (result.return_code == PYEXEC_DEEP_SLEEP) {
|
||||||
|
exit_code = PYEXEC_DEEP_SLEEP;
|
||||||
|
}
|
||||||
#endif
|
#endif
|
||||||
cleanup_after_vm(heap, MP_OBJ_SENTINEL);
|
cleanup_after_vm(heap, MP_OBJ_SENTINEL);
|
||||||
#if CIRCUITPY_STATUS_LED
|
#if CIRCUITPY_STATUS_LED
|
||||||
|
|
|
@ -28,11 +28,6 @@
|
||||||
#include "py/runtime.h"
|
#include "py/runtime.h"
|
||||||
#include "shared-module/atexit/__init__.h"
|
#include "shared-module/atexit/__init__.h"
|
||||||
|
|
||||||
typedef struct _atexit_callback_t {
|
|
||||||
size_t n_pos, n_kw;
|
|
||||||
mp_obj_t func, *args;
|
|
||||||
} atexit_callback_t;
|
|
||||||
|
|
||||||
static size_t callback_len = 0;
|
static size_t callback_len = 0;
|
||||||
static atexit_callback_t *callback = NULL;
|
static atexit_callback_t *callback = NULL;
|
||||||
|
|
||||||
|
@ -79,11 +74,18 @@ void shared_module_atexit_unregister(const mp_obj_t *func) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void shared_module_atexit_execute(void) {
|
void shared_module_atexit_execute(pyexec_result_t *result) {
|
||||||
if (callback) {
|
if (callback) {
|
||||||
for (size_t i = callback_len; i-- > 0;) {
|
for (size_t i = callback_len; i-- > 0;) {
|
||||||
if (callback[i].func != mp_const_none) {
|
if (callback[i].func != mp_const_none) {
|
||||||
mp_call_function_n_kw(callback[i].func, callback[i].n_pos, callback[i].n_kw, callback[i].args);
|
if (result != NULL) {
|
||||||
|
pyexec_result_t res;
|
||||||
|
if (pyexec_exit_handler(&callback[i], &res) == PYEXEC_DEEP_SLEEP) {
|
||||||
|
*result = res;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
pyexec_exit_handler(&callback[i], NULL);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -28,6 +28,12 @@
|
||||||
#define MICROPY_INCLUDED_SHARED_MODULE_ATEXIT___INIT___H
|
#define MICROPY_INCLUDED_SHARED_MODULE_ATEXIT___INIT___H
|
||||||
|
|
||||||
#include "py/obj.h"
|
#include "py/obj.h"
|
||||||
|
#include "lib/utils/pyexec.h"
|
||||||
|
|
||||||
|
typedef struct _atexit_callback_t {
|
||||||
|
size_t n_pos, n_kw;
|
||||||
|
mp_obj_t func, *args;
|
||||||
|
} atexit_callback_t;
|
||||||
|
|
||||||
extern void atexit_reset(void);
|
extern void atexit_reset(void);
|
||||||
extern void atexit_gc_collect(void);
|
extern void atexit_gc_collect(void);
|
||||||
|
@ -35,6 +41,6 @@ extern void atexit_gc_collect(void);
|
||||||
extern void shared_module_atexit_register(mp_obj_t *func,
|
extern void shared_module_atexit_register(mp_obj_t *func,
|
||||||
size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args);
|
size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args);
|
||||||
extern void shared_module_atexit_unregister(const mp_obj_t *func);
|
extern void shared_module_atexit_unregister(const mp_obj_t *func);
|
||||||
extern void shared_module_atexit_execute(void);
|
extern void shared_module_atexit_execute(pyexec_result_t *result);
|
||||||
|
|
||||||
#endif // MICROPY_INCLUDED_SHARED_MODULE_ATEXIT___INIT___H
|
#endif // MICROPY_INCLUDED_SHARED_MODULE_ATEXIT___INIT___H
|
||||||
|
|
Loading…
Reference in New Issue