Skip to content

Commit a952fe1

Browse files
pi-anlandrewleech
authored andcommitted
py/modsys: Extend atexit to hold multiple functions.
Signed-off-by: Andrew Leech <andrew@alelec.net>
1 parent 838f212 commit a952fe1

File tree

5 files changed

+44
-5
lines changed

5 files changed

+44
-5
lines changed

py/modsys.c

Lines changed: 33 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -208,13 +208,42 @@ static MP_DEFINE_CONST_FUN_OBJ_1(mp_sys_getsizeof_obj, mp_sys_getsizeof);
208208
#endif
209209

210210
#if MICROPY_PY_SYS_ATEXIT
211+
typedef struct _m_atexit_node_t {
212+
struct _m_atexit_node_t *prev;
213+
struct _m_atexit_node_t *next;
214+
mp_obj_t fn;
215+
} m_atexit_node_t;
216+
211217
// atexit(callback): Callback is called when sys.exit is called.
212218
static mp_obj_t mp_sys_atexit(mp_obj_t obj) {
213-
mp_obj_t old = MP_STATE_VM(sys_exitfunc);
214-
MP_STATE_VM(sys_exitfunc) = obj;
215-
return old;
219+
m_atexit_node_t *node = m_malloc(sizeof(m_atexit_node_t));
220+
if (MP_STATE_VM(sys_exitfunc) != mp_const_none) {
221+
MP_STATE_VM(sys_exitfunc)->prev = node;
222+
}
223+
node->fn = obj;
224+
node->prev = NULL;
225+
node->next = MP_STATE_VM(sys_exitfunc);
226+
MP_STATE_VM(sys_exitfunc) = node;
227+
return obj;
216228
}
217229
static MP_DEFINE_CONST_FUN_OBJ_1(mp_sys_atexit_obj, mp_sys_atexit);
230+
231+
void mp_sys_atexit_execute(void) {
232+
// walk through the linked list and execute each function
233+
// Beware, the sys.settrace callback should be disabled before running sys.atexit.
234+
while (MP_STATE_VM(sys_exitfunc) != mp_const_none) {
235+
if (mp_obj_is_callable(MP_STATE_VM(sys_exitfunc)->fn)) {
236+
nlr_buf_t nlr;
237+
if (nlr_push(&nlr) == 0) {
238+
mp_call_function_0(MP_STATE_VM(sys_exitfunc)->fn);
239+
} else {
240+
// Uncaught exception: print it out.
241+
mp_obj_print_exception(&mp_plat_print, (mp_obj_t)nlr.ret_val);
242+
}
243+
}
244+
MP_STATE_VM(sys_exitfunc) = MP_STATE_VM(sys_exitfunc)->next;
245+
}
246+
}
218247
#endif
219248

220249
#if MICROPY_PY_SYS_SETTRACE
@@ -364,7 +393,7 @@ MP_REGISTER_ROOT_POINTER(mp_obj_base_t * cur_exception);
364393

365394
#if MICROPY_PY_SYS_ATEXIT
366395
// exposed through sys.atexit function
367-
MP_REGISTER_ROOT_POINTER(mp_obj_t sys_exitfunc);
396+
MP_REGISTER_ROOT_POINTER(struct _m_atexit_node_t *sys_exitfunc);
368397
#endif
369398

370399
#if MICROPY_PY_SYS_ATTR_DELEGATION

py/mpconfig.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1488,7 +1488,7 @@ typedef double mp_float_t;
14881488

14891489
// Whether to provide "sys.atexit" function (MicroPython extension)
14901490
#ifndef MICROPY_PY_SYS_ATEXIT
1491-
#define MICROPY_PY_SYS_ATEXIT (0)
1491+
#define MICROPY_PY_SYS_ATEXIT (MICROPY_CONFIG_ROM_LEVEL_AT_LEAST_EXTRA_FEATURES)
14921492
#endif
14931493

14941494
// Whether to provide the "sys.path" attribute (which forces module delegation

py/runtime.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -95,6 +95,10 @@ extern const byte mp_binary_op_method_name[];
9595
void mp_init(void);
9696
void mp_deinit(void);
9797

98+
#if MICROPY_PY_SYS_ATEXIT
99+
void mp_sys_atexit_execute(void);
100+
#endif
101+
98102
void mp_sched_exception(mp_obj_t exc);
99103
void mp_sched_keyboard_interrupt(void);
100104
#if MICROPY_ENABLE_VM_ABORT

tests/misc/sys_atexit.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,11 @@ def do_at_exit():
1515
print("done at exit:", some_var)
1616

1717

18+
@sys.atexit
19+
def do_at_exit_2():
20+
print("done at exit last")
21+
22+
1823
sys.atexit(do_at_exit)
1924

2025
some_var = "ok"

tests/misc/sys_atexit.py.exp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,3 @@
11
done before exit
22
done at exit: ok
3+
done at exit last

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy