mirror of
https://github.com/apache/nuttx.git
synced 2026-09-26 09:54:24 +08:00
sched: Check the mutex consistent in main thread too
Signed-off-by: Xiang Xiao <xiaoxiang@xiaomi.com> Change-Id: I2d91154572805699237cfc028202021c8f8eee40
This commit is contained in:
@@ -714,6 +714,12 @@ struct tcb_s
|
||||
FAR struct mqueue_inode_s *msgwaitq; /* Waiting for this message queue */
|
||||
#endif
|
||||
|
||||
/* Robust mutex support *******************************************************/
|
||||
|
||||
#if !defined(CONFIG_DISABLE_PTHREAD) && !defined(CONFIG_PTHREAD_MUTEX_UNSAFE)
|
||||
FAR struct pthread_mutex_s *mhead; /* List of mutexes held by thread */
|
||||
#endif
|
||||
|
||||
/* Clean-up stack *************************************************************/
|
||||
|
||||
#ifdef CONFIG_PTHREAD_CLEANUP
|
||||
@@ -796,12 +802,6 @@ struct pthread_tcb_s
|
||||
|
||||
pthread_addr_t arg; /* Startup argument */
|
||||
FAR void *joininfo; /* Detach-able info to support join */
|
||||
|
||||
/* Robust mutex support *******************************************************/
|
||||
|
||||
#ifndef CONFIG_PTHREAD_MUTEX_UNSAFE
|
||||
FAR struct pthread_mutex_s *mhead; /* List of mutexes held by thread */
|
||||
#endif
|
||||
};
|
||||
#endif /* !CONFIG_DISABLE_PTHREAD */
|
||||
|
||||
|
||||
@@ -121,7 +121,7 @@ int pthread_mutex_take(FAR struct pthread_mutex_s *mutex,
|
||||
FAR const struct timespec *abs_timeout, bool intr);
|
||||
int pthread_mutex_trytake(FAR struct pthread_mutex_s *mutex);
|
||||
int pthread_mutex_give(FAR struct pthread_mutex_s *mutex);
|
||||
void pthread_mutex_inconsistent(FAR struct pthread_tcb_s *tcb);
|
||||
void pthread_mutex_inconsistent(FAR struct tcb_s *tcb);
|
||||
#else
|
||||
# define pthread_mutex_take(m,abs_timeout,i) pthread_sem_take(&(m)->sem,(abs_timeout),(i))
|
||||
# define pthread_mutex_trytake(m) pthread_sem_trytake(&(m)->sem)
|
||||
|
||||
@@ -39,7 +39,7 @@
|
||||
|
||||
int pthread_cancel(pthread_t thread)
|
||||
{
|
||||
FAR struct pthread_tcb_s *tcb;
|
||||
FAR struct tcb_s *tcb;
|
||||
|
||||
/* First, make sure that the handle references a valid thread */
|
||||
|
||||
@@ -52,7 +52,7 @@ int pthread_cancel(pthread_t thread)
|
||||
return ESRCH;
|
||||
}
|
||||
|
||||
tcb = (FAR struct pthread_tcb_s *)nxsched_get_tcb((pid_t)thread);
|
||||
tcb = nxsched_get_tcb((pid_t)thread);
|
||||
if (tcb == NULL)
|
||||
{
|
||||
/* The pid does not correspond to any known thread. The thread
|
||||
@@ -64,7 +64,7 @@ int pthread_cancel(pthread_t thread)
|
||||
|
||||
/* Only pthreads should use this interface */
|
||||
|
||||
DEBUGASSERT((tcb->cmn.flags & TCB_FLAG_TTYPE_MASK) ==
|
||||
DEBUGASSERT((tcb->flags & TCB_FLAG_TTYPE_MASK) ==
|
||||
TCB_FLAG_TTYPE_PTHREAD);
|
||||
|
||||
/* Check to see if this thread has the non-cancelable bit set in its
|
||||
@@ -73,7 +73,7 @@ int pthread_cancel(pthread_t thread)
|
||||
*/
|
||||
|
||||
sched_lock();
|
||||
if ((tcb->cmn.flags & TCB_FLAG_NONCANCELABLE) != 0)
|
||||
if ((tcb->flags & TCB_FLAG_NONCANCELABLE) != 0)
|
||||
{
|
||||
/* Then we cannot cancel the thread now. Here is how this is
|
||||
* supposed to work:
|
||||
@@ -88,7 +88,7 @@ int pthread_cancel(pthread_t thread)
|
||||
* immediately, interrupting the thread with its processing."
|
||||
*/
|
||||
|
||||
tcb->cmn.flags |= TCB_FLAG_CANCEL_PENDING;
|
||||
tcb->flags |= TCB_FLAG_CANCEL_PENDING;
|
||||
sched_unlock();
|
||||
return OK;
|
||||
}
|
||||
@@ -96,21 +96,21 @@ int pthread_cancel(pthread_t thread)
|
||||
#ifdef CONFIG_CANCELLATION_POINTS
|
||||
/* Check if this thread supports deferred cancellation */
|
||||
|
||||
if ((tcb->cmn.flags & TCB_FLAG_CANCEL_DEFERRED) != 0)
|
||||
if ((tcb->flags & TCB_FLAG_CANCEL_DEFERRED) != 0)
|
||||
{
|
||||
/* Then we cannot cancel the thread asynchronously. Mark the
|
||||
* cancellation as pending.
|
||||
*/
|
||||
|
||||
tcb->cmn.flags |= TCB_FLAG_CANCEL_PENDING;
|
||||
tcb->flags |= TCB_FLAG_CANCEL_PENDING;
|
||||
|
||||
/* If the thread is waiting at a cancellation point, then notify of the
|
||||
* cancellation thereby waking the task up with an ECANCELED error.
|
||||
*/
|
||||
|
||||
if (tcb->cmn.cpcount > 0)
|
||||
if (tcb->cpcount > 0)
|
||||
{
|
||||
nxnotify_cancellation(&tcb->cmn);
|
||||
nxnotify_cancellation(tcb);
|
||||
}
|
||||
|
||||
sched_unlock();
|
||||
@@ -126,7 +126,7 @@ int pthread_cancel(pthread_t thread)
|
||||
* same as pthread_exit(PTHREAD_CANCELED).
|
||||
*/
|
||||
|
||||
if (tcb == (FAR struct pthread_tcb_s *)this_task())
|
||||
if (tcb == this_task())
|
||||
{
|
||||
pthread_exit(PTHREAD_CANCELED);
|
||||
}
|
||||
@@ -141,7 +141,7 @@ int pthread_cancel(pthread_t thread)
|
||||
* function will be unable to unlock its own mutexes.
|
||||
*/
|
||||
|
||||
pthread_cleanup_popall((FAR struct tcb_s *)tcb);
|
||||
pthread_cleanup_popall(tcb);
|
||||
#endif
|
||||
|
||||
/* Complete pending join operations */
|
||||
|
||||
@@ -124,7 +124,7 @@ void pthread_exit(FAR void *exit_value)
|
||||
#ifndef CONFIG_PTHREAD_MUTEX_UNSAFE
|
||||
/* Recover any mutexes still held by the canceled thread */
|
||||
|
||||
pthread_mutex_inconsistent((FAR struct pthread_tcb_s *)tcb);
|
||||
pthread_mutex_inconsistent(tcb);
|
||||
#endif
|
||||
|
||||
/* Perform common task termination logic. This will get called again later
|
||||
|
||||
@@ -57,30 +57,16 @@
|
||||
static void pthread_mutex_add(FAR struct pthread_mutex_s *mutex)
|
||||
{
|
||||
FAR struct tcb_s *rtcb = this_task();
|
||||
irqstate_t flags;
|
||||
|
||||
DEBUGASSERT(mutex->flink == NULL);
|
||||
|
||||
/* Check if this is a pthread. The main thread may also lock and unlock
|
||||
* mutexes. The main thread, however, does not participate in the mutex
|
||||
* consistency logic. Presumably, when the main thread exits, all of the
|
||||
* child pthreads will also terminate.
|
||||
*
|
||||
* REVISIT: NuttX does not support that behavior at present; child
|
||||
* pthreads will persist after the main thread exits.
|
||||
*/
|
||||
/* Add the mutex to the list of mutexes held by this pthread */
|
||||
|
||||
if ((rtcb->flags & TCB_FLAG_TTYPE_MASK) == TCB_FLAG_TTYPE_PTHREAD)
|
||||
{
|
||||
FAR struct pthread_tcb_s *ptcb = (FAR struct pthread_tcb_s *)rtcb;
|
||||
irqstate_t flags;
|
||||
|
||||
/* Add the mutex to the list of mutexes held by this pthread */
|
||||
|
||||
flags = enter_critical_section();
|
||||
mutex->flink = ptcb->mhead;
|
||||
ptcb->mhead = mutex;
|
||||
leave_critical_section(flags);
|
||||
}
|
||||
flags = enter_critical_section();
|
||||
mutex->flink = rtcb->mhead;
|
||||
rtcb->mhead = mutex;
|
||||
leave_critical_section(flags);
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
@@ -100,47 +86,37 @@ static void pthread_mutex_add(FAR struct pthread_mutex_s *mutex)
|
||||
static void pthread_mutex_remove(FAR struct pthread_mutex_s *mutex)
|
||||
{
|
||||
FAR struct tcb_s *rtcb = this_task();
|
||||
FAR struct pthread_mutex_s *curr;
|
||||
FAR struct pthread_mutex_s *prev;
|
||||
irqstate_t flags;
|
||||
|
||||
/* Check if this is a pthread. The main thread may also lock and unlock
|
||||
* mutexes. The main thread, however, does not participate in the mutex
|
||||
* consistency logic.
|
||||
flags = enter_critical_section();
|
||||
|
||||
/* Remove the mutex from the list of mutexes held by this task */
|
||||
|
||||
for (prev = NULL, curr = rtcb->mhead;
|
||||
curr != NULL && curr != mutex;
|
||||
prev = curr, curr = curr->flink)
|
||||
{
|
||||
}
|
||||
|
||||
DEBUGASSERT(curr == mutex);
|
||||
|
||||
/* Remove the mutex from the list. prev == NULL means that the mutex
|
||||
* to be removed is at the head of the list.
|
||||
*/
|
||||
|
||||
if ((rtcb->flags & TCB_FLAG_TTYPE_MASK) == TCB_FLAG_TTYPE_PTHREAD)
|
||||
if (prev == NULL)
|
||||
{
|
||||
FAR struct pthread_tcb_s *ptcb = (FAR struct pthread_tcb_s *)rtcb;
|
||||
FAR struct pthread_mutex_s *curr;
|
||||
FAR struct pthread_mutex_s *prev;
|
||||
irqstate_t flags;
|
||||
|
||||
flags = enter_critical_section();
|
||||
|
||||
/* Remove the mutex from the list of mutexes held by this task */
|
||||
|
||||
for (prev = NULL, curr = ptcb->mhead;
|
||||
curr != NULL && curr != mutex;
|
||||
prev = curr, curr = curr->flink)
|
||||
{
|
||||
}
|
||||
|
||||
DEBUGASSERT(curr == mutex);
|
||||
|
||||
/* Remove the mutex from the list. prev == NULL means that the mutex
|
||||
* to be removed is at the head of the list.
|
||||
*/
|
||||
|
||||
if (prev == NULL)
|
||||
{
|
||||
ptcb->mhead = mutex->flink;
|
||||
}
|
||||
else
|
||||
{
|
||||
prev->flink = mutex->flink;
|
||||
}
|
||||
|
||||
mutex->flink = NULL;
|
||||
leave_critical_section(flags);
|
||||
rtcb->mhead = mutex->flink;
|
||||
}
|
||||
else
|
||||
{
|
||||
prev->flink = mutex->flink;
|
||||
}
|
||||
|
||||
mutex->flink = NULL;
|
||||
leave_critical_section(flags);
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
|
||||
@@ -71,7 +71,7 @@
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
void pthread_mutex_inconsistent(FAR struct pthread_tcb_s *tcb)
|
||||
void pthread_mutex_inconsistent(FAR struct tcb_s *tcb)
|
||||
{
|
||||
FAR struct pthread_mutex_s *mutex;
|
||||
irqstate_t flags;
|
||||
@@ -80,7 +80,7 @@ void pthread_mutex_inconsistent(FAR struct pthread_tcb_s *tcb)
|
||||
|
||||
sched_lock();
|
||||
|
||||
/* Remove and process each mutex from the list of mutexes held by this task */
|
||||
/* Remove and process each mutex held by this task */
|
||||
|
||||
while (tcb->mhead != NULL)
|
||||
{
|
||||
|
||||
@@ -93,6 +93,12 @@ void exit(int status)
|
||||
pthread_cleanup_popall(tcb);
|
||||
#endif
|
||||
|
||||
#if !defined(CONFIG_DISABLE_PTHREAD) && !defined(CONFIG_PTHREAD_MUTEX_UNSAFE)
|
||||
/* Recover any mutexes still held by the canceled thread */
|
||||
|
||||
pthread_mutex_inconsistent(tcb);
|
||||
#endif
|
||||
|
||||
/* Perform common task termination logic. This will get called again later
|
||||
* through logic kicked off by _exit(). However, we need to call it before
|
||||
* calling _exit() in order to handle atexit() and on_exit() callbacks and
|
||||
|
||||
Reference in New Issue
Block a user