pthread_mutexunlock.c 8.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243
  1. /****************************************************************************
  2. * sched/pthread/pthread_mutexunlock.c
  3. *
  4. * Copyright (C) 2007-2009, 2017 Gregory Nutt. All rights reserved.
  5. * Author: Gregory Nutt <gnutt@nuttx.org>
  6. *
  7. * Redistribution and use in source and binary forms, with or without
  8. * modification, are permitted provided that the following conditions
  9. * are met:
  10. *
  11. * 1. Redistributions of source code must retain the above copyright
  12. * notice, this list of conditions and the following disclaimer.
  13. * 2. Redistributions in binary form must reproduce the above copyright
  14. * notice, this list of conditions and the following disclaimer in
  15. * the documentation and/or other materials provided with the
  16. * distribution.
  17. * 3. Neither the name NuttX nor the names of its contributors may be
  18. * used to endorse or promote products derived from this software
  19. * without specific prior written permission.
  20. *
  21. * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
  22. * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
  23. * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
  24. * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
  25. * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
  26. * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
  27. * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
  28. * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
  29. * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  30. * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
  31. * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
  32. * POSSIBILITY OF SUCH DAMAGE.
  33. *
  34. ****************************************************************************/
  35. /****************************************************************************
  36. * Included Files
  37. ****************************************************************************/
  38. #include <nuttx/config.h>
  39. #include <unistd.h>
  40. #include <pthread.h>
  41. #include <sched.h>
  42. #include <assert.h>
  43. #include <errno.h>
  44. #include <debug.h>
  45. #include "pthread/pthread.h"
  46. /****************************************************************************
  47. * Private Functions
  48. ****************************************************************************/
  49. /****************************************************************************
  50. * Name: pthread_mutex_islocked
  51. *
  52. * Description:
  53. * Return true is the mutex is locked.
  54. *
  55. * Input Parameters:
  56. * None
  57. *
  58. * Returned Value:
  59. * Returns true if the mutex is locked
  60. *
  61. ****************************************************************************/
  62. static inline bool pthread_mutex_islocked(FAR struct pthread_mutex_s *mutex)
  63. {
  64. int semcount = mutex->sem.semcount;
  65. /* The underlying semaphore should have a count less than 2:
  66. *
  67. * 1 == mutex is unlocked.
  68. * 0 == mutex is locked with no waiters
  69. * -n == mutex is locked with 'n' waiters.
  70. */
  71. DEBUGASSERT(semcount < 2);
  72. return semcount < 1;
  73. }
  74. /****************************************************************************
  75. * Public Functions
  76. ****************************************************************************/
  77. /****************************************************************************
  78. * Name: pthread_mutex_unlock
  79. *
  80. * Description:
  81. * The pthread_mutex_unlock() function releases the mutex object referenced
  82. * by mutex. The manner in which a mutex is released is dependent upon the
  83. * mutex's type attribute. If there are threads blocked on the mutex object
  84. * referenced by mutex when pthread_mutex_unlock() is called, resulting in
  85. * the mutex becoming available, the scheduling policy is used to determine
  86. * which thread shall acquire the mutex. (In the case of PTHREAD_MUTEX_RECURSIVE
  87. * mutexes, the mutex becomes available when the count reaches zero and the
  88. * calling thread no longer has any locks on this mutex).
  89. *
  90. * If a signal is delivered to a thread waiting for a mutex, upon return from
  91. * the signal handler the thread resumes waiting for the mutex as if it was
  92. * not interrupted.
  93. *
  94. * Input Parameters:
  95. * None
  96. *
  97. * Returned Value:
  98. * None
  99. *
  100. * Assumptions:
  101. *
  102. ****************************************************************************/
  103. int pthread_mutex_unlock(FAR pthread_mutex_t *mutex)
  104. {
  105. int ret = EPERM;
  106. sinfo("mutex=0x%p\n", mutex);
  107. DEBUGASSERT(mutex != NULL);
  108. if (mutex == NULL)
  109. {
  110. return EINVAL;
  111. }
  112. /* Make sure the semaphore is stable while we make the following checks.
  113. * This all needs to be one atomic action.
  114. */
  115. sched_lock();
  116. /* The unlock operation is only performed if the mutex is actually locked.
  117. * EPERM *must* be returned if the mutex type is PTHREAD_MUTEX_ERRORCHECK
  118. * or PTHREAD_MUTEX_RECURSIVE, or the mutex is a robust mutex, and the
  119. * current thread does not own the mutex. Behavior is undefined for the
  120. * remaining case.
  121. */
  122. if (pthread_mutex_islocked(mutex))
  123. {
  124. #if !defined(CONFIG_PTHREAD_MUTEX_UNSAFE) || defined(CONFIG_PTHREAD_MUTEX_TYPES)
  125. /* Does the calling thread own the semaphore? If no, should we return
  126. * an error?
  127. *
  128. * Error checking is always performed for ERRORCHECK and RECURSIVE
  129. * mutex types. Error checking is only performed for NORMAL (or
  130. * DEFAULT) mutex type if the NORMAL mutex is robust. That is either:
  131. *
  132. * 1. CONFIG_PTHREAD_MUTEX_ROBUST is defined, or
  133. * 2. CONFIG_PTHREAD_MUTEX_BOTH is defined and the robust flag is set
  134. */
  135. #if defined(CONFIG_PTHREAD_MUTEX_ROBUST)
  136. /* Not that error checking is always performed if the configuration has
  137. * CONFIG_PTHREAD_MUTEX_ROBUST defined. Just check if the calling
  138. * thread owns the semaphore.
  139. */
  140. if (mutex->pid != (int)getpid())
  141. #elif defined(CONFIG_PTHREAD_MUTEX_UNSAFE) && defined(CONFIG_PTHREAD_MUTEX_TYPES)
  142. /* If mutex types are not supported, then all mutexes are NORMAL (or
  143. * DEFAULT). Error checking should never be performed for the
  144. * non-robust NORMAL mutex type.
  145. */
  146. if (mutex->type != PTHREAD_MUTEX_NORMAL && mutex->pid != (int)getpid())
  147. #else /* CONFIG_PTHREAD_MUTEX_BOTH */
  148. /* Skip the error check if this is a non-robust NORMAL mutex */
  149. bool errcheck = ((mutex->flags & _PTHREAD_MFLAGS_ROBUST) != 0);
  150. #ifdef CONFIG_PTHREAD_MUTEX_TYPES
  151. errcheck |= (mutex->type != PTHREAD_MUTEX_NORMAL);
  152. #endif
  153. /* Does the calling thread own the semaphore? If not should we report
  154. * the EPERM error?
  155. */
  156. if (errcheck && mutex->pid != (int)getpid())
  157. #endif
  158. {
  159. /* No... return an EPERM error.
  160. *
  161. * Per POSIX: "EPERM should be returned if the mutex type is
  162. * PTHREAD_MUTEX_ERRORCHECK or PTHREAD_MUTEX_RECURSIVE, or the
  163. * mutex is a robust mutex, and the current thread does not own
  164. * the mutex."
  165. *
  166. * For the case of the non-robust PTHREAD_MUTEX_NORMAL mutex,
  167. * the behavior is undefined.
  168. */
  169. serr("ERROR: Holder=%d returning EPERM\n", mutex->pid);
  170. ret = EPERM;
  171. }
  172. else
  173. #endif /* !CONFIG_PTHREAD_MUTEX_UNSAFE || CONFIG_PTHREAD_MUTEX_TYPES */
  174. #ifdef CONFIG_PTHREAD_MUTEX_TYPES
  175. /* Yes, the caller owns the semaphore.. Is this a recursive mutex? */
  176. if (mutex->type == PTHREAD_MUTEX_RECURSIVE && mutex->nlocks > 1)
  177. {
  178. /* This is a recursive mutex and we there are multiple locks held. Retain
  179. * the mutex lock, just decrement the count of locks held, and return
  180. * success.
  181. */
  182. mutex->nlocks--;
  183. ret = OK;
  184. }
  185. else
  186. #endif /* CONFIG_PTHREAD_MUTEX_TYPES */
  187. /* This is either a non-recursive mutex or is the outermost unlock of
  188. * a recursive mutex.
  189. *
  190. * In the case where the calling thread is NOT the holder of the thread,
  191. * the behavior is undefined per POSIX. Here we do the same as GLIBC:
  192. * We allow the other thread to release the mutex even though it does
  193. * not own it.
  194. */
  195. {
  196. /* Nullify the pid and lock count then post the semaphore */
  197. mutex->pid = -1;
  198. #ifdef CONFIG_PTHREAD_MUTEX_TYPES
  199. mutex->nlocks = 0;
  200. #endif
  201. ret = pthread_mutex_give(mutex);
  202. }
  203. }
  204. sched_unlock();
  205. sinfo("Returning %d\n", ret);
  206. return ret;
  207. }