Skip to content
Snippets Groups Projects
Commit 5b7fd20f authored by Dave Hylands's avatar Dave Hylands
Browse files

Add support for storing args during an exception raised by an irq.

The user code should call micropython.alloc_emergency_exception_buf(size)
where size is the size of the buffer used to print the argument
passed to the exception.

With the test code from #732, and a call to
micropython.alloc_emergenncy_exception_buf(100) the following error is
now printed:
```python
>>> import heartbeat_irq
Uncaught exception in Timer(4) interrupt handler
Traceback (most recent call last):
  File "0://heartbeat_irq.py", line 14, in heartbeat_cb
NameError: name 'led' is not defined
```
parent 05c255f0
Branches
No related tags found
No related merge requests found
...@@ -51,6 +51,10 @@ STATIC MP_DEFINE_CONST_FUN_OBJ_0(mp_micropython_mem_current_obj, mp_micropython_ ...@@ -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); STATIC MP_DEFINE_CONST_FUN_OBJ_0(mp_micropython_mem_peak_obj, mp_micropython_mem_peak);
#endif #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[] = { 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) }, { MP_OBJ_NEW_QSTR(MP_QSTR___name__), MP_OBJ_NEW_QSTR(MP_QSTR_micropython) },
#if MICROPY_MEM_STATS #if MICROPY_MEM_STATS
...@@ -58,6 +62,9 @@ STATIC const mp_map_elem_t mp_module_micropython_globals_table[] = { ...@@ -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_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 }, { MP_OBJ_NEW_QSTR(MP_QSTR_mem_peak), (mp_obj_t)&mp_micropython_mem_peak_obj },
#endif #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 = { STATIC const mp_obj_dict_t mp_module_micropython_globals = {
......
...@@ -163,6 +163,16 @@ ...@@ -163,6 +163,16 @@
#define MICROPY_STACK_CHECK (1) #define MICROPY_STACK_CHECK (1)
#endif #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 // Whether to include REPL helper function
#ifndef MICROPY_HELPER_REPL #ifndef MICROPY_HELPER_REPL
#define MICROPY_HELPER_REPL (0) #define MICROPY_HELPER_REPL (0)
...@@ -378,6 +388,14 @@ typedef double mp_float_t; ...@@ -378,6 +388,14 @@ typedef double mp_float_t;
/*****************************************************************************/ /*****************************************************************************/
/* Miscellaneous settings */ /* 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 // Allow to override static modifier for global objects, e.g. to use with
// object code analysis tools which don't support static symbols. // object code analysis tools which don't support static symbols.
#ifndef STATIC #ifndef STATIC
......
...@@ -453,6 +453,8 @@ void mp_obj_exception_add_traceback(mp_obj_t self_in, qstr file, mp_uint_t line, ...@@ -453,6 +453,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); 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_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_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 // str
mp_obj_t mp_obj_str_builder_start(const mp_obj_type_t *type, uint len, byte **data); mp_obj_t mp_obj_str_builder_start(const mp_obj_type_t *type, uint len, byte **data);
......
...@@ -27,12 +27,15 @@ ...@@ -27,12 +27,15 @@
#include <string.h> #include <string.h>
#include <stdarg.h> #include <stdarg.h>
#include <assert.h> #include <assert.h>
#include <stdio.h>
#include "mpconfig.h" #include "mpconfig.h"
#include "nlr.h" #include "nlr.h"
#include "misc.h" #include "misc.h"
#include "qstr.h" #include "qstr.h"
#include "obj.h" #include "obj.h"
#include "objlist.h"
#include "objstr.h"
#include "objtuple.h" #include "objtuple.h"
#include "objtype.h" #include "objtype.h"
#include "runtime.h" #include "runtime.h"
...@@ -51,6 +54,53 @@ const mp_obj_exception_t mp_const_MemoryError_obj = {{&mp_type_MemoryError}, MP_ ...@@ -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 // Local non-heap memory for allocating an exception when we run out of RAM
STATIC mp_obj_exception_t mp_emergency_exception_obj; 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() // Instance of GeneratorExit exception - needed by generator.close()
// This would belong to objgenerator.c, but to keep mp_obj_exception_t // This would belong to objgenerator.c, but to keep mp_obj_exception_t
// definition module-private so far, have it here. // 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 ...@@ -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->base.type = exc_type;
o->traceback = MP_OBJ_NULL; o->traceback = MP_OBJ_NULL;
o->args = mp_const_empty_tuple; 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 { } else {
o->base.type = exc_type; o->base.type = exc_type;
o->traceback = MP_OBJ_NULL; o->traceback = MP_OBJ_NULL;
...@@ -336,15 +430,24 @@ void mp_obj_exception_clear_traceback(mp_obj_t self_in) { ...@@ -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) { 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 MICROPY_ENABLE_GC
if (gc_is_locked()) { if (gc_is_locked()) {
// We can't allocate memory, so don't bother to try 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; 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 #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 // 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) { if (self->traceback == MP_OBJ_NULL) {
self->traceback = mp_obj_new_list(0, NULL); self->traceback = mp_obj_new_list(0, NULL);
......
...@@ -323,6 +323,10 @@ Q(mem_total) ...@@ -323,6 +323,10 @@ Q(mem_total)
Q(mem_current) Q(mem_current)
Q(mem_peak) Q(mem_peak)
#if MICROPY_ENABLE_EMERGENCY_EXCEPTION_BUF && (MICROPY_EMERGENCY_EXCEPTION_BUF_SIZE == 0)
Q(alloc_emergency_exception_buf)
#endif
Q(<module>) Q(<module>)
Q(<lambda>) Q(<lambda>)
Q(<listcomp>) Q(<listcomp>)
......
...@@ -119,6 +119,14 @@ void MP_WEAK __assert_func(const char *file, int line, const char *func, const c ...@@ -119,6 +119,14 @@ void MP_WEAK __assert_func(const char *file, int line, const char *func, const c
} }
#endif #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_source_dir = MP_OBJ_NULL;
STATIC mp_obj_t pyb_config_main = MP_OBJ_NULL; STATIC mp_obj_t pyb_config_main = MP_OBJ_NULL;
STATIC mp_obj_t pyb_config_usb_mode = MP_OBJ_NULL; STATIC mp_obj_t pyb_config_usb_mode = MP_OBJ_NULL;
...@@ -302,6 +310,9 @@ soft_reset: ...@@ -302,6 +310,9 @@ soft_reset:
// GC init // GC init
gc_init(&_heap_start, &_heap_end); 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) // Change #if 0 to #if 1 if you want REPL on UART_6 (or another uart)
// as well as on USB VCP // as well as on USB VCP
......
...@@ -52,6 +52,15 @@ ...@@ -52,6 +52,15 @@
#define MICROPY_PY_IO (1) #define MICROPY_PY_IO (1)
#define MICROPY_PY_IO_FILEIO (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 // 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_help_obj;
extern const struct _mp_obj_fun_native_t mp_builtin_input_obj; extern const struct _mp_obj_fun_native_t mp_builtin_input_obj;
......
...@@ -273,6 +273,9 @@ int main(int argc, char **argv) { ...@@ -273,6 +273,9 @@ int main(int argc, char **argv) {
char *heap = malloc(heap_size); char *heap = malloc(heap_size);
gc_init(heap, heap + heap_size); gc_init(heap, heap + heap_size);
#endif #endif
#if MICROPY_ENABLE_EMERGENCY_EXCEPTION_BUF
mp_init_emergency_exception_buf();
#endif
qstr_init(); qstr_init();
mp_init(); mp_init();
......
...@@ -64,6 +64,9 @@ ...@@ -64,6 +64,9 @@
#define MICROPY_GCREGS_SETJMP (0) #define MICROPY_GCREGS_SETJMP (0)
#endif #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_os;
extern const struct _mp_obj_module_t mp_module_time; extern const struct _mp_obj_module_t mp_module_time;
extern const struct _mp_obj_module_t mp_module_socket; extern const struct _mp_obj_module_t mp_module_socket;
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment