Merge branch 'robust'

This commit is contained in:
Gregory Nutt 2017-03-27 08:51:53 -06:00
commit 9484ac5c22
11 changed files with 352 additions and 23 deletions

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
};
@ -432,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. */

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

@ -549,7 +549,29 @@ choice
software you may be porting or, perhaps, if you are trying to minimize
footprint.
endchoice # thread mutex robustness
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"

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
}
@ -128,7 +138,7 @@ int pthread_mutex_init(FAR pthread_mutex_t *mutex,
/* Initial internal fields of the mutex */
mutex->flink = NULL;
mutex->flags = 0;
mutex->flags = (robust == PTHREAD_MUTEX_ROBUST ? _PTHREAD_MFLAGS_ROBUST : 0);
#endif
#ifdef CONFIG_MUTEX_TYPES

View File

@ -171,7 +171,28 @@ int pthread_mutex_lock(FAR pthread_mutex_t *mutex)
* where the holder of the mutex has exitted without unlocking it.
*/
#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);

View File

@ -156,7 +156,28 @@ int pthread_mutex_trylock(FAR pthread_mutex_t *mutex)
* 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);

View File

@ -85,27 +85,54 @@ 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();
#if !defined(CONFIG_PTHREAD_MUTEX_UNSAFE) || !defined(CONFIG_MUTEX_TYPES)
/* Does the calling thread own the semaphore? Should we report the
* EPERM error? This applies to robust NORMAL (and DEFAULT) mutexes
* as well as ERRORCHECK and RECURSIVE mutexes.
#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())
#else
/* Does the calling thread own the semaphore? Should we report the
* EPERM error? This applies to ERRORCHECK and RECURSIVE mutexes.
#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.
@ -123,6 +150,7 @@ int pthread_mutex_unlock(FAR pthread_mutex_t *mutex)
ret = EPERM;
}
else
#endif /* !CONFIG_PTHREAD_MUTEX_UNSAFE || CONFIG_MUTEX_TYPES */
#ifdef CONFIG_MUTEX_TYPES
/* Yes, the caller owns the semaphore.. Is this a recursive mutex? */
@ -159,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;
}