From fc9f87824ca814fb0b711ba9e43da0f4cc470189 Mon Sep 17 00:00:00 2001 From: zhangyuan21 Date: Tue, 23 May 2023 02:26:59 +0800 Subject: [PATCH] sched/pthread: Return ESRCH when the task is in the process of exit. Resolving the issue with the ltp_interfaces_pthread_join_6_2 test case. In SMP mode, the pthread may still be in the process of exiting when pthread_join returns, and calling pthread_join again at this time will result in an error. The error code returned should be ESRCH. Signed-off-by: zhangyuan21 --- include/nuttx/sched.h | 1 + sched/pthread/pthread.h | 4 +- sched/pthread/pthread_completejoin.c | 7 +- sched/pthread/pthread_detach.c | 24 +------ sched/pthread/pthread_findjoininfo.c | 102 ++++++++++++++++++--------- sched/pthread/pthread_join.c | 33 ++------- 6 files changed, 81 insertions(+), 90 deletions(-) diff --git a/include/nuttx/sched.h b/include/nuttx/sched.h index 5a80e6df1e..200a83528e 100644 --- a/include/nuttx/sched.h +++ b/include/nuttx/sched.h @@ -702,6 +702,7 @@ struct pthread_tcb_s pthread_trampoline_t trampoline; /* User-space pthread startup function */ pthread_addr_t arg; /* Startup argument */ FAR void *joininfo; /* Detach-able info to support join */ + bool join_complete; /* Join was completed */ }; #endif /* !CONFIG_DISABLE_PTHREAD */ diff --git a/sched/pthread/pthread.h b/sched/pthread/pthread.h index c02d6bd729..22f2cd3b8b 100644 --- a/sched/pthread/pthread.h +++ b/sched/pthread/pthread.h @@ -84,8 +84,8 @@ int pthread_setup_scheduler(FAR struct pthread_tcb_s *tcb, int priority, int pthread_completejoin(pid_t pid, FAR void *exit_value); void pthread_destroyjoin(FAR struct task_group_s *group, FAR struct join_s *pjoin); -FAR struct join_s *pthread_findjoininfo(FAR struct task_group_s *group, - pid_t pid); +int pthread_findjoininfo(FAR struct task_group_s *group, + pid_t pid, FAR struct join_s **join); void pthread_release(FAR struct task_group_s *group); int pthread_sem_take(FAR sem_t *sem, FAR const struct timespec *abs_timeout); diff --git a/sched/pthread/pthread_completejoin.c b/sched/pthread/pthread_completejoin.c index f65ef9b854..dedabf19a3 100644 --- a/sched/pthread/pthread_completejoin.c +++ b/sched/pthread/pthread_completejoin.c @@ -191,6 +191,7 @@ int pthread_completejoin(pid_t pid, FAR void *exit_value) FAR struct tcb_s *tcb = nxsched_get_tcb(pid); FAR struct task_group_s *group = tcb ? tcb->group : NULL; FAR struct join_s *pjoin; + int ret; sinfo("pid=%d exit_value=%p group=%p\n", pid, exit_value, group); DEBUGASSERT(group && tcb); @@ -198,20 +199,22 @@ int pthread_completejoin(pid_t pid, FAR void *exit_value) /* First, find thread's structure in the private data set. */ nxmutex_lock(&group->tg_joinlock); - pjoin = pthread_findjoininfo(group, pid); - if (!pjoin) + ret = pthread_findjoininfo(group, pid, &pjoin); + if (ret != OK) { nxmutex_unlock(&group->tg_joinlock); return tcb->flags & TCB_FLAG_DETACHED ? OK : ERROR; } else { + FAR struct pthread_tcb_s *ptcb = (FAR struct pthread_tcb_s *)tcb; bool waiters; /* Save the return exit value in the thread structure. */ pjoin->terminated = true; pjoin->exit_value = exit_value; + ptcb->join_complete = true; /* Notify waiters of the availability of the exit value */ diff --git a/sched/pthread/pthread_detach.c b/sched/pthread/pthread_detach.c index 91fa802db1..5aff4a9c76 100644 --- a/sched/pthread/pthread_detach.c +++ b/sched/pthread/pthread_detach.c @@ -73,28 +73,8 @@ int pthread_detach(pthread_t thread) /* Find the entry associated with this pthread. */ nxmutex_lock(&group->tg_joinlock); - pjoin = pthread_findjoininfo(group, (pid_t)thread); - if (!pjoin) - { - FAR struct tcb_s *tcb = nxsched_get_tcb((pid_t)thread); - - serr("ERROR: Could not find thread entry\n"); - - if (tcb == NULL) - { - ret = ESRCH; - } - - /* The thread is still active but has no join info. In that - * case, it must be a task and not a pthread. - */ - - else - { - ret = EINVAL; - } - } - else + ret = pthread_findjoininfo(group, (pid_t)thread, &pjoin); + if (ret == OK) { /* Has the thread already terminated? */ diff --git a/sched/pthread/pthread_findjoininfo.c b/sched/pthread/pthread_findjoininfo.c index 631980aaf5..e781194407 100644 --- a/sched/pthread/pthread_findjoininfo.c +++ b/sched/pthread/pthread_findjoininfo.c @@ -45,35 +45,36 @@ * Input Parameters: * ptcb * + * Output Parameters: + * pjoin - joininfo point + * * Returned Value: - * joininfo point. + * 0 if successful. * * Assumptions: * ****************************************************************************/ -static FAR struct join_s * -pthread_createjoininfo(FAR struct pthread_tcb_s *ptcb) +int pthread_createjoininfo(FAR struct pthread_tcb_s *ptcb, + FAR struct join_s **pjoin) { - FAR struct join_s *pjoin; - /* Allocate a detachable structure to support pthread_join logic */ - pjoin = (FAR struct join_s *)kmm_zalloc(sizeof(struct join_s)); - if (!pjoin) + *pjoin = (FAR struct join_s *)kmm_zalloc(sizeof(struct join_s)); + if (*pjoin == NULL) { serr("ERROR: Failed to allocate join\n"); - return NULL; + return EINVAL; } - pjoin->thread = (pthread_t)ptcb->cmn.pid; + (*pjoin)->thread = (pthread_t)ptcb->cmn.pid; /* Initialize the semaphore in the join structure to zero. */ - if (nxsem_init(&pjoin->exit_sem, 0, 0) < 0) + if (nxsem_init(&(*pjoin)->exit_sem, 0, 0) < 0) { - kmm_free(pjoin); - return NULL; + kmm_free(*pjoin); + return EINVAL; } else { @@ -81,22 +82,22 @@ pthread_createjoininfo(FAR struct pthread_tcb_s *ptcb) /* Attach the join info to the TCB. */ - ptcb->joininfo = (FAR void *)pjoin; + ptcb->joininfo = (FAR void *)(*pjoin); - pjoin->next = NULL; + (*pjoin)->next = NULL; if (!group->tg_jointail) { - group->tg_joinhead = pjoin; + group->tg_joinhead = *pjoin; } else { - group->tg_jointail->next = pjoin; + group->tg_jointail->next = *pjoin; } - group->tg_jointail = pjoin; + group->tg_jointail = *pjoin; } - return pjoin; + return OK; } /**************************************************************************** @@ -113,40 +114,71 @@ pthread_createjoininfo(FAR struct pthread_tcb_s *ptcb) * group - The group that the pid is (or was) a member of * pid - The ID of the pthread * + * Output Parameters: + * pjoin - None or pointer to the found entry + * * Returned Value: - * None or pointer to the found entry. + * 0 if successful. Otherwise, one of the following error codes: + * + * EINVAL The value specified by thread does not refer to joinable + * thread. + * ESRCH No thread could be found corresponding to that specified by the + * given thread ID. * * Assumptions: * The caller has provided protection from re-entrancy. * ****************************************************************************/ -FAR struct join_s *pthread_findjoininfo(FAR struct task_group_s *group, - pid_t pid) +int pthread_findjoininfo(FAR struct task_group_s *group, + pid_t pid, FAR struct join_s **pjoin) { - FAR struct join_s *pjoin; + FAR struct pthread_tcb_s *ptcb; + FAR struct tcb_s *tcb; DEBUGASSERT(group); /* Find the entry with the matching pid */ - for (pjoin = group->tg_joinhead; - (pjoin && (pid_t)pjoin->thread != pid); - pjoin = pjoin->next); + for (*pjoin = group->tg_joinhead; + (*pjoin && (pid_t)(*pjoin)->thread != pid); + *pjoin = (*pjoin)->next); /* and return it */ - if (pjoin == NULL) + if (*pjoin) { - FAR struct tcb_s *tcb = nxsched_get_tcb(pid); - - if (tcb != NULL && (tcb->flags & TCB_FLAG_DETACHED) == 0 && - (tcb->flags & TCB_FLAG_TTYPE_MASK) == TCB_FLAG_TTYPE_PTHREAD && - tcb->group == group) - { - pjoin = pthread_createjoininfo((FAR struct pthread_tcb_s *)tcb); - } + return OK; } - return pjoin; + /* Task has been deleted, return ESRCH */ + + tcb = nxsched_get_tcb(pid); + if (tcb == NULL) + { + return ESRCH; + } + + /* Task was detached or not a pthread, return EINVAL */ + + if ((tcb->flags & TCB_FLAG_DETACHED) != 0 || + (tcb->flags & TCB_FLAG_TTYPE_MASK) != TCB_FLAG_TTYPE_PTHREAD) + { + return EINVAL; + } + + ptcb = (FAR struct pthread_tcb_s *)tcb; + + /* Task was join completed, is in the process + * of being deleted, return ESRCH + */ + + if (ptcb->join_complete) + { + return ESRCH; + } + + /* Else create joininfo for the task */ + + return pthread_createjoininfo(ptcb, pjoin); } diff --git a/sched/pthread/pthread_join.c b/sched/pthread/pthread_join.c index 5a7263bd61..7eda733cd4 100644 --- a/sched/pthread/pthread_join.c +++ b/sched/pthread/pthread_join.c @@ -109,34 +109,8 @@ int pthread_join(pthread_t thread, FAR pthread_addr_t *pexit_value) * was detached and has exited. */ - pjoin = pthread_findjoininfo(group, (pid_t)thread); - if (pjoin == NULL) - { - /* Determine what kind of error to return */ - - FAR struct tcb_s *tcb = nxsched_get_tcb((pid_t)thread); - - swarn("WARNING: Could not find thread data\n"); - - /* Case (1) or (3) -- we can't tell which. Assume (3) */ - - if (tcb == NULL) - { - ret = ESRCH; - } - - /* The thread is still active but has no join info. In that - * case, it must be a task and not a pthread. - */ - - else - { - ret = EINVAL; - } - - nxmutex_unlock(&group->tg_joinlock); - } - else + ret = pthread_findjoininfo(group, (pid_t)thread, &pjoin); + if (ret == OK) { if (pjoin->detached) { @@ -241,10 +215,11 @@ int pthread_join(pthread_t thread, FAR pthread_addr_t *pexit_value) pthread_destroyjoin(group, pjoin); } - nxmutex_unlock(&group->tg_joinlock); ret = OK; } + nxmutex_unlock(&group->tg_joinlock); + leave_cancellation_point(); sinfo("Returning %d\n", ret); return ret;