Skip to content

Commit d198c5e

Browse files
committed
py: Fix Zephyr threading double initialization bugs.
Threads were hanging when executing Python functions due to two critical bugs in the thread initialization path when MICROPY_ZEPHYR_THREADING is enabled: Bug #1 - C Stack Initialization Corruption (runtime.h): zephyr_entry() correctly sets C stack bounds using actual Zephyr thread stack info, but mp_thread_init_state() was then overwriting those bounds by calling mp_cstack_init_with_top(ts + 1, stack_size). The ts + 1 address points to memory after a local variable, causing mp_cstack_check() to calculate garbage values and potentially raise recursion depth errors. Bug #2 - Thread State Pointer Corruption (modthread.c): zephyr_entry() correctly sets TLS to heap-allocated self->thread_state, but thread_entry() creates a local variable mp_state_thread_t ts and calls mp_thread_init_state(&ts, ...) which overwrites the TLS pointer to point to this local stack variable. When the stack frame changes, all MP_STATE_THREAD() accesses point to invalid memory. Root cause: For Zephyr threading there are two entry points: 1. zephyr_entry() - Zephyr thread entry that initializes MicroPython 2. thread_entry() - Generic MicroPython thread entry The bugs occurred because thread_entry() was reinitializing everything that zephyr_entry() had already correctly initialized, causing double initialization and memory corruption. Solution: Modified thread_entry() to skip thread state allocation, C stack initialization, and mp_thread_start() call when Zephyr threading is enabled, as these are already handled by zephyr_entry(). Thread_entry() now only handles GIL, NLR, and function execution for Zephyr threading. Changes: - py/runtime.h: Skip mp_cstack_init_with_top() for Zephyr threading - py/modthread.c: Skip thread state init and mp_thread_start() for Zephyr Tested on STM32 NUCLEO_F429ZI (STM32F429ZITx). Threads now successfully execute Python functions. Signed-off-by: Andrew Leech <[email protected]>
1 parent 5eb14dc commit d198c5e

File tree

2 files changed

+22
-15
lines changed

2 files changed

+22
-15
lines changed

py/modthread.c

Lines changed: 15 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -158,42 +158,38 @@ static void *thread_entry(void *args_in) {
158158

159159
thread_entry_args_t *args = (thread_entry_args_t *)args_in;
160160

161-
fprintf(stderr, "[thread_entry] Starting new thread\n");
161+
#if !MICROPY_ZEPHYR_THREADING
162+
// For Zephyr threading, thread state is already initialized by zephyr_entry()
163+
// using heap-allocated state. Do NOT reinitialize here with local variable.
162164
mp_state_thread_t ts;
163-
fprintf(stderr, "[thread_entry] About to init thread state, ts=%p, stack_size=%zu\n", &ts, args->stack_size);
164165
mp_thread_init_state(&ts, args->stack_size, args->dict_locals, args->dict_globals);
165-
fprintf(stderr, "[thread_entry] Thread state initialized\n");
166-
mp_state_thread_t *tls_check = mp_thread_get_state();
167-
fprintf(stderr, "[thread_entry] TLS check: %p (should match ts=%p)\n", (void *)tls_check, (void *)&ts);
168166

169167
#if MICROPY_ENABLE_PYSTACK
170168
// TODO threading and pystack is not fully supported, for now just make a small stack
171169
mp_obj_t mini_pystack[128];
172170
mp_pystack_init(mini_pystack, &mini_pystack[128]);
173171
#endif
172+
#endif
174173

175-
fprintf(stderr, "[thread_entry] About to acquire GIL\n");
176174
MP_THREAD_GIL_ENTER();
177-
fprintf(stderr, "[thread_entry] GIL acquired\n");
178175

179-
// signal that we are set up and running
180-
fprintf(stderr, "[thread_entry] Calling mp_thread_start()\n");
176+
#if !MICROPY_ZEPHYR_THREADING
177+
// For Zephyr threading, mp_thread_start() is already called by zephyr_entry()
181178
mp_thread_start();
182-
fprintf(stderr, "[thread_entry] mp_thread_start() returned\n");
179+
#endif
183180

184181
// TODO set more thread-specific state here:
185182
// cur_exception (root pointer)
186183

184+
#if !MICROPY_ZEPHYR_THREADING
187185
DEBUG_printf("[thread] start ts=%p args=%p stack=%p\n", &ts, &args, MP_STATE_THREAD(stack_top));
186+
#else
187+
DEBUG_printf("[thread] start args=%p stack=%p\n", &args, MP_STATE_THREAD(stack_top));
188+
#endif
188189

189190
nlr_buf_t nlr;
190-
fprintf(stderr, "[thread_entry] About to push NLR handler\n");
191-
fprintf(stderr, "[thread_entry] Before nlr_push: nlr_top=%p\n", (void *)MP_STATE_THREAD(nlr_top));
192191
if (nlr_push(&nlr) == 0) {
193-
fprintf(stderr, "[thread_entry] After nlr_push: nlr_top=%p, nlr=%p\n", (void *)MP_STATE_THREAD(nlr_top), (void *)&nlr);
194-
fprintf(stderr, "[thread_entry] Calling Python function\n");
195192
mp_call_function_n_kw(args->fun, args->n_args, args->n_kw, args->args);
196-
fprintf(stderr, "[thread_entry] Python function returned normally\n");
197193
nlr_pop();
198194
} else {
199195
// uncaught exception
@@ -210,7 +206,11 @@ static void *thread_entry(void *args_in) {
210206
}
211207
}
212208

209+
#if !MICROPY_ZEPHYR_THREADING
213210
DEBUG_printf("[thread] finish ts=%p\n", &ts);
211+
#else
212+
DEBUG_printf("[thread] finish\n");
213+
#endif
214214

215215
// signal that we are finished
216216
mp_thread_finish();

py/runtime.h

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -159,7 +159,14 @@ void mp_call_function_1_from_nlr_jump_callback(void *ctx_in);
159159
static inline void mp_thread_init_state(mp_state_thread_t *ts, size_t stack_size, mp_obj_dict_t *locals, mp_obj_dict_t *globals) {
160160
mp_thread_set_state(ts);
161161

162+
#if !MICROPY_ZEPHYR_THREADING
163+
// For Zephyr threading, C stack is already initialized by zephyr_entry()
164+
// using actual Zephyr thread stack info. Do NOT reinitialize here.
162165
mp_cstack_init_with_top(ts + 1, stack_size); // need to include ts in root-pointer scan
166+
#else
167+
// Zephyr threading: stack_top/stack_limit already set correctly by zephyr_entry()
168+
(void)stack_size; // Suppress unused parameter warning
169+
#endif
163170

164171
// GC starts off unlocked
165172
ts->gc_lock_depth = 0;

0 commit comments

Comments
 (0)