Merge remote-tracking branch 'origin/master' into ieee802154

This commit is contained in:
Gregory Nutt 2017-03-27 09:01:15 -06:00
commit 51b7668859
16 changed files with 437 additions and 33 deletions

View File

@ -699,7 +699,9 @@ struct pthread_tcb_s
/* Robust mutex support *******************************************************/
#ifndef CONFIG_PTHREAD_MUTEX_UNSAFE
FAR struct pthread_mutex_s *mhead; /* List of mutexes held by thread */
#endif
/* Clean-up stack *************************************************************/

View File

@ -143,12 +143,42 @@
#define PTHREAD_PRIO_INHERIT SEM_PRIO_INHERIT
#define PTHREAD_PRIO_PROTECT SEM_PRIO_PROTECT
/* Values for robust argument of pthread_mutexattr_get/setrobust
*
* PTHREAD_MUTEX_STALLED - No special actions are taken if the owner of the
* mutex is terminated while holding the mutex lock. This can lead to
* deadlocks if no other thread can unlock the mutex. This is the standard
* default value (NuttX permits you to override that default behavior
* with a configuration option).
*
* PTHREAD_MUTEX_ROBUST - If the process containing the owning thread of a
* robust mutex terminates while holding the mutex lock, the next thread
* that acquires the mutex will be notified about the termination by the
* return value EOWNERDEAD from the locking function. If the owning thread
* of a robust mutex terminates while holding the mutex lock, the next
* thread that attempts to acquire the mutex may be notified about the
* termination by the return value EOWNERDEAD. The notified thread can
* then attempt to make the state protected by the mutex consistent again,
* and if successful can mark the mutex state as consistent by calling
* pthread_mutex_consistent(). After a subsequent successful call to
* pthread_mutex_unlock(), the mutex lock will be released and can be used
* normally by other threads. If the mutex is unlocked without a call to
* pthread_mutex_consistent(), it will be in a permanently unusable state
* and all attempts to lock the mutex will fail with the error
* ENOTRECOVERABLE. The only permissible operation on such a mutex is
* pthread_mutex_destroy().
*/
#define PTHREAD_MUTEX_STALLED 0
#define PTHREAD_MUTEX_ROBUST 1
/* Values for struct pthread_mutex_s flags. These are non-standard and
* intended only for internal use within the OS.
*/
#define _PTHREAD_MFLAGS_INCONSISTENT (1 << 0) /* Mutex is in an inconsistent state */
#define _PTHREAD_MFLAGS_NOTRECOVRABLE (1 << 1) /* Inconsistent mutex has been unlocked */
#define _PTHREAD_MFLAGS_ROBUST (1 << 0) /* Robust (NORMAL) mutex */
#define _PTHREAD_MFLAGS_INCONSISTENT (1 << 1) /* Mutex is in an inconsistent state */
#define _PTHREAD_MFLAGS_NRECOVERABLE (1 << 2) /* Inconsistent mutex has been unlocked */
/* Definitions to map some non-standard, BSD thread management interfaces to
* the non-standard Linux-like prctl() interface. Since these are simple
@ -226,12 +256,15 @@ typedef struct pthread_cond_s pthread_cond_t;
struct pthread_mutexattr_s
{
uint8_t pshared; /* PTHREAD_PROCESS_PRIVATE or PTHREAD_PROCESS_SHARED */
uint8_t pshared : 1; /* PTHREAD_PROCESS_PRIVATE or PTHREAD_PROCESS_SHARED */
#ifdef CONFIG_PRIORITY_INHERITANCE
uint8_t proto; /* See PTHREAD_PRIO_* definitions */
uint8_t proto : 2; /* See PTHREAD_PRIO_* definitions */
#endif
#ifdef CONFIG_MUTEX_TYPES
uint8_t type; /* Type of the mutex. See PTHREAD_MUTEX_* definitions */
uint8_t type : 2; /* Type of the mutex. See PTHREAD_MUTEX_* definitions */
#endif
#ifdef CONFIG_PTHREAD_MUTEX_BOTH
uint8_t robust : 1; /* PTHREAD_MUTEX_STALLED or PTHREAD_MUTEX_ROBUST */
#endif
};
@ -240,15 +273,19 @@ typedef struct pthread_mutexattr_s pthread_mutexattr_t;
struct pthread_mutex_s
{
#ifndef CONFIG_PTHREAD_MUTEX_UNSAFE
/* Supports a singly linked list */
FAR struct pthread_mutex_s *flink;
#endif
/* Payload */
sem_t sem; /* Semaphore underlying the implementation of the mutex */
pid_t pid; /* ID of the holder of the mutex */
#ifndef CONFIG_PTHREAD_MUTEX_UNSAFE
uint8_t flags; /* See _PTHREAD_MFLAGS_* */
#endif
#ifdef CONFIG_MUTEX_TYPES
uint8_t type; /* Type of the mutex. See PTHREAD_MUTEX_* definitions */
int16_t nlocks; /* The number of recursive locks held */
@ -428,6 +465,10 @@ int pthread_mutexattr_getprotocol(FAR const pthread_mutexattr_t *attr,
FAR int *protocol);
int pthread_mutexattr_setprotocol(FAR pthread_mutexattr_t *attr,
int protocol);
int pthread_mutexattr_getrobust(FAR const pthread_mutexattr_t *attr,
FAR int *robust);
int pthread_mutexattr_setrobust(FAR pthread_mutexattr_t *attr,
int robust);
/* The following routines create, delete, lock and unlock mutexes. */
@ -438,9 +479,11 @@ int pthread_mutex_lock(FAR pthread_mutex_t *mutex);
int pthread_mutex_trylock(FAR pthread_mutex_t *mutex);
int pthread_mutex_unlock(FAR pthread_mutex_t *mutex);
#ifndef CONFIG_PTHREAD_MUTEX_UNSAFE
/* Make sure that the pthread mutex is in a consistent state */
int pthread_mutex_consistent(FAR pthread_mutex_t *mutex);
#endif
/* Operations on condition variables */

View File

@ -49,6 +49,7 @@ CSRCS += pthread_mutexattr_init.c pthread_mutexattr_destroy.c
CSRCS += pthread_mutexattr_getpshared.c pthread_mutexattr_setpshared.c
CSRCS += pthread_mutexattr_setprotocol.c pthread_mutexattr_getprotocol.c
CSRCS += pthread_mutexattr_settype.c pthread_mutexattr_gettype.c
CSRCS += pthread_mutexattr_setrobust.c pthread_mutexattr_getrobust.c
CSRCS += pthread_setcancelstate.c pthread_setcanceltype.c
CSRCS += pthread_testcancel.c

View File

@ -0,0 +1,82 @@
/****************************************************************************
* libc/pthread/pthread_mutexattr_getrobust.c
*
* Copyright (C) 2017 Gregory Nutt. All rights reserved.
* Author: Gregory Nutt <gnutt@nuttx.org>
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
* 3. Neither the name NuttX nor the names of its contributors may be
* used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
* OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
* AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
****************************************************************************/
/****************************************************************************
* Included Files
****************************************************************************/
#include <nuttx/config.h>
#include <pthread.h>
#include <errno.h>
/****************************************************************************
* Public Functions
****************************************************************************/
/****************************************************************************
* Function: pthread_mutexattr_getrobust
*
* Description:
* Return the mutex robustneess from the mutex attributes.
*
* Parameters:
* attr - The mutex attributes to query
* robust - Location to return the robustness indication
*
* Return Value:
* 0, if the robustness was successfully return in 'robust', or
* EINVAL, if any NULL pointers provided.
*
* Assumptions:
*
****************************************************************************/
int pthread_mutexattr_getrobust(FAR const pthread_mutexattr_t *attr,
FAR int *robust)
{
if (attr != NULL && robust != NULL)
{
#if defined(CONFIG_PTHREAD_MUTEX_UNSAFE)
*robust = PTHREAD_MUTEX_STALLED;
#elif defined(CONFIG_PTHREAD_MUTEX_BOTH)
*robust = attr->robust;
#else /* Default: CONFIG_PTHREAD_MUTEX_ROBUST */
*robust = PTHREAD_MUTEX_ROBUST;
#endif
return 0;
}
return EINVAL;
}

View File

@ -76,11 +76,21 @@ int pthread_mutexattr_init(FAR pthread_mutexattr_t *attr)
else
{
attr->pshared = 0;
#ifdef CONFIG_PRIORITY_INHERITANCE
attr->proto = SEM_PRIO_INHERIT;
#endif
#ifdef CONFIG_MUTEX_TYPES
attr->type = PTHREAD_MUTEX_DEFAULT;
#endif
#ifdef CONFIG_PTHREAD_MUTEX_BOTH
#ifdef CONFIG_PTHREAD_MUTEX_DEFAULT_UNSAFE
attr->robust = PTHREAD_MUTEX_STALLED;
#else
attr->robust = PTHREAD_MUTEX_ROBUST;
#endif
#endif
}

View File

@ -0,0 +1,96 @@
/****************************************************************************
* libc/pthread/pthread_mutexattr_setrobust.c
*
* Copyright (C) 201t Gregory Nutt. All rights reserved.
* Author: Gregory Nutt <gnutt@nuttx.org>
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
* 3. Neither the name NuttX nor the names of its contributors may be
* used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
* OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
* AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
****************************************************************************/
/****************************************************************************
* Included Files
****************************************************************************/
#include <nuttx/config.h>
#include <pthread.h>
#include <errno.h>
/****************************************************************************
* Public Functions
****************************************************************************/
/****************************************************************************
* Function: pthread_mutexattr_setrobust
*
* Description:
* Set the mutex robustness in the mutex attributes.
*
* Parameters:
* attr - The mutex attributes in which to set the mutex type.
* robust - The mutex type value to set.
*
* Return Value:
* 0, if the mutex robustness was successfully set in 'attr', or
* EINVAL, if 'attr' is NULL or 'robust' unrecognized.
*
* Assumptions:
*
****************************************************************************/
int pthread_mutexattr_setrobust(pthread_mutexattr_t *attr, int robust)
{
#if defined(CONFIG_PTHREAD_MUTEX_UNSAFE)
if (attr != NULL && robust == PTHREAD_MUTEX_STALLED)
{
return OK;
}
return EINVAL;
#elif defined(CONFIG_PTHREAD_MUTEX_BOTH)
if (attr != NULL && (robust == PTHREAD_MUTEX_STALLED || robust == _PTHREAD_MFLAGS_ROBUST))
{
attr->robust = robust;
return OK;
}
return EINVAL;
#else /* Default: CONFIG_PTHREAD_MUTEX_ROBUST */
if (attr != NULL && robust == _PTHREAD_MFLAGS_ROBUST)
{
return OK;
}
return EINVAL;
#endif
}

View File

@ -531,6 +531,48 @@ config MUTEX_TYPES:
Set to enable support for recursive and errorcheck mutexes. Enables
pthread_mutexattr_settype().
choice
prompt "pthread mutex robustness"
default PTHREAD_MUTEX_ROBUST if !DEFAULT_SMALL
default PTHREAD_UNSAFE if DEFAULT_SMALL
config PTHREAD_MUTEX_ROBUST
bool "Robust mutexes"
---help---
Support only the robust form of the NORMAL mutex.
config PTHREAD_MUTEX_UNSAFE
bool "Traditional unsafe mutexes"
---help---
Support only the traditional non-robust form of the NORMAL mutex.
You should select this option only for backward compatibility with
software you may be porting or, perhaps, if you are trying to minimize
footprint.
config PTHREAD_MUTEX_BOTH
bool "Both robust and unsafe mutexes"
---help---
Support both forms of NORMAL mutexes.
endchoice # pthread mutex robustness
choice
prompt "Default NORMAL mutex robustness"
default PTHREAD_MUTEX_DEFAULT_ROBUST
depends on PTHREAD_MUTEX_BOTH
config PTHREAD_MUTEX_DEFAULT_ROBUST
bool "Robust default"
---help---
The default is robust NORMAL mutexes (non-standard)
config PTHREAD_MUTEX_DEFAULT_UNSAFE
bool "Unsafe default"
---help---
The default is traditional unsafe NORMAL mutexes (standard)
endchoice # Default NORMAL mutex robustness
config NPTHREAD_KEYS
int "Maximum number of pthread keys"
default 4

View File

@ -37,9 +37,8 @@ ifneq ($(CONFIG_DISABLE_PTHREAD),y)
CSRCS += pthread_create.c pthread_exit.c pthread_join.c pthread_detach.c
CSRCS += pthread_yield.c pthread_getschedparam.c pthread_setschedparam.c
CSRCS += pthread_mutexinit.c pthread_mutexdestroy.c pthread_mutex.c
CSRCS += pthread_mutexinit.c pthread_mutexdestroy.c
CSRCS += pthread_mutexlock.c pthread_mutextrylock.c pthread_mutexunlock.c
CSRCS += pthread_mutexconsistent.c pthread_mutexinconsistent.c
CSRCS += pthread_condinit.c pthread_conddestroy.c
CSRCS += pthread_condwait.c pthread_condsignal.c pthread_condbroadcast.c
CSRCS += pthread_barrierinit.c pthread_barrierdestroy.c pthread_barrierwait.c
@ -49,6 +48,10 @@ CSRCS += pthread_keydelete.c
CSRCS += pthread_initialize.c pthread_completejoin.c pthread_findjoininfo.c
CSRCS += pthread_once.c pthread_release.c pthread_setschedprio.c
ifneq ($(CONFIG_PTHREAD_MUTEX_UNSAFE),y)
CSRCS += pthread_mutex.c pthread_mutexconsistent.c pthread_mutexinconsistent.c
endif
ifneq ($(CONFIG_DISABLE_SIGNALS),y)
CSRCS += pthread_condtimedwait.c pthread_kill.c pthread_sigmask.c
endif

View File

@ -109,9 +109,15 @@ FAR struct join_s *pthread_findjoininfo(FAR struct task_group_s *group,
void pthread_release(FAR struct task_group_s *group);
int pthread_takesemaphore(sem_t *sem, bool intr);
int pthread_givesemaphore(sem_t *sem);
#ifndef CONFIG_PTHREAD_MUTEX_UNSAFE
int pthread_mutex_take(FAR struct pthread_mutex_s *mutex, bool intr);
int pthread_mutex_give(FAR struct pthread_mutex_s *mutex);
void pthread_mutex_inconsistent(FAR struct pthread_tcb_s *tcb);
#else
# define pthread_mutex_take(m,i) pthread_takesemaphore(&(m)->sem,(i))
# define pthread_mutex_give(m) pthread_givesemaphore(&(m)->sem)
#endif
#ifdef CONFIG_MUTEX_TYPES
int pthread_mutexattr_verifytype(int type);

View File

@ -162,9 +162,11 @@ int pthread_cancel(pthread_t thread)
(void)pthread_completejoin((pid_t)thread, PTHREAD_CANCELED);
#ifndef CONFIG_PTHREAD_MUTEX_UNSAFE
/* Recover any mutexes still held by the canceled thread */
pthread_mutex_inconsistent(tcb);
#endif
/* Then let task_terminate do the real work */

View File

@ -123,9 +123,11 @@ void pthread_exit(FAR void *exit_value)
exit(EXIT_FAILURE);
}
#ifndef CONFIG_PTHREAD_MUTEX_UNSAFE
/* Recover any mutexes still held by the canceled thread */
pthread_mutex_inconsistent(tcb);
pthread_mutex_inconsistent((FAR struct pthread_tcb_s *)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

View File

@ -118,9 +118,11 @@ int pthread_mutex_consistent(FAR pthread_mutex_t *mutex)
{
/* The thread associated with the PID no longer exists */
mutex->pid = -1;
mutex->flags = 0;
mutex->pid = -1;
mutex->flags &= _PTHREAD_MFLAGS_ROBUST;
#ifdef CONFIG_MUTEX_TYPES
mutex->nlocks = 0;
#endif
/* Reset the semaphore. This has the same affect as if the
* dead task had called pthread_mutex_unlock().
*/

View File

@ -77,6 +77,13 @@ int pthread_mutex_init(FAR pthread_mutex_t *mutex,
#endif
#ifdef CONFIG_PRIORITY_INHERITANCE
uint8_t proto = PTHREAD_PRIO_INHERIT;
#endif
#ifndef CONFIG_PTHREAD_MUTEX_UNSAFE
#ifdef CONFIG_PTHREAD_MUTEX_DEFAULT_UNSAFE
uint8_t robust = PTHREAD_MUTEX_STALLED;
#else
uint8_t robust = PTHREAD_MUTEX_ROBUST;
#endif
#endif
int ret = OK;
int status;
@ -99,6 +106,9 @@ int pthread_mutex_init(FAR pthread_mutex_t *mutex,
#endif
#ifdef CONFIG_MUTEX_TYPES
type = attr->type;
#endif
#ifdef CONFIG_PTHREAD_MUTEX_BOTH
robust = attr->robust;
#endif
}
@ -123,14 +133,17 @@ int pthread_mutex_init(FAR pthread_mutex_t *mutex,
ret = get_errno();
}
#endif
#ifndef CONFIG_PTHREAD_MUTEX_UNSAFE
/* Initial internal fields of the mutex */
mutex->flink = NULL;
mutex->flags = 0;
/* Set up attributes unique to the mutex type */
mutex->flags = (robust == PTHREAD_MUTEX_ROBUST ? _PTHREAD_MFLAGS_ROBUST : 0);
#endif
#ifdef CONFIG_MUTEX_TYPES
/* Set up attributes unique to the mutex type */
mutex->type = type;
mutex->nlocks = 0;
#endif

View File

@ -120,13 +120,15 @@ int pthread_mutex_lock(FAR pthread_mutex_t *mutex)
sched_lock();
/* Does this thread already hold the semaphore? */
#ifdef CONFIG_MUTEX_TYPES
/* All mutex types except for NORMAL (and DEFAULT) will return
* and an error error if the caller does not hold the mutex.
*/
if (mutex->pid == mypid)
if (mutex->type != PTHREAD_MUTEX_NORMAL && mutex->pid == mypid)
{
/* Yes.. Is this a recursive mutex? */
#ifdef CONFIG_MUTEX_TYPES
if (mutex->type == PTHREAD_MUTEX_RECURSIVE)
{
/* Yes... just increment the number of locks held and return
@ -144,7 +146,6 @@ int pthread_mutex_lock(FAR pthread_mutex_t *mutex)
}
}
else
#endif
{
/* No, then we would deadlock... return an error (default
* behavior is like PTHREAD_MUTEX_ERRORCHECK)
@ -160,14 +161,38 @@ int pthread_mutex_lock(FAR pthread_mutex_t *mutex)
ret = EDEADLK;
}
}
else
#endif /* CONFIG_MUTEX_TYPES */
#ifndef CONFIG_PTHREAD_MUTEX_UNSAFE
/* The calling thread does not hold the semaphore. The correct
* behavior for the 'robust' mutex is to verify that the holder of the
* mutex is still valid. This is protection from the case
* where the holder of the mutex has exitted without unlocking it.
*/
else if (mutex->pid > 0 && sched_gettcb(mutex->pid) == NULL)
#ifdef CONFIG_PTHREAD_MUTEX_BOTH
#ifdef CONFIG_MUTEX_TYPES
/* Include check if this is a NORMAL mutex and that it is robust */
if (mutex->pid > 0 &&
((mutex->flags & _PTHREAD_MFLAGS_ROBUST) != 0 ||
mutex->type != PTHREAD_MUTEX_NORMAL) &&
sched_gettcb(mutex->pid) == NULL)
#else /* CONFIG_MUTEX_TYPES */
/* This can only be a NORMAL mutex. Include check if it is robust */
if (mutex->pid > 0 &&
(mutex->flags & _PTHREAD_MFLAGS_ROBUST) != 0 &&
sched_gettcb(mutex->pid) == NULL)
#endif /* CONFIG_MUTEX_TYPES */
#else /* CONFIG_PTHREAD_MUTEX_ROBUST */
/* This mutex is always robust, whatever type it is. */
if (mutex->pid > 0 && sched_gettcb(mutex->pid) == NULL)
#endif
{
DEBUGASSERT(mutex->pid != 0); /* < 0: available, >0 owned, ==0 error */
DEBUGASSERT((mutex->flags & _PTHREAD_MFLAGS_INCONSISTENT) != 0);
@ -182,8 +207,13 @@ int pthread_mutex_lock(FAR pthread_mutex_t *mutex)
ret = EOWNERDEAD;
}
else
#endif /* !CONFIG_PTHREAD_MUTEX_UNSAFE */
{
/* Take the underlying semaphore, waiting if necessary */
/* Take the underlying semaphore, waiting if necessary. NOTE that
* is required to deadlock for the case of the non-robust NORMAL or
* default mutex.
*/
ret = pthread_mutex_take(mutex, true);

View File

@ -124,7 +124,7 @@ int pthread_mutex_trylock(FAR pthread_mutex_t *mutex)
else
{
/* Did it fail because the semaphore was not avaialabl? */
/* Did it fail because the semaphore was not avaialable? */
int errcode = get_errno();
if (errcode == EAGAIN)
@ -148,13 +148,36 @@ int pthread_mutex_trylock(FAR pthread_mutex_t *mutex)
}
else
#endif
#ifndef CONFIG_PTHREAD_MUTEX_UNSAFE
/* The calling thread does not hold the semaphore. The correct
* behavior for the 'robust' mutex is to verify that the holder of
* the mutex is still valid. This is protection from the case
* where the holder of the mutex has exitted without unlocking it.
*/
#ifdef CONFIG_PTHREAD_MUTEX_BOTH
#ifdef CONFIG_MUTEX_TYPES
/* Check if this NORMAL mutex is robust */
if (mutex->pid > 0 &&
((mutex->flags & _PTHREAD_MFLAGS_ROBUST) != 0 ||
mutex->type != PTHREAD_MUTEX_NORMAL) &&
sched_gettcb(mutex->pid) == NULL)
#else /* CONFIG_MUTEX_TYPES */
/* Check if this NORMAL mutex is robust */
if (mutex->pid > 0 &&
(mutex->flags & _PTHREAD_MFLAGS_ROBUST) != 0 &&
sched_gettcb(mutex->pid) == NULL)
#endif /* CONFIG_MUTEX_TYPES */
#else /* CONFIG_PTHREAD_MUTEX_ROBUST */
/* This mutex is always robust, whatever type it is. */
if (mutex->pid > 0 && sched_gettcb(mutex->pid) == NULL)
#endif
{
DEBUGASSERT(mutex->pid != 0); /* < 0: available, >0 owned, ==0 error */
DEBUGASSERT((mutex->flags & _PTHREAD_MFLAGS_INCONSISTENT) != 0);
@ -172,6 +195,8 @@ int pthread_mutex_trylock(FAR pthread_mutex_t *mutex)
/* The mutex is locked by another, active thread */
else
#endif /* CONFIG_PTHREAD_MUTEX_UNSAFE */
{
ret = EBUSY;
}

View File

@ -85,17 +85,55 @@ int pthread_mutex_unlock(FAR pthread_mutex_t *mutex)
sinfo("mutex=0x%p\n", mutex);
DEBUGASSERT(mutex != NULL);
/* Make sure the semaphore is stable while we make the following checks.
* This all needs to be one atomic action.
*/
sched_lock();
if (mutex != NULL)
{
/* Make sure the semaphore is stable while we make the following
* checks. This all needs to be one atomic action.
#if !defined(CONFIG_PTHREAD_MUTEX_UNSAFE) || defined(CONFIG_MUTEX_TYPES)
/* Does the calling thread own the semaphore? If no, should we return
* an error?
*
* Error checking is always performed for ERRORCHECK and RECURSIVE
* mutex types. Error checking is only performed for NORMAL (or
* DEFAULT) mutex type if the NORMAL mutex is robust. That is either:
*
* 1. CONFIG_PTHREAD_MUTEX_ROBUST is defined, or
* 2. CONFIG_PTHREAD_MUTEX_BOTH is defined and the robust flag is set
*/
sched_lock();
/* Does the calling thread own the semaphore? */
#if defined(CONFIG_PTHREAD_MUTEX_ROBUST)
/* Not that error checking is always performed if the configuration has
* CONFIG_PTHREAD_MUTEX_ROBUST defined. Just check if the calling
* thread owns the semaphore.
*/
if (mutex->pid != (int)getpid())
#elif defined(CONFIG_PTHREAD_MUTEX_UNSAFE) && defined(CONFIG_MUTEX_TYPES)
/* If mutex types are not supported, then all mutexes are NORMAL (or
* DEFAULT). Error checking should never be performed for the
* non-robust NORMAL mutex type.
*/
if (mutex->type != PTHREAD_MUTEX_NORMAL && mutex->pid != (int)getpid())
#else /* CONFIG_PTHREAD_MUTEX_BOTH */
/* Skip the error check if this is a non-robust NORMAL mutex */
bool errcheck = ((mutex->flags & _PTHREAD_MFLAGS_ROBUST) != 0);
#ifdef CONFIG_MUTEX_TYPES
errcheck |= (mutex->type != PTHREAD_MUTEX_NORMAL);
#endif
/* Does the calling thread own the semaphore? If not should we report
* the EPERM error?
*/
if (errcheck && mutex->pid != (int)getpid())
#endif
{
/* No... return an EPERM error.
*
@ -111,11 +149,13 @@ int pthread_mutex_unlock(FAR pthread_mutex_t *mutex)
serr("ERROR: Holder=%d returning EPERM\n", mutex->pid);
ret = EPERM;
}
/* Yes, the caller owns the semaphore.. Is this a recursive mutex? */
else
#endif /* !CONFIG_PTHREAD_MUTEX_UNSAFE || CONFIG_MUTEX_TYPES */
#ifdef CONFIG_MUTEX_TYPES
else if (mutex->type == PTHREAD_MUTEX_RECURSIVE && mutex->nlocks > 1)
/* Yes, the caller owns the semaphore.. Is this a recursive mutex? */
if (mutex->type == PTHREAD_MUTEX_RECURSIVE && mutex->nlocks > 1)
{
/* This is a recursive mutex and we there are multiple locks held. Retain
* the mutex lock, just decrement the count of locks held, and return
@ -125,13 +165,19 @@ int pthread_mutex_unlock(FAR pthread_mutex_t *mutex)
mutex->nlocks--;
ret = OK;
}
#endif
else
#endif /* CONFIG_MUTEX_TYPES */
/* This is either a non-recursive mutex or is the outermost unlock of
* a recursive mutex.
*
* In the case where the calling thread is NOT the holder of the thread,
* the behavior is undefined per POSIX. Here we do the same as GLIBC:
* We allow the other thread to release the mutex even though it does
* not own it.
*/
else
{
/* Nullify the pid and lock count then post the semaphore */
@ -141,10 +187,9 @@ int pthread_mutex_unlock(FAR pthread_mutex_t *mutex)
#endif
ret = pthread_mutex_give(mutex);
}
sched_unlock();
}
sched_unlock();
sinfo("Returning %d\n", ret);
return ret;
}