sched_waitpid.c: HIS_metric_violation(HIS_GOTO)

This commit eliminates the goto statement in nxsched_waitpid() function to
improve code quality metrics compliance. The control flow has been restructured
using nested if-else statements to achieve identical functionality while
maintaining MISRA/HIS coding standard compliance and improving code readability.

Signed-off-by: hujun5 <hujun5@xiaomi.com>
This commit is contained in:
hujun5 2026-02-03 16:19:16 +08:00 committed by Xiang Xiao
parent 87b317f965
commit 5abba4f655

View file

@ -97,104 +97,106 @@ pid_t nxsched_waitpid(pid_t pid, int *stat_loc, int options)
FAR struct tcb_s *ctcb;
FAR struct task_group_s *group;
bool mystat = false;
int ret;
/* NOTE: sched_lock() is not enough for SMP
* because the child task is running on another CPU
*/
irqstate_t flags = enter_critical_section();
irqstate_t flags;
int ret = -ECHILD;
/* Get the TCB corresponding to this PID */
ctcb = nxsched_get_tcb(pid);
if (ctcb == NULL)
if (ctcb != NULL)
{
ret = -ECHILD;
goto errout;
}
/* Then the task group corresponding to this PID */
group = ctcb->group;
if (group == NULL)
{
ret = -ECHILD;
goto errout;
}
/* Lock this group so that it cannot be deleted until the wait completes */
group_add_waiter(group);
/* "If more than one thread is suspended in waitpid() awaiting termination
* of the same process, exactly one thread will return the process status
* at the time of the target process termination." Hmmm.. what do we
* return to the others?
*/
if (group->tg_waitflags == 0)
{
/* Save the waitpid() options, setting the non-standard WCLAIMED bit to
* assure that tg_waitflags is non-zero.
*/
group->tg_waitflags = (uint8_t)options | WCLAIMED;
/* Save the return status location (which may be NULL) */
group->tg_statloc = stat_loc;
/* We are the waipid() instance that gets the return status */
mystat = true;
}
/* Then wait for the task to exit */
if ((options & WNOHANG) != 0)
{
/* Don't wait if status is not available */
ret = nxsem_trywait(&group->tg_exitsem);
}
else
{
/* Wait if necessary for status to become available */
ret = nxsem_wait(&group->tg_exitsem);
}
group_del_waiter(group);
if (ret < 0)
{
/* Handle the awkward case of whether or not we
* need to nullify the stat_loc value.
*/
if (mystat)
if ((group = ctcb->group) != NULL &&
(atomic_read(&ctcb->flags) & TCB_FLAG_EXIT_PROCESSING) == 0)
{
group->tg_statloc = NULL;
group->tg_waitflags = 0;
}
nxsched_put_tcb(ctcb);
if ((options & WNOHANG) != 0)
{
pid = 0;
/* Lock this group so that it cannot be
* deleted until the wait completes
*/
flags = spin_lock_irqsave(&group->tg_lock);
group->tg_nwaiters++;
DEBUGASSERT(group->tg_nwaiters > 0);
/* "If more than one thread is suspended in waitpid() awaiting
* termination of the same process, exactly one thread will
* return the process status at the time of the target process
* termination." Hmmm.. what do we return to the others?
*/
if (group->tg_waitflags == 0)
{
/* Save the waitpid() options, setting the non-standard
* WCLAIMED bit to assure that tg_waitflags is non-zero.
*/
group->tg_waitflags = (uint8_t)options | WCLAIMED;
/* Save the return status location (which may be NULL) */
group->tg_statloc = stat_loc;
/* We are the waipid() instance
* that gets the return status
*/
mystat = true;
}
/* Then wait for the task to exit */
if ((options & WNOHANG) != 0)
{
/* Don't wait if status is not available */
ret = nxsem_trywait(&group->tg_exitsem);
}
else
{
/* Wait if necessary for status to become available */
spin_unlock_irqrestore(&group->tg_lock, flags);
ret = nxsem_wait(&group->tg_exitsem);
flags = spin_lock_irqsave(&group->tg_lock);
}
group->tg_nwaiters--;
if (ret < 0)
{
/* Handle the awkward case of whether or not we
* need to nullify the stat_loc value.
*/
if (mystat)
{
group->tg_statloc = NULL;
group->tg_waitflags = 0;
}
if ((options & WNOHANG) != 0)
{
pid = 0;
}
else
{
pid = ret;
}
}
/* On success, return the PID */
ret = pid;
spin_unlock_irqrestore(&group->tg_lock, flags);
group_drop(group);
}
else
{
goto errout;
nxsched_put_tcb(ctcb);
}
}
/* On success, return the PID */
ret = pid;
errout:
leave_critical_section(flags);
return ret;
}
@ -220,16 +222,15 @@ pid_t nxsched_waitpid(pid_t pid, int *stat_loc, int options)
FAR struct child_status_s *child = NULL;
bool retains;
#endif
struct siginfo info;
FAR struct siginfo info;
irqstate_t flags;
sigset_t set;
int ret;
int ret = OK;
/* Create a signal set that contains only SIGCHLD */
sigemptyset(&set);
nxsig_addset(&set, SIGCHLD);
flags = enter_critical_section();
/* Verify that this task actually has children and that the requested PID
* is actually a child of this task.
@ -238,12 +239,12 @@ pid_t nxsched_waitpid(pid_t pid, int *stat_loc, int options)
#ifdef CONFIG_SCHED_CHILD_STATUS
/* Does this task retain child status? */
retains = ((rtcb->group->tg_flags & GROUP_FLAG_NOCLDWAIT) == 0);
retains = ((atomic_read(&rtcb->group->tg_flags) &
GROUP_FLAG_NOCLDWAIT) == 0);
if (rtcb->group->tg_children == NULL && retains)
{
ret = -ECHILD;
goto errout;
}
else if (pid != INVALID_PROCESS_ID)
{
@ -259,34 +260,32 @@ pid_t nxsched_waitpid(pid_t pid, int *stat_loc, int options)
if (ctcb->group->tg_ppid != rtcb->group->tg_pid)
{
ret = -ECHILD;
goto errout;
}
}
nxsched_put_tcb(ctcb);
/* The child task is ours or it is no longer active. Does the parent
* task retain child status?
*/
if (retains)
if (retains && ret == OK)
{
/* Yes.. Check if this specific pid has allocated child status? */
if (group_find_child(rtcb->group, pid) == NULL)
{
ret = -ECHILD;
goto errout;
}
}
}
#else /* CONFIG_SCHED_CHILD_STATUS */
if (rtcb->group->tg_nchildren == 0)
if (atomic_read(&rtcb->group->tg_nchildren) == 0)
{
/* There are no children */
ret = -ECHILD;
goto errout;
}
else if (pid != INVALID_PROCESS_ID)
{
@ -295,18 +294,20 @@ pid_t nxsched_waitpid(pid_t pid, int *stat_loc, int options)
*/
ctcb = nxsched_get_tcb(pid);
if (!ctcb || !ctcb->group || ctcb->group->tg_ppid != rtcb->pid)
if (!ctcb || !ctcb->group || ctcb->group->tg_ppid != rtcb->pid ||
(atomic_read(&ctcb->flags) & TCB_FLAG_EXIT_PROCESSING) != 0)
{
ret = -ECHILD;
goto errout;
}
nxsched_put_tcb(ctcb);
}
#endif /* CONFIG_SCHED_CHILD_STATUS */
/* Loop until the child that we are waiting for dies */
for (; ; )
while (ret >= 0)
{
#ifdef CONFIG_SCHED_CHILD_STATUS
/* Check if the task has already died. Signals are not queued in
@ -335,7 +336,7 @@ pid_t nxsched_waitpid(pid_t pid, int *stat_loc, int options)
*stat_loc = child->ch_status << 8;
}
pid = child->ch_pid;
ret = child->ch_pid;
/* Discard the child entry and break out of the loop */
@ -374,6 +375,8 @@ pid_t nxsched_waitpid(pid_t pid, int *stat_loc, int options)
group_remove_child(rtcb->group, pid);
group_free_child(child);
}
ret = pid;
break;
}
}
@ -394,7 +397,7 @@ pid_t nxsched_waitpid(pid_t pid, int *stat_loc, int options)
*/
ret = -ECHILD;
goto errout;
break;
}
}
@ -406,7 +409,7 @@ pid_t nxsched_waitpid(pid_t pid, int *stat_loc, int options)
* instead).
*/
if (rtcb->group->tg_nchildren == 0 ||
if (atomic_read(&rtcb->group->tg_nchildren) == 0 ||
(pid != INVALID_PROCESS_ID && nxsig_kill(pid, 0) < 0))
{
/* We know that the child task was running okay when we started,
@ -415,23 +418,46 @@ pid_t nxsched_waitpid(pid_t pid, int *stat_loc, int options)
*/
ret = -ECHILD;
goto errout;
break;
}
#endif /* CONFIG_SCHED_CHILD_STATUS */
if ((options & WNOHANG) != 0)
{
pid = 0;
ret = 0;
break;
}
/* Wait for any death-of-child signal */
ret = nxsig_timedwait(&set, &info, NULL);
flags = enter_critical_section();
if (pid != INVALID_PROCESS_ID)
{
ctcb = nxsched_get_tcb(pid);
}
else
{
ctcb = nxsched_get_childtcb(rtcb);
}
if (ctcb && ctcb->group &&
!(atomic_read(&ctcb->group->tg_flags) & GROUP_FLAG_EXITING))
{
ret = nxsig_waitinfo(&set, &info);
}
else
{
ret = -ECHILD;
}
nxsched_put_tcb(ctcb);
leave_critical_section(flags);
if (ret < 0)
{
goto errout;
break;
}
/* Was this the death of the thread we were waiting for? In the of
@ -467,16 +493,11 @@ pid_t nxsched_waitpid(pid_t pid, int *stat_loc, int options)
}
#endif /* CONFIG_SCHED_CHILD_STATUS */
ret = pid;
break;
}
}
/* On success, return the PID */
ret = pid;
errout:
leave_critical_section(flags);
return ret;
}
#endif /* CONFIG_SCHED_HAVE_PARENT */