Merge pull request #738 from dhylands/except-args
Add support for storing args during an exception raised by an irq.
This commit is contained in:
commit
07133415d2
@ -51,6 +51,10 @@ STATIC MP_DEFINE_CONST_FUN_OBJ_0(mp_micropython_mem_current_obj, mp_micropython_
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_0(mp_micropython_mem_peak_obj, mp_micropython_mem_peak);
|
||||
#endif
|
||||
|
||||
#if MICROPY_ENABLE_EMERGENCY_EXCEPTION_BUF && (MICROPY_EMERGENCY_EXCEPTION_BUF_SIZE == 0)
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_1(mp_alloc_emergency_exception_buf_obj, mp_alloc_emergency_exception_buf);
|
||||
#endif
|
||||
|
||||
STATIC const mp_map_elem_t mp_module_micropython_globals_table[] = {
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR___name__), MP_OBJ_NEW_QSTR(MP_QSTR_micropython) },
|
||||
#if MICROPY_MEM_STATS
|
||||
@ -58,6 +62,9 @@ STATIC const mp_map_elem_t mp_module_micropython_globals_table[] = {
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_mem_current), (mp_obj_t)&mp_micropython_mem_current_obj },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_mem_peak), (mp_obj_t)&mp_micropython_mem_peak_obj },
|
||||
#endif
|
||||
#if MICROPY_ENABLE_EMERGENCY_EXCEPTION_BUF && (MICROPY_EMERGENCY_EXCEPTION_BUF_SIZE == 0)
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_alloc_emergency_exception_buf), (mp_obj_t)&mp_alloc_emergency_exception_buf_obj },
|
||||
#endif
|
||||
};
|
||||
|
||||
STATIC const mp_obj_dict_t mp_module_micropython_globals = {
|
||||
|
@ -163,6 +163,16 @@
|
||||
#define MICROPY_STACK_CHECK (1)
|
||||
#endif
|
||||
|
||||
// Whether to have an emergency exception buffer
|
||||
#ifndef MICROPY_ENABLE_EMERGENCY_EXCEPTION_BUF
|
||||
#define MICROPY_ENABLE_EMERGENCY_EXCEPTION_BUF (0)
|
||||
#endif
|
||||
#if MICROPY_ENABLE_EMERGENCY_EXCEPTION_BUF
|
||||
# ifndef MICROPY_EMERGENCY_EXCEPTION_BUF_SIZE
|
||||
# define MICROPY_EMERGENCY_EXCEPTION_BUF_SIZE (0) // 0 - implies dynamic allocation
|
||||
# endif
|
||||
#endif
|
||||
|
||||
// Whether to include REPL helper function
|
||||
#ifndef MICROPY_HELPER_REPL
|
||||
#define MICROPY_HELPER_REPL (0)
|
||||
@ -383,6 +393,14 @@ typedef double mp_float_t;
|
||||
/*****************************************************************************/
|
||||
/* Miscellaneous settings */
|
||||
|
||||
// On embedded platforms, these will typically enable/disable irqs.
|
||||
#ifndef MICROPY_BEGIN_ATOMIC_SECTION
|
||||
#define MICROPY_BEGIN_ATOMIC_SECTION()
|
||||
#endif
|
||||
#ifndef MICROPY_END_ATOMIC_SECTION
|
||||
#define MICROPY_END_ATOMIC_SECTION()
|
||||
#endif
|
||||
|
||||
// Allow to override static modifier for global objects, e.g. to use with
|
||||
// object code analysis tools which don't support static symbols.
|
||||
#ifndef STATIC
|
||||
|
2
py/obj.h
2
py/obj.h
@ -454,6 +454,8 @@ void mp_obj_exception_add_traceback(mp_obj_t self_in, qstr file, mp_uint_t line,
|
||||
void mp_obj_exception_get_traceback(mp_obj_t self_in, mp_uint_t *n, mp_uint_t **values);
|
||||
mp_obj_t mp_obj_exception_get_value(mp_obj_t self_in);
|
||||
mp_obj_t mp_obj_exception_make_new(mp_obj_t type_in, uint n_args, uint n_kw, const mp_obj_t *args);
|
||||
mp_obj_t mp_alloc_emergency_exception_buf(mp_obj_t size_in);
|
||||
void mp_init_emergency_exception_buf(void);
|
||||
|
||||
// str
|
||||
mp_obj_t mp_obj_str_builder_start(const mp_obj_type_t *type, uint len, byte **data);
|
||||
|
111
py/objexcept.c
111
py/objexcept.c
@ -27,12 +27,15 @@
|
||||
#include <string.h>
|
||||
#include <stdarg.h>
|
||||
#include <assert.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include "mpconfig.h"
|
||||
#include "nlr.h"
|
||||
#include "misc.h"
|
||||
#include "qstr.h"
|
||||
#include "obj.h"
|
||||
#include "objlist.h"
|
||||
#include "objstr.h"
|
||||
#include "objtuple.h"
|
||||
#include "objtype.h"
|
||||
#include "runtime.h"
|
||||
@ -51,6 +54,53 @@ const mp_obj_exception_t mp_const_MemoryError_obj = {{&mp_type_MemoryError}, MP_
|
||||
// Local non-heap memory for allocating an exception when we run out of RAM
|
||||
STATIC mp_obj_exception_t mp_emergency_exception_obj;
|
||||
|
||||
// Optionally allocated buffer for storing the first argument of an exception
|
||||
// allocated when the heap is locked.
|
||||
#if MICROPY_ENABLE_EMERGENCY_EXCEPTION_BUF
|
||||
# if MICROPY_EMERGENCY_EXCEPTION_BUF_SIZE > 0
|
||||
STATIC byte mp_emergency_exception_buf[MICROPY_EMERGENCY_EXCEPTION_BUF_SIZE];
|
||||
#define mp_emergency_exception_buf_size MICROPY_EMERGENCY_EXCEPTION_BUF_SIZE
|
||||
|
||||
void mp_init_emergency_exception_buf(void) {
|
||||
// Nothing to do since the buffer was declared statically. We put this
|
||||
// definition here so that the calling code can call this function
|
||||
// regardless of how its configured (makes the calling code a bit cleaner).
|
||||
}
|
||||
|
||||
#else
|
||||
STATIC mp_int_t mp_emergency_exception_buf_size = 0;
|
||||
STATIC byte *mp_emergency_exception_buf = NULL;
|
||||
|
||||
void mp_init_emergency_exception_buf(void) {
|
||||
mp_emergency_exception_buf_size = 0;
|
||||
mp_emergency_exception_buf = NULL;
|
||||
}
|
||||
|
||||
mp_obj_t mp_alloc_emergency_exception_buf(mp_obj_t size_in) {
|
||||
mp_int_t size = mp_obj_get_int(size_in);
|
||||
void *buf = NULL;
|
||||
if (size > 0) {
|
||||
buf = m_malloc(size);
|
||||
}
|
||||
|
||||
int old_size = mp_emergency_exception_buf_size;
|
||||
void *old_buf = mp_emergency_exception_buf;
|
||||
|
||||
// Update the 2 variables atomically so that an interrupt can't occur
|
||||
// between the assignments.
|
||||
MICROPY_BEGIN_ATOMIC_SECTION();
|
||||
mp_emergency_exception_buf_size = size;
|
||||
mp_emergency_exception_buf = buf;
|
||||
MICROPY_END_ATOMIC_SECTION();
|
||||
|
||||
if (old_buf != NULL) {
|
||||
m_free(old_buf, old_size);
|
||||
}
|
||||
return mp_const_none;
|
||||
}
|
||||
#endif
|
||||
#endif // MICROPY_ENABLE_EMERGENCY_EXCEPTION_BUF
|
||||
|
||||
// Instance of GeneratorExit exception - needed by generator.close()
|
||||
// This would belong to objgenerator.c, but to keep mp_obj_exception_t
|
||||
// definition module-private so far, have it here.
|
||||
@ -268,6 +318,50 @@ mp_obj_t mp_obj_new_exception_msg_varg(const mp_obj_type_t *exc_type, const char
|
||||
o->base.type = exc_type;
|
||||
o->traceback = MP_OBJ_NULL;
|
||||
o->args = mp_const_empty_tuple;
|
||||
|
||||
#if MICROPY_ENABLE_EMERGENCY_EXCEPTION_BUF
|
||||
// If the user has provided a buffer, then we try to create a tuple
|
||||
// of length 1, which has a string object and the string data.
|
||||
|
||||
if (mp_emergency_exception_buf_size > (sizeof(mp_obj_tuple_t) + sizeof(mp_obj_str_t) + sizeof(mp_obj_t))) {
|
||||
mp_obj_tuple_t *tuple = (mp_obj_tuple_t *)mp_emergency_exception_buf;
|
||||
mp_obj_str_t *str = (mp_obj_str_t *)&tuple->items[1];
|
||||
|
||||
tuple->base.type = &mp_type_tuple;
|
||||
tuple->len = 1;
|
||||
tuple->items[0] = str;
|
||||
|
||||
byte *str_data = (byte *)&str[1];
|
||||
uint max_len = mp_emergency_exception_buf + mp_emergency_exception_buf_size
|
||||
- str_data;
|
||||
|
||||
va_list ap;
|
||||
va_start(ap, fmt);
|
||||
str->len = vsnprintf((char *)str_data, max_len, fmt, ap);
|
||||
va_end(ap);
|
||||
|
||||
str->base.type = &mp_type_str;
|
||||
str->hash = qstr_compute_hash(str_data, str->len);
|
||||
str->data = str_data;
|
||||
|
||||
o->args = tuple;
|
||||
|
||||
uint offset = &str_data[str->len] - mp_emergency_exception_buf;
|
||||
offset += sizeof(void *) - 1;
|
||||
offset &= ~(sizeof(void *) - 1);
|
||||
|
||||
if ((mp_emergency_exception_buf_size - offset) > (sizeof(mp_obj_list_t) + sizeof(mp_obj_t) * 3)) {
|
||||
// We have room to store some traceback.
|
||||
mp_obj_list_t *list = (mp_obj_list_t *)((byte *)mp_emergency_exception_buf + offset);
|
||||
list->base.type = &mp_type_list;
|
||||
list->items = (mp_obj_t)&list[1];
|
||||
list->alloc = (mp_emergency_exception_buf + mp_emergency_exception_buf_size - (byte *)list->items) / sizeof(list->items[0]);
|
||||
list->len = 0;
|
||||
|
||||
o->traceback = list;
|
||||
}
|
||||
}
|
||||
#endif // MICROPY_ENABLE_EMERGENCY_EXCEPTION_BUF
|
||||
} else {
|
||||
o->base.type = exc_type;
|
||||
o->traceback = MP_OBJ_NULL;
|
||||
@ -336,15 +430,24 @@ void mp_obj_exception_clear_traceback(mp_obj_t self_in) {
|
||||
}
|
||||
|
||||
void mp_obj_exception_add_traceback(mp_obj_t self_in, qstr file, mp_uint_t line, qstr block) {
|
||||
GET_NATIVE_EXCEPTION(self, self_in);
|
||||
|
||||
#if MICROPY_ENABLE_GC
|
||||
if (gc_is_locked()) {
|
||||
// We can't allocate memory, so don't bother to try
|
||||
return;
|
||||
if (self->traceback == MP_OBJ_NULL) {
|
||||
// We can't allocate any memory, and no memory has been
|
||||
// pre-allocated, so there is nothing else we can do.
|
||||
return;
|
||||
}
|
||||
mp_obj_list_t *list = self->traceback;
|
||||
if (list->alloc <= (list->len + 3)) {
|
||||
// There is some preallocated memory, but not enough to store an
|
||||
// entire record.
|
||||
return;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
GET_NATIVE_EXCEPTION(self, self_in);
|
||||
|
||||
// for traceback, we are just using the list object for convenience, it's not really a list of Python objects
|
||||
if (self->traceback == MP_OBJ_NULL) {
|
||||
self->traceback = mp_obj_new_list(0, NULL);
|
||||
|
@ -326,6 +326,10 @@ Q(mem_total)
|
||||
Q(mem_current)
|
||||
Q(mem_peak)
|
||||
|
||||
#if MICROPY_ENABLE_EMERGENCY_EXCEPTION_BUF && (MICROPY_EMERGENCY_EXCEPTION_BUF_SIZE == 0)
|
||||
Q(alloc_emergency_exception_buf)
|
||||
#endif
|
||||
|
||||
Q(<module>)
|
||||
Q(<lambda>)
|
||||
Q(<listcomp>)
|
||||
|
@ -119,6 +119,14 @@ void MP_WEAK __assert_func(const char *file, int line, const char *func, const c
|
||||
}
|
||||
#endif
|
||||
|
||||
void enable_irq(void) {
|
||||
__enable_irq();
|
||||
}
|
||||
|
||||
void disable_irq(void) {
|
||||
__disable_irq();
|
||||
}
|
||||
|
||||
STATIC mp_obj_t pyb_config_source_dir = MP_OBJ_NULL;
|
||||
STATIC mp_obj_t pyb_config_main = MP_OBJ_NULL;
|
||||
STATIC mp_obj_t pyb_config_usb_mode = MP_OBJ_NULL;
|
||||
@ -302,6 +310,9 @@ soft_reset:
|
||||
|
||||
// GC init
|
||||
gc_init(&_heap_start, &_heap_end);
|
||||
#if MICROPY_ENABLE_EMERGENCY_EXCEPTION_BUF
|
||||
mp_init_emergency_exception_buf();
|
||||
#endif
|
||||
|
||||
// Change #if 0 to #if 1 if you want REPL on UART_6 (or another uart)
|
||||
// as well as on USB VCP
|
||||
|
@ -52,6 +52,15 @@
|
||||
#define MICROPY_PY_IO (1)
|
||||
#define MICROPY_PY_IO_FILEIO (1)
|
||||
|
||||
#define MICROPY_ENABLE_EMERGENCY_EXCEPTION_BUF (1)
|
||||
#define MICROPY_EMERGENCY_EXCEPTION_BUF_SIZE (0)
|
||||
|
||||
void enable_irq(void);
|
||||
void disable_irq(void);
|
||||
|
||||
#define MICROPY_BEGIN_ATOMIC_SECTION() disable_irq()
|
||||
#define MICROPY_END_ATOMIC_SECTION() enable_irq()
|
||||
|
||||
// extra built in names to add to the global namespace
|
||||
extern const struct _mp_obj_fun_native_t mp_builtin_help_obj;
|
||||
extern const struct _mp_obj_fun_native_t mp_builtin_input_obj;
|
||||
|
@ -278,6 +278,9 @@ int main(int argc, char **argv) {
|
||||
char *heap = malloc(heap_size);
|
||||
gc_init(heap, heap + heap_size);
|
||||
#endif
|
||||
#if MICROPY_ENABLE_EMERGENCY_EXCEPTION_BUF
|
||||
mp_init_emergency_exception_buf();
|
||||
#endif
|
||||
|
||||
qstr_init();
|
||||
mp_init();
|
||||
|
@ -64,6 +64,9 @@
|
||||
#define MICROPY_GCREGS_SETJMP (0)
|
||||
#endif
|
||||
|
||||
#define MICROPY_ENABLE_EMERGENCY_EXCEPTION_BUF (1)
|
||||
#define MICROPY_EMERGENCY_EXCEPTION_BUF_SIZE (128)
|
||||
|
||||
extern const struct _mp_obj_module_t mp_module_os;
|
||||
extern const struct _mp_obj_module_t mp_module_time;
|
||||
extern const struct _mp_obj_module_t mp_module_socket;
|
||||
|
Loading…
x
Reference in New Issue
Block a user