diff options
author | Damien George <damien.p.george@gmail.com> | 2017-04-12 13:52:04 +1000 |
---|---|---|
committer | Damien George <damien.p.george@gmail.com> | 2017-04-12 13:52:04 +1000 |
commit | c7e8c6f7dec539aae4ca6445541533bfbc1a1405 (patch) | |
tree | 33abba94bd71b6ecb74ae99ac16dfc5fe5b66c45 | |
parent | 08242eed2677cde806fd9c0de33138a8491293a2 (diff) | |
download | micropython-c7e8c6f7dec539aae4ca6445541533bfbc1a1405.tar.gz micropython-c7e8c6f7dec539aae4ca6445541533bfbc1a1405.zip |
py/gc: Execute finaliser code in a protected environment.
If a finaliser raises an exception then it must not propagate through the
GC sweep function. This patch protects against such a thing by running
finaliser code via the mp_call_function_1_protected call.
This patch also adds scheduler lock/unlock calls around the finaliser
execution to further protect against any possible reentrancy issues: the
memory manager is already locked when doing a collection, but we also don't
want to allow any scheduled code to run, KeyboardInterrupts to interupt the
code, nor threads to switch.
-rw-r--r-- | py/gc.c | 14 |
1 files changed, 8 insertions, 6 deletions
@@ -258,18 +258,20 @@ STATIC void gc_sweep(void) { case AT_HEAD: #if MICROPY_ENABLE_FINALISER if (FTB_GET(block)) { - #if MICROPY_PY_THREAD - // TODO need to think about reentrancy with finaliser code - assert(!"finaliser with threading not implemented"); - #endif mp_obj_base_t *obj = (mp_obj_base_t*)PTR_FROM_BLOCK(block); if (obj->type != NULL) { // if the object has a type then see if it has a __del__ method mp_obj_t dest[2]; mp_load_method_maybe(MP_OBJ_FROM_PTR(obj), MP_QSTR___del__, dest); if (dest[0] != MP_OBJ_NULL) { - // load_method returned a method - mp_call_method_n_kw(0, 0, dest); + // load_method returned a method, execute it in a protected environment + #if MICROPY_ENABLE_SCHEDULER + mp_sched_lock(); + #endif + mp_call_function_1_protected(dest[0], dest[1]); + #if MICROPY_ENABLE_SCHEDULER + mp_sched_unlock(); + #endif } } // clear finaliser flag |