Merge remote-tracking branch 'origin/master' into ieee802154
This commit is contained in:
commit
51b7668859
@ -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 *************************************************************/
|
||||
|
||||
|
@ -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 */
|
||||
|
||||
|
@ -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
|
||||
|
||||
|
82
libc/pthread/pthread_mutexattr_getrobust.c
Normal file
82
libc/pthread/pthread_mutexattr_getrobust.c
Normal 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;
|
||||
}
|
@ -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
|
||||
}
|
||||
|
||||
|
96
libc/pthread/pthread_mutexattr_setrobust.c
Normal file
96
libc/pthread/pthread_mutexattr_setrobust.c
Normal 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
|
||||
}
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
|
@ -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 */
|
||||
|
||||
|
@ -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
|
||||
|
@ -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().
|
||||
*/
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user