pthread robust mutexes: Fix memmory trashing problem: the main task may also use mutexes; need to check thread type before accessing pthread-specific mutex data structures. Problem noted by Jussi Kivilinna.

This commit is contained in:
Gregory Nutt
2017-05-31 10:55:37 -06:00
parent 705185be1e
commit 90dda9357e
2 changed files with 117 additions and 46 deletions
+90 -43
View File
@@ -58,7 +58,7 @@
* Name: pthread_mutex_add
*
* Description:
* Add the mutex to the list of mutexes held by this thread.
* Add the mutex to the list of mutexes held by this pthread.
*
* Parameters:
* mutex - The mux to be locked
@@ -70,17 +70,91 @@
static void pthread_mutex_add(FAR struct pthread_mutex_s *mutex)
{
FAR struct pthread_tcb_s *rtcb = (FAR struct pthread_tcb_s *)this_task();
irqstate_t flags;
FAR struct tcb_s *rtcb = this_task();
DEBUGASSERT(mutex->flink == NULL);
/* Add the mutex to the list of mutexes held by this task */
/* 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.
*/
flags = enter_critical_section();
mutex->flink = rtcb->mhead;
rtcb->mhead = mutex;
leave_critical_section(flags);
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);
}
}
/****************************************************************************
* Name: pthread_mutex_remove
*
* Description:
* Remove the mutex to the list of mutexes held by this pthread.
*
* Parameters:
* mutex - The mux to be locked
*
* Return Value:
* None
*
****************************************************************************/
static void pthread_mutex_remove(FAR struct pthread_mutex_s *mutex)
{
FAR struct tcb_s *rtcb = this_task();
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.
*/
if ((rtcb->flags & TCB_FLAG_TTYPE_MASK) == TCB_FLAG_TTYPE_PTHREAD)
{
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);
}
}
/****************************************************************************
@@ -233,8 +307,6 @@ int pthread_mutex_trytake(FAR struct pthread_mutex_s *mutex)
int pthread_mutex_give(FAR struct pthread_mutex_s *mutex)
{
FAR struct pthread_mutex_s *curr;
FAR struct pthread_mutex_s *prev;
int ret = EINVAL;
/* Verify input parameters */
@@ -242,34 +314,9 @@ int pthread_mutex_give(FAR struct pthread_mutex_s *mutex)
DEBUGASSERT(mutex != NULL);
if (mutex != NULL)
{
FAR struct pthread_tcb_s *rtcb = (FAR struct pthread_tcb_s *)this_task();
irqstate_t flags;
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 (prev == NULL)
{
rtcb->mhead = mutex->flink;
}
else
{
prev->flink = mutex->flink;
}
mutex->flink = NULL;
leave_critical_section(flags);
pthread_mutex_remove(mutex);
/* Now release the underlying semaphore */
@@ -300,7 +347,7 @@ int pthread_mutex_give(FAR struct pthread_mutex_s *mutex)
#ifdef CONFIG_CANCELLATION_POINTS
uint16_t pthread_disable_cancel(void)
{
FAR struct pthread_tcb_s *tcb = (FAR struct pthread_tcb_s *)this_task();
FAR struct tcb_s *tcb = this_task();
irqstate_t flags;
uint16_t old;
@@ -309,15 +356,15 @@ uint16_t pthread_disable_cancel(void)
*/
flags = enter_critical_section();
old = tcb->cmn.flags & (TCB_FLAG_CANCEL_PENDING | TCB_FLAG_NONCANCELABLE);
tcb->cmn.flags &= ~(TCB_FLAG_CANCEL_PENDING | TCB_FLAG_NONCANCELABLE);
old = tcb->flags & (TCB_FLAG_CANCEL_PENDING | TCB_FLAG_NONCANCELABLE);
tcb->flags &= ~(TCB_FLAG_CANCEL_PENDING | TCB_FLAG_NONCANCELABLE);
leave_critical_section(flags);
return old;
}
void pthread_enable_cancel(uint16_t cancelflags)
{
FAR struct pthread_tcb_s *tcb = (FAR struct pthread_tcb_s *)this_task();
FAR struct tcb_s *tcb = this_task();
irqstate_t flags;
/* We need perform the following operations from within a critical section
@@ -325,7 +372,7 @@ void pthread_enable_cancel(uint16_t cancelflags)
*/
flags = enter_critical_section();
tcb->cmn.flags |= cancelflags;
tcb->flags |= cancelflags;
/* What should we do if there is a pending cancellation?
*
@@ -337,8 +384,8 @@ void pthread_enable_cancel(uint16_t cancelflags)
* then we need to terminate now by simply calling pthread_exit().
*/
if ((tcb->cmn.flags & TCB_FLAG_CANCEL_DEFERRED) == 0 &&
(tcb->cmn.flags & TCB_FLAG_CANCEL_PENDING) != 0)
if ((tcb->flags & TCB_FLAG_CANCEL_DEFERRED) == 0 &&
(tcb->flags & TCB_FLAG_CANCEL_PENDING) != 0)
{
pthread_exit(NULL);
}