diff --git a/components/lwp/lwp.c b/components/lwp/lwp.c index 4e589788993..f3841bb4c10 100644 --- a/components/lwp/lwp.c +++ b/components/lwp/lwp.c @@ -514,14 +514,14 @@ pid_t lwp_execve(char *filename, int debug, int argc, char **argv, char **envp) if ((tid = lwp_tid_get()) == 0) { - lwp_ref_dec(lwp); + lwp_pid_rollback(lwp); return -ENOMEM; } #ifdef ARCH_MM_MMU if (lwp_user_space_init(lwp, 0) != 0) { lwp_tid_put(tid); - lwp_ref_dec(lwp); + lwp_pid_rollback(lwp); return -ENOMEM; } #endif @@ -529,7 +529,7 @@ pid_t lwp_execve(char *filename, int debug, int argc, char **argv, char **envp) if ((aux = argscopy(lwp, argc, argv, envp)) == RT_NULL) { lwp_tid_put(tid); - lwp_ref_dec(lwp); + lwp_pid_rollback(lwp); return -ENOMEM; } @@ -629,7 +629,7 @@ pid_t lwp_execve(char *filename, int debug, int argc, char **argv, char **envp) } lwp_tid_put(tid); - lwp_ref_dec(lwp); + lwp_pid_rollback(lwp); return -RT_ERROR; } diff --git a/components/lwp/lwp_pid.c b/components/lwp/lwp_pid.c index c992f1da8c3..82f205a694e 100644 --- a/components/lwp/lwp_pid.c +++ b/components/lwp/lwp_pid.c @@ -335,6 +335,35 @@ void lwp_pid_put(struct rt_lwp *lwp) lwp_ref_dec(lwp); } +/** + * @brief Roll back a PID allocated for a process that never became runnable. + * + * @param[in,out] lwp The lightweight process whose PID allocation should be + * undone. The LWP must have been allocated a PID, but must + * not have been made visible as a runnable user task. + * + * @note This helper is intended for exec/spawn failure paths after PID + * allocation and before task startup. It removes the PID table entry, + * clears lwp->pid, and drops the initial LWP reference. + * + * Do not use lwp_pid_put() for this case. lwp_pid_put() has process-exit + * semantics: when the PID tree becomes empty it wakes waiters and keeps + * the PID lock held to prevent new PID allocation. A failed exec rollback + * must release the PID lock unconditionally so later LWP launches can + * still allocate PIDs, especially in init-less boot flows. + */ +void lwp_pid_rollback(struct rt_lwp *lwp) +{ + _free_proc_dentry(lwp); + + lwp_pid_lock_take(); + lwp_pid_put_locked(lwp->pid); + lwp_pid_lock_release(); + + lwp->pid = 0; + lwp_ref_dec(lwp); +} + /** * @brief Set the LWP for a given PID while holding the PID lock * diff --git a/components/lwp/lwp_pid.h b/components/lwp/lwp_pid.h index 4901fd4392d..5b85b321977 100644 --- a/components/lwp/lwp_pid.h +++ b/components/lwp/lwp_pid.h @@ -29,6 +29,7 @@ int lwp_pid_init(void); int lwp_pid_wait_for_empty(int wait_flags, rt_tick_t to); int lwp_pid_for_each(int (*cb)(pid_t pid, void *data), void *data); void lwp_pid_put(struct rt_lwp *lwp); +void lwp_pid_rollback(struct rt_lwp *lwp); void lwp_pid_lock_take(void); void lwp_pid_lock_release(void);