pthread/mutex: finish logic to support configuration mutex robustness
authorEunBong Song <eunb.song@samsung.com>
Thu, 13 Apr 2017 04:16:01 +0000 (13:16 +0900)
committerHeesub Shin <heesub.shin@samsung.com>
Tue, 18 Apr 2017 03:02:19 +0000 (12:02 +0900)
All credits should go to Gregory Nutt who wrote the original commit.

Change-Id: Iaf25679c6882e7b362a58e6aadfe45d879219f91
Signed-off-by: Gregory Nutt <gnutt@nuttx.org>
[Song: backported f2f798cb from NuttX]
Signed-off-by: EunBong Song <eunb.song@samsung.com>
os/include/pthread.h
os/kernel/pthread/pthread_mutexconsistent.c
os/kernel/pthread/pthread_mutexlock.c
os/kernel/pthread/pthread_mutextrylock.c
os/kernel/pthread/pthread_mutexunlock.c

index 302003b..72de5bb 100644 (file)
  * 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
@@ -209,7 +246,7 @@ extern "C" {
 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;
 
 /**
@@ -248,21 +285,17 @@ struct pthread_cond_s {
 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;
@@ -274,20 +307,20 @@ 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;
@@ -295,25 +328,25 @@ 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
 
 /**
@@ -559,10 +592,8 @@ int pthread_mutex_unlock(FAR pthread_mutex_t *mutex);
 
 #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. */
@@ -795,7 +826,7 @@ int pthread_barrierattr_getpshared(FAR const pthread_barrierattr_t *attr, FAR in
  */
 int pthread_barrierattr_setpshared(FAR pthread_barrierattr_t *attr, int pshared);
 /**
* @} */ //end for PTHREAD_KERNEL
       * @} *///end for PTHREAD_KERNEL
 
 #ifdef __cplusplus
 }
index d233cbd..d66ac37 100644 (file)
@@ -49,7 +49,6 @@
  * 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;
 }
index 547a7e2..01681b9 100644 (file)
@@ -193,7 +193,26 @@ int pthread_mutex_lock(FAR pthread_mutex_t *mutex)
                 * 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);
 
index b6d59c1..9b397b8 100644 (file)
@@ -180,7 +180,26 @@ int pthread_mutex_trylock(FAR pthread_mutex_t *mutex)
                                         * 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);
 
index f61255b..cb1d076 100644 (file)
@@ -122,26 +122,49 @@ int pthread_mutex_unlock(FAR pthread_mutex_t *mutex)
        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) */
@@ -149,45 +172,42 @@ int pthread_mutex_unlock(FAR pthread_mutex_t *mutex)
                        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;
 }