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 <zhangyuan21@xiaomi.com>
This commit is contained in:
zhangyuan21 2023-05-23 02:26:59 +08:00 committed by Alan Carvalho de Assis
parent c71007323e
commit fc9f87824c
6 changed files with 81 additions and 90 deletions

View File

@ -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 */

View File

@ -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);

View File

@ -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 */

View File

@ -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? */

View File

@ -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);
}

View File

@ -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;