Skip to content

Commit 5f815b8

Browse files
pi-anldpgeorge
authored andcommitted
unix: Enable exit code handling for sys.exit().
Enable `MICROPY_PYEXEC_ENABLE_EXIT_CODE_HANDLING` to propagate `sys.exit()` exit codes properly. Update `convert_pyexec_result()` to handle return values where pyexec returns the exit code with `PYEXEC_FORCED_EXIT` flag set for `SystemExit`. Extract the exit code from the lower 8 bits when the flag is set, otherwise return as-is (0 for success, 1 for exception). Signed-off-by: Andrew Leech <andrew.leech@planetinnovation.com.au>
1 parent fd1ddc3 commit 5f815b8

File tree

4 files changed

+19
-0
lines changed

4 files changed

+19
-0
lines changed

ports/unix/main.c

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -242,6 +242,17 @@ static int do_repl(void) {
242242
}
243243

244244
static inline int convert_pyexec_result(int ret) {
245+
#if MICROPY_PYEXEC_ENABLE_EXIT_CODE_HANDLING
246+
// With exit code handling enabled:
247+
// pyexec returns exit code with PYEXEC_FORCED_EXIT flag set for SystemExit
248+
// Unix port expects: 0 for success, non-zero for error/exit
249+
if (ret & PYEXEC_FORCED_EXIT) {
250+
// SystemExit: extract exit code from lower bits
251+
return ret & 0xFF;
252+
}
253+
// Normal execution or exception: return as-is (0 for success, 1 for exception)
254+
return ret;
255+
#else
245256
// pyexec returns 1 for success, 0 for exception, PYEXEC_FORCED_EXIT for SystemExit
246257
// Convert to unix port's expected codes: 0 for success, 1 for exception, FORCED_EXIT|val for SystemExit
247258
if (ret == 1) {
@@ -251,6 +262,7 @@ static inline int convert_pyexec_result(int ret) {
251262
} else {
252263
return 1; // exception
253264
}
265+
#endif
254266
}
255267

256268
static int do_file(const char *file) {

ports/unix/mpconfigport.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -154,6 +154,9 @@ typedef long mp_off_t;
154154
// Enable support for compile-only mode.
155155
#define MICROPY_PYEXEC_COMPILE_ONLY (1)
156156

157+
// Enable handling of sys.exit() exit codes.
158+
#define MICROPY_PYEXEC_ENABLE_EXIT_CODE_HANDLING (1)
159+
157160
#define MICROPY_PY_SOCKET_LISTEN_BACKLOG_DEFAULT (SOMAXCONN < 128 ? SOMAXCONN : 128)
158161

159162
// Bare-metal ports don't have stderr. Printing debug to stderr may give tests

ports/windows/mpconfigport.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -164,6 +164,9 @@
164164
// Enable support for compile-only mode.
165165
#define MICROPY_PYEXEC_COMPILE_ONLY (1)
166166

167+
// Enable handling of sys.exit() exit codes.
168+
#define MICROPY_PYEXEC_ENABLE_EXIT_CODE_HANDLING (1)
169+
167170
#define MICROPY_ERROR_REPORTING (MICROPY_ERROR_REPORTING_DETAILED)
168171
#define MICROPY_ERROR_PRINTER (&mp_stderr_print)
169172
#define MICROPY_WARNINGS (1)

shared/runtime/pyexec.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -165,6 +165,7 @@ static int parse_compile_execute(const void *source, mp_parse_input_kind_t input
165165
#endif
166166
if (mp_obj_is_subclass_fast(MP_OBJ_FROM_PTR(((mp_obj_base_t *)nlr.ret_val)->type), MP_OBJ_FROM_PTR(&mp_type_SystemExit))) { // system exit
167167
#if MICROPY_PYEXEC_ENABLE_EXIT_CODE_HANDLING
168+
// None is an exit value of 0; an int is its value; anything else is 1
168169
mp_obj_t val = mp_obj_exception_get_value(MP_OBJ_FROM_PTR(nlr.ret_val));
169170
if (val != mp_const_none) {
170171
if (mp_obj_is_int(val)) {

0 commit comments

Comments
 (0)