aboutsummaryrefslogtreecommitdiff
path: root/py/gc.c
diff options
context:
space:
mode:
authorDamien George <damien.p.george@gmail.com>2017-04-12 13:52:04 +1000
committerDamien George <damien.p.george@gmail.com>2017-04-12 13:52:04 +1000
commitc7e8c6f7dec539aae4ca6445541533bfbc1a1405 (patch)
tree33abba94bd71b6ecb74ae99ac16dfc5fe5b66c45 /py/gc.c
parent08242eed2677cde806fd9c0de33138a8491293a2 (diff)
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.
Diffstat (limited to 'py/gc.c')
-rw-r--r--py/gc.c14
1 files changed, 8 insertions, 6 deletions
diff --git a/py/gc.c b/py/gc.c
index 7ed53cfc7..937dae44f 100644
--- a/py/gc.c
+++ b/py/gc.c
@@ -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