* Included Files
********************************************************************************/
-#include <tinyara/config.h> /* Default settings */
+#include <tinyara/config.h> /* Default settings */
#include <tinyara/compiler.h> /* Compiler settings, noreturn_function */
-#include <sys/types.h> /* Needed for general types */
-#include <sys/prctl.h> /* Needed by pthread_[set|get]name_np */
+#include <sys/types.h> /* Needed for general types */
+#include <sys/prctl.h> /* Needed by pthread_[set|get]name_np */
-#include <stdint.h> /* C99 fixed width integer types */
-#include <stdbool.h> /* C99 boolean types */
-#include <unistd.h> /* For getpid */
-#include <signal.h> /* Needed for sigset_t */
-#include <time.h> /* Needed for struct timespec */
+#include <stdint.h> /* C99 fixed width integer types */
+#include <stdbool.h> /* C99 boolean types */
+#include <unistd.h> /* For getpid */
+#include <signal.h> /* Needed for sigset_t */
+#include <time.h> /* Needed for struct timespec */
#include <tinyara/semaphore.h> /* For sem_t and SEM_PRIO_* defines */
#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_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
* mappings to prctl, they will return 0 on success and -1 on failure with the
typedef int pthread_key_t;
typedef FAR void *pthread_addr_t;
-typedef pthread_addr_t (*pthread_startroutine_t)(pthread_addr_t);
+typedef pthread_addr_t(*pthread_startroutine_t)(pthread_addr_t);
typedef pthread_startroutine_t pthread_func_t;
/**
typedef struct pthread_cond_s pthread_cond_t;
#define PTHREAD_COND_INITIALIZER { {0, 0xffff} }
-#define _PTHREAD_MFLAGS_ROBUST (1 << 0) /* Robust (NORMAL) mutex */
-#define _PTHREAD_MFLAGS_INCONSISTENT (1 << 1) /* Mutex is in an inconsistent state */
-#define _PTHREAD_MFLAGS_NOTRECOVRABLE (1 << 2) /* Inconsistent mutex has been unlocked */
-
/**
* @ingroup PTHREAD_KERNEL
* @brief Structure of pthread mutex attr configuration
*/
struct pthread_mutexattr_s {
- uint8_t pshared; /* PTHREAD_PROCESS_PRIVATE or PTHREAD_PROCESS_SHARED */
+ uint8_t pshared; /* PTHREAD_PROCESS_PRIVATE or PTHREAD_PROCESS_SHARED */
#ifdef CONFIG_PRIORITY_INHERITANCE
- uint8_t proto; /* See PTHREAD_PRIO_* definitions */
+ uint8_t proto; /* See PTHREAD_PRIO_* definitions */
#endif
#ifdef CONFIG_MUTEX_TYPES
- uint8_t type; /* Type of the mutex. See PTHREAD_MUTEX_* definitions */
+ uint8_t type; /* Type of the mutex. See PTHREAD_MUTEX_* definitions */
#endif
};
typedef struct pthread_mutexattr_s pthread_mutexattr_t;
struct pthread_mutex_s {
#ifndef CONFIG_PTHREAD_MUTEX_UNSAFE
- /* Supports a singly linked list */
+ /* Supports a singly linked list */
- FAR struct pthread_mutex_s *flink;
+ FAR struct pthread_mutex_s *flink;
#endif
/* Payload */
- sem_t sem; /* Semaphore underlying the implementation of the mutex */
- int pid; /* ID of the holder of the mutex */
+ sem_t sem; /* Semaphore underlying the implementation of the mutex */
+ int pid; /* ID of the holder of the mutex */
#ifndef CONFIG_PTHREAD_MUTEX_UNSAFE
- uint8_t flags; /* See _PTHREAD_MFLAGS_* */
+ uint8_t flags; /* See _PTHREAD_MFLAGS_* */
#endif
#ifdef CONFIG_MUTEX_TYPES
- uint8_t type; /* Type of the mutex. See PTHREAD_MUTEX_* definitions */
- int nlocks; /* The number of recursive locks held */
+ uint8_t type; /* Type of the mutex. See PTHREAD_MUTEX_* definitions */
+ int nlocks; /* The number of recursive locks held */
#endif
};
typedef struct pthread_mutex_s pthread_mutex_t;
#define __PTHREAD_MUTEX_T_DEFINED 1
#ifndef CONFIG_PTHREAD_MUTEX_UNSAFE
-# ifdef CONFIG_PTHREAD_MUTEX_DEFAULT_UNSAFE
-# define __PTHREAD_MUTEX_DEFAULT_FLAGS 0
-# else
-# define __PTHREAD_MUTEX_DEFAULT_FLAGS _PTHREAD_MFLAGS_ROBUST
-# endif
+#ifdef CONFIG_PTHREAD_MUTEX_DEFAULT_UNSAFE
+#define __PTHREAD_MUTEX_DEFAULT_FLAGS 0
+#else
+#define __PTHREAD_MUTEX_DEFAULT_FLAGS _PTHREAD_MFLAGS_ROBUST
+#endif
#endif
#if defined(CONFIG_MUTEX_TYPES) && !defined(CONFIG_PTHREAD_MUTEX_UNSAFE)
-# define PTHREAD_MUTEX_INITIALIZER {NULL, SEM_INITIALIZER(1), -1, \
+#define PTHREAD_MUTEX_INITIALIZER {NULL, SEM_INITIALIZER(1), -1, \
__PTHREAD_MUTEX_DEFAULT_FLAGS, \
PTHREAD_MUTEX_DEFAULT, 0}
#elif defined(CONFIG_MUTEX_TYPES)
-# define PTHREAD_MUTEX_INITIALIZER {SEM_INITIALIZER(1), -1, \
+#define PTHREAD_MUTEX_INITIALIZER {SEM_INITIALIZER(1), -1, \
PTHREAD_MUTEX_DEFAULT, 0}
#elif !defined(CONFIG_PTHREAD_MUTEX_UNSAFE)
-# define PTHREAD_MUTEX_INITIALIZER {NULL, SEM_INITIALIZER(1), -1,\
+#define PTHREAD_MUTEX_INITIALIZER {NULL, SEM_INITIALIZER(1), -1,\
__PTHREAD_MUTEX_DEFAULT_FLAGS}
#else
-# define PTHREAD_MUTEX_INITIALIZER {SEM_INITIALIZER(1), -1}
+#define PTHREAD_MUTEX_INITIALIZER {SEM_INITIALIZER(1), -1}
#endif
/**
#ifdef CONFIG_PRIORITY_INHERITANCE
/* Manage priority inheritance */
-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_getprotocol(FAR const pthread_mutexattr_t *attr, FAR int *protocol);
+int pthread_mutexattr_setprotocol(FAR pthread_mutexattr_t *attr, int protocol);
#endif
/* A thread can create and delete condition variables. */
*/
int pthread_barrierattr_setpshared(FAR pthread_barrierattr_t *attr, int pshared);
/**
- * @} */ //end for PTHREAD_KERNEL
+ * @} *///end for PTHREAD_KERNEL
#ifdef __cplusplus
}
* POSSIBILITY OF SUCH DAMAGE.
****************************************************************************/
-
/****************************************************************************
* Included Files
****************************************************************************/
int pthread_mutex_consistent(FAR pthread_mutex_t *mutex)
{
- int ret = EINVAL;
- int status;
-
- svdbg("mutex=0x%p\n", mutex);
- DEBUGASSERT(mutex != NULL);
-
- if (mutex != NULL)
- {
- /* Make sure the mutex is stable while we make the following checks. */
-
- sched_lock();
-
- /* Is the mutex available? */
-
- DEBUGASSERT(mutex->pid != 0); /* < 0: available, >0 owned, ==0 error */
- if (mutex->pid >= 0)
- {
- /* No.. Verify that the thread associated with the PID still
- * exists. We may be destroying the mutex after cancelling a
- * pthread and the mutex may have been in a bad state owned by
- * the dead pthread. NOTE: The following is unspecified behavior
- * (see pthread_mutex_consistent()).
- *
- * If the holding thread is still valid, then we should be able to
- * map its PID to the underlying TCB. That is what sched_gettcb()
- * does.
- */
-
- if (sched_gettcb(mutex->pid) == NULL)
- {
- /* The thread associated with the PID no longer exists */
-
- mutex->pid = -1;
- mutex->flags = 0;
+ int ret = EINVAL;
+ int status;
+
+ svdbg("mutex=0x%p\n", mutex);
+ DEBUGASSERT(mutex != NULL);
+
+ if (mutex != NULL) {
+ /* Make sure the mutex is stable while we make the following checks. */
+
+ sched_lock();
+
+ /* Is the mutex available? */
+
+ DEBUGASSERT(mutex->pid != 0); /* < 0: available, >0 owned, ==0 error */
+ if (mutex->pid >= 0) {
+ /* No.. Verify that the thread associated with the PID still
+ * exists. We may be destroying the mutex after cancelling a
+ * pthread and the mutex may have been in a bad state owned by
+ * the dead pthread. NOTE: The following is unspecified behavior
+ * (see pthread_mutex_consistent()).
+ *
+ * If the holding thread is still valid, then we should be able to
+ * map its PID to the underlying TCB. That is what sched_gettcb()
+ * does.
+ */
+
+ if (sched_gettcb(mutex->pid) == NULL) {
+ /* The thread associated with the PID no longer exists */
+
+ mutex->pid = -1;
+ mutex->flags &= _PTHREAD_MFLAGS_ROBUST;
#ifdef CONFIG_MUTEX_TYPES
- mutex->nlocks = 0;
+ mutex->nlocks = 0;
#endif
- /* Reset the semaphore. This has the same affect as if the
- * dead task had called pthread_mutex_unlock().
- */
-
- status = sem_reset((FAR sem_t *)&mutex->sem, 1);
- ret = (status != OK) ? get_errno() : OK;
- }
-
- /* Otherwise the mutex is held by some active thread. Let's not
- * touch anything!
- */
- }
- else
- {
- /* There is no holder of the mutex. Just make sure the
- * inconsistent flag is cleared and the number of locks is zero.
- */
-
- mutex->flags &= _PTHREAD_MFLAGS_ROBUST;
+ /* Reset the semaphore. This has the same affect as if the
+ * dead task had called pthread_mutex_unlock().
+ */
+
+ status = sem_reset((FAR sem_t *)&mutex->sem, 1);
+ ret = (status != OK) ? get_errno() : OK;
+ }
+
+ /* Otherwise the mutex is held by some active thread. Let's not
+ * touch anything!
+ */
+ } else {
+ /* There is no holder of the mutex. Just make sure the
+ * inconsistent flag is cleared and the number of locks is zero.
+ */
+
+ mutex->flags &= _PTHREAD_MFLAGS_ROBUST;
#ifdef CONFIG_MUTEX_TYPES
- mutex->nlocks = 0;
+ mutex->nlocks = 0;
#endif
- }
+ }
- sched_unlock();
- ret = OK;
- }
+ sched_unlock();
+ ret = OK;
+ }
- svdbg("Returning %d\n", ret);
- return ret;
+ svdbg("Returning %d\n", ret);
+ return ret;
}
* where the holder of the mutex has exitted without unlocking it.
*/
- 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);
* where the holder of the mutex has exitted without unlocking it.
*/
- if (mutex->pid > 0 && sched_gettcb(mutex->pid) == NULL) {
+#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);
svdbg("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.
+ 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 error (default behavior is like PTHREAD_MUTEX_ERRORCHECK) */
sdbg("Holder=%d returning EPERM\n", mutex->pid);
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? */
-
- 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
- * success.
- */
- mutex->nlocks--;
- ret = OK;
- }
- 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.
- */
-
-
- {
- /* Nullify the pid and lock count then post the semaphore */
-
- mutex->pid = -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
+ * success.
+ */
+ mutex->nlocks--;
+ ret = OK;
+ } 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.
+ */
+
+ {
+ /* Nullify the pid and lock count then post the semaphore */
+
+ mutex->pid = -1;
#ifdef CONFIG_MUTEX_TYPES
- mutex->nlocks = 0;
+ mutex->nlocks = 0;
#endif
- ret = pthread_mutex_give(mutex);
- }
- sched_unlock();
+ ret = pthread_mutex_give(mutex);
+ }
}
+ sched_unlock();
svdbg("Returning %d\n", ret);
return ret;
}