diff --git a/include/nuttx/sched.h b/include/nuttx/sched.h index 0bc3d1efa17..c7865f2f8de 100644 --- a/include/nuttx/sched.h +++ b/include/nuttx/sched.h @@ -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 */ diff --git a/sched/pthread/pthread.h b/sched/pthread/pthread.h index 82c9bd8a614..f2fd4157bcf 100644 --- a/sched/pthread/pthread.h +++ b/sched/pthread/pthread.h @@ -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) diff --git a/sched/pthread/pthread_cancel.c b/sched/pthread/pthread_cancel.c index ab64a4e77e2..02b8087dd3f 100644 --- a/sched/pthread/pthread_cancel.c +++ b/sched/pthread/pthread_cancel.c @@ -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 */ diff --git a/sched/pthread/pthread_exit.c b/sched/pthread/pthread_exit.c index 740bec88ad5..b77f2c8a5cc 100644 --- a/sched/pthread/pthread_exit.c +++ b/sched/pthread/pthread_exit.c @@ -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 diff --git a/sched/pthread/pthread_mutex.c b/sched/pthread/pthread_mutex.c index 01b3d37d1c1..5648a7ddc24 100644 --- a/sched/pthread/pthread_mutex.c +++ b/sched/pthread/pthread_mutex.c @@ -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); } /**************************************************************************** diff --git a/sched/pthread/pthread_mutexinconsistent.c b/sched/pthread/pthread_mutexinconsistent.c index eb50056d543..d5d7c0abbad 100644 --- a/sched/pthread/pthread_mutexinconsistent.c +++ b/sched/pthread/pthread_mutexinconsistent.c @@ -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) { diff --git a/sched/task/exit.c b/sched/task/exit.c index 5bb9b1c4a05..fed287abfa7 100644 --- a/sched/task/exit.c +++ b/sched/task/exit.c @@ -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