sched/nxtask_sigchild: Set process exit code to group exit code

There is an issue where the wrong process exit code is given to the parent
when a process exits. This happens when the process has pthreads running
user code i.e. not within a cancel point / system call.

Why does this happen ?

When exit() is called, the following steps are done:
- group_kill_children(), which tells the children to die via pthread_cancel()

Then, one of two things can happen:
1. if the child is in a cancel point, it gets scheduled to allow it to leave
   the cancel point and gets destroyed immediately
2. if the child is not in a cancel point, a "cancel pending" flag is set and
   the child will die when the next cancel point is encountered

So what is the problem here?

The last thread alive dispatches SIGCHLD to the parent, which carries the
process's exit code. The group head has the only meaningful exit code and
this is what should be passed. However, in the second case, the group head
exits before the child, taking the process exit code to its grave. The child
that was alive will exit next and will pass its "status" to the parent process,
but this status is not the correct value to pass.

This commit fixes the issue by passing the group head's exit code ALWAYS to
the parent process.
This commit is contained in:
Ville Juven 2023-02-09 14:43:44 +02:00 committed by Xiang Xiao
parent 1949991fe0
commit 9638187192
2 changed files with 5 additions and 2 deletions

View File

@ -454,6 +454,9 @@ struct task_group_s
#else
uint16_t tg_nchildren; /* This is the number active children */
#endif
/* Group exit status ******************************************************/
int tg_exitcode; /* Exit code (status) for group */
#endif /* CONFIG_SCHED_HAVE_PARENT */
#if defined(CONFIG_SCHED_WAITPID) && !defined(CONFIG_SCHED_HAVE_PARENT)

View File

@ -80,7 +80,7 @@ static inline void nxtask_exitstatus(FAR struct task_group_s *group,
}
#else
# define nxtask_exitstatus(group,status)
# define nxtask_exitstatus(group,status) (group)->tg_exitcode = (status);
#endif /* CONFIG_SCHED_CHILD_STATUS */
@ -188,7 +188,7 @@ static inline void nxtask_sigchild(pid_t ppid, FAR struct tcb_s *ctcb,
info.si_errno = OK;
info.si_value.sival_ptr = NULL;
info.si_pid = chgrp->tg_pid;
info.si_status = status;
info.si_status = pgrp->tg_exitcode;
/* Send the signal to one thread in the group */