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:
Xiang Xiao
2020-06-15 07:16:21 -06:00
committed by patacongo
parent 309dda3ef8
commit fd5fc2ab07
7 changed files with 59 additions and 77 deletions
+6 -6
View File
@@ -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 */
+1 -1
View File
@@ -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)
+11 -11
View File
@@ -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 */
+1 -1
View File
@@ -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
+32 -56
View File
@@ -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);
}
/****************************************************************************
+2 -2
View File
@@ -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)
{
+6
View File
@@ -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