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:
parent
c71007323e
commit
fc9f87824c
@ -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 */
|
||||
|
||||
|
@ -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);
|
||||
|
@ -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 */
|
||||
|
||||
|
@ -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? */
|
||||
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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;
|
||||
|
Loading…
Reference in New Issue
Block a user