From 8b3c554e45aa0cc643f80ae783b3852766a130c7 Mon Sep 17 00:00:00 2001
From: Gregory Nutt <gnutt@nuttx.org>
Date: Sun, 26 Mar 2017 17:37:28 -0600
Subject: [PATCH 1/4] pthreads:  Add a configuration option to disable robust
 mutexes and revert to the traditional unsafe mutexes.

---
 include/nuttx/sched.h                |  2 ++
 include/pthread.h                    |  6 ++++++
 sched/Kconfig                        | 20 +++++++++++++++++++
 sched/pthread/Make.defs              |  7 +++++--
 sched/pthread/pthread.h              |  6 ++++++
 sched/pthread/pthread_cancel.c       |  2 ++
 sched/pthread/pthread_exit.c         |  4 +++-
 sched/pthread/pthread_mutexinit.c    |  7 +++++--
 sched/pthread/pthread_mutexlock.c    | 21 +++++++++++++------
 sched/pthread/pthread_mutextrylock.c |  6 +++++-
 sched/pthread/pthread_mutexunlock.c  | 30 ++++++++++++++++++++++------
 11 files changed, 93 insertions(+), 18 deletions(-)

diff --git a/include/nuttx/sched.h b/include/nuttx/sched.h
index f618ac94ce..f8bc539e3d 100644
--- a/include/nuttx/sched.h
+++ b/include/nuttx/sched.h
@@ -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 *************************************************************/
 
diff --git a/include/pthread.h b/include/pthread.h
index 305bb8db21..214ad454fe 100644
--- a/include/pthread.h
+++ b/include/pthread.h
@@ -240,15 +240,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 */
@@ -438,9 +442,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 */
 
diff --git a/sched/Kconfig b/sched/Kconfig
index 3a5807d4dc..369e9ac7cd 100644
--- a/sched/Kconfig
+++ b/sched/Kconfig
@@ -531,6 +531,26 @@ 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.
+
+endchoice # thread mutex robustness
+
 config NPTHREAD_KEYS
 	int "Maximum number of pthread keys"
 	default 4
diff --git a/sched/pthread/Make.defs b/sched/pthread/Make.defs
index a39a35d208..20bc7e8d6c 100644
--- a/sched/pthread/Make.defs
+++ b/sched/pthread/Make.defs
@@ -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
diff --git a/sched/pthread/pthread.h b/sched/pthread/pthread.h
index 6ab044a3ba..2e7106495f 100644
--- a/sched/pthread/pthread.h
+++ b/sched/pthread/pthread.h
@@ -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);
diff --git a/sched/pthread/pthread_cancel.c b/sched/pthread/pthread_cancel.c
index 3a520b1f93..e2cad60ebb 100644
--- a/sched/pthread/pthread_cancel.c
+++ b/sched/pthread/pthread_cancel.c
@@ -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 */
 
diff --git a/sched/pthread/pthread_exit.c b/sched/pthread/pthread_exit.c
index 4654d86371..bcc8e79c85 100644
--- a/sched/pthread/pthread_exit.c
+++ b/sched/pthread/pthread_exit.c
@@ -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
diff --git a/sched/pthread/pthread_mutexinit.c b/sched/pthread/pthread_mutexinit.c
index b521137683..46c9e67356 100644
--- a/sched/pthread/pthread_mutexinit.c
+++ b/sched/pthread/pthread_mutexinit.c
@@ -123,14 +123,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 */
+#endif
 
 #ifdef CONFIG_MUTEX_TYPES
+      /* Set up attributes unique to the mutex type */
+
       mutex->type   = type;
       mutex->nlocks = 0;
 #endif
diff --git a/sched/pthread/pthread_mutexlock.c b/sched/pthread/pthread_mutexlock.c
index 67b668bf9d..ffc8eadad2 100644
--- a/sched/pthread/pthread_mutexlock.c
+++ b/sched/pthread/pthread_mutexlock.c
@@ -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,17 @@ 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)
+      if (mutex->pid > 0 && sched_gettcb(mutex->pid) == NULL)
         {
           DEBUGASSERT(mutex->pid != 0); /* < 0: available, >0 owned, ==0 error */
           DEBUGASSERT((mutex->flags & _PTHREAD_MFLAGS_INCONSISTENT) != 0);
@@ -182,8 +186,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);
 
diff --git a/sched/pthread/pthread_mutextrylock.c b/sched/pthread/pthread_mutextrylock.c
index 683909c859..6e21c74b44 100644
--- a/sched/pthread/pthread_mutextrylock.c
+++ b/sched/pthread/pthread_mutextrylock.c
@@ -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,6 +148,8 @@ 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
@@ -172,6 +174,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;
                 }
diff --git a/sched/pthread/pthread_mutexunlock.c b/sched/pthread/pthread_mutexunlock.c
index 7ab0c90469..9efd9ed847 100644
--- a/sched/pthread/pthread_mutexunlock.c
+++ b/sched/pthread/pthread_mutexunlock.c
@@ -93,9 +93,20 @@ int pthread_mutex_unlock(FAR pthread_mutex_t *mutex)
 
       sched_lock();
 
-      /* Does the calling thread own the semaphore? */
+#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 (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->type != PTHREAD_MUTEX_NORMAL && mutex->pid != (int)getpid())
+#endif
         {
           /* No... return an EPERM error.
            *
@@ -111,11 +122,12 @@ 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
 
 #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 +137,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 */
 

From 666208cf237248e03ad13a730b8c4f3ea5ccef1a Mon Sep 17 00:00:00 2001
From: Gregory Nutt <gnutt@nuttx.org>
Date: Sun, 26 Mar 2017 18:37:24 -0600
Subject: [PATCH 2/4] pthread mutexes:  Add option to support both unsafe and
 robust mutexes via pthread_mutexattr_get/setrobust().

---
 include/pthread.h                     | 47 ++++++++++++++++++++++++---
 libc/pthread/Make.defs                |  1 +
 libc/pthread/pthread_mutexattr_init.c | 10 ++++++
 sched/Kconfig                         | 24 +++++++++++++-
 sched/pthread/pthread_mutexinit.c     | 12 ++++++-
 5 files changed, 87 insertions(+), 7 deletions(-)

diff --git a/include/pthread.h b/include/pthread.h
index 214ad454fe..30c96bab9c 100644
--- a/include/pthread.h
+++ b/include/pthread.h
@@ -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_NOTRECOVRABLE (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. */
 
diff --git a/libc/pthread/Make.defs b/libc/pthread/Make.defs
index 089845d8f7..b8be2927d2 100644
--- a/libc/pthread/Make.defs
+++ b/libc/pthread/Make.defs
@@ -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
 
diff --git a/libc/pthread/pthread_mutexattr_init.c b/libc/pthread/pthread_mutexattr_init.c
index f1b6bca9c7..de6183e56c 100644
--- a/libc/pthread/pthread_mutexattr_init.c
+++ b/libc/pthread/pthread_mutexattr_init.c
@@ -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
     }
 
diff --git a/sched/Kconfig b/sched/Kconfig
index 369e9ac7cd..60183e67d2 100644
--- a/sched/Kconfig
+++ b/sched/Kconfig
@@ -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"
diff --git a/sched/pthread/pthread_mutexinit.c b/sched/pthread/pthread_mutexinit.c
index 46c9e67356..e6abe32900 100644
--- a/sched/pthread/pthread_mutexinit.c
+++ b/sched/pthread/pthread_mutexinit.c
@@ -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

From d1196ddb6072056c931f1f187ab20148dbebe943 Mon Sep 17 00:00:00 2001
From: Gregory Nutt <gnutt@nuttx.org>
Date: Mon, 27 Mar 2017 07:49:13 -0600
Subject: [PATCH 3/4] pthread mutex:  Forgot to add files in last commit

---
 libc/pthread/pthread_mutexattr_getrobust.c | 82 ++++++++++++++++++
 libc/pthread/pthread_mutexattr_setrobust.c | 96 ++++++++++++++++++++++
 2 files changed, 178 insertions(+)
 create mode 100644 libc/pthread/pthread_mutexattr_getrobust.c
 create mode 100644 libc/pthread/pthread_mutexattr_setrobust.c

diff --git a/libc/pthread/pthread_mutexattr_getrobust.c b/libc/pthread/pthread_mutexattr_getrobust.c
new file mode 100644
index 0000000000..8d5e4c1060
--- /dev/null
+++ b/libc/pthread/pthread_mutexattr_getrobust.c
@@ -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;
+}
diff --git a/libc/pthread/pthread_mutexattr_setrobust.c b/libc/pthread/pthread_mutexattr_setrobust.c
new file mode 100644
index 0000000000..42930fa0b7
--- /dev/null
+++ b/libc/pthread/pthread_mutexattr_setrobust.c
@@ -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
+}

From f2f798cb2957582ab61d100aa0ab9b3680be24e8 Mon Sep 17 00:00:00 2001
From: Gregory Nutt <gnutt@nuttx.org>
Date: Mon, 27 Mar 2017 08:50:45 -0600
Subject: [PATCH 4/4] pthread mutexes: Finish logic to support configuration
 mutex robustness.

---
 include/pthread.h                       |  2 +-
 sched/pthread/pthread_mutexconsistent.c |  8 ++--
 sched/pthread/pthread_mutexlock.c       | 21 ++++++++++
 sched/pthread/pthread_mutextrylock.c    | 21 ++++++++++
 sched/pthread/pthread_mutexunlock.c     | 53 +++++++++++++++++++------
 5 files changed, 88 insertions(+), 17 deletions(-)

diff --git a/include/pthread.h b/include/pthread.h
index 30c96bab9c..53eaa0ddaa 100644
--- a/include/pthread.h
+++ b/include/pthread.h
@@ -178,7 +178,7 @@
 
 #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 */
+#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
diff --git a/sched/pthread/pthread_mutexconsistent.c b/sched/pthread/pthread_mutexconsistent.c
index 3febab2d0b..86930e276c 100644
--- a/sched/pthread/pthread_mutexconsistent.c
+++ b/sched/pthread/pthread_mutexconsistent.c
@@ -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().
                */
diff --git a/sched/pthread/pthread_mutexlock.c b/sched/pthread/pthread_mutexlock.c
index ffc8eadad2..3013248842 100644
--- a/sched/pthread/pthread_mutexlock.c
+++ b/sched/pthread/pthread_mutexlock.c
@@ -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);
diff --git a/sched/pthread/pthread_mutextrylock.c b/sched/pthread/pthread_mutextrylock.c
index 6e21c74b44..50c3175de5 100644
--- a/sched/pthread/pthread_mutextrylock.c
+++ b/sched/pthread/pthread_mutextrylock.c
@@ -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);
diff --git a/sched/pthread/pthread_mutexunlock.c b/sched/pthread/pthread_mutexunlock.c
index 9efd9ed847..b27c9ecda0 100644
--- a/sched/pthread/pthread_mutexunlock.c
+++ b/sched/pthread/pthread_mutexunlock.c
@@ -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;
 }