summaryrefslogtreecommitdiffstatshomepage
path: root/py
diff options
context:
space:
mode:
Diffstat (limited to 'py')
-rw-r--r--py/modmicropython.c7
-rw-r--r--py/mpconfig.h18
-rw-r--r--py/obj.h2
-rw-r--r--py/objexcept.c111
-rw-r--r--py/qstrdefs.h4
5 files changed, 138 insertions, 4 deletions
diff --git a/py/modmicropython.c b/py/modmicropython.c
index 0d559c42a2..78beb88afa 100644
--- a/py/modmicropython.c
+++ b/py/modmicropython.c
@@ -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 = {
diff --git a/py/mpconfig.h b/py/mpconfig.h
index bb1c0b5fe7..351910b6dd 100644
--- a/py/mpconfig.h
+++ b/py/mpconfig.h
@@ -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
diff --git a/py/obj.h b/py/obj.h
index 4745b76443..c391611c10 100644
--- a/py/obj.h
+++ b/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);
diff --git a/py/objexcept.c b/py/objexcept.c
index 68992bdaed..cddc77bfeb 100644
--- a/py/objexcept.c
+++ b/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);
diff --git a/py/qstrdefs.h b/py/qstrdefs.h
index 27b695722c..6470cb9509 100644
--- a/py/qstrdefs.h
+++ b/py/qstrdefs.h
@@ -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>)