pthread_mutex.c 9.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326
  1. /****************************************************************************
  2. * sched/pthread/pthread_mutex.c
  3. *
  4. * Copyright (C) 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 <stdbool.h>
  40. #include <sched.h>
  41. #include <assert.h>
  42. #include <errno.h>
  43. #include <nuttx/irq.h>
  44. #include <nuttx/sched.h>
  45. #include <nuttx/semaphore.h>
  46. #include "sched/sched.h"
  47. #include "pthread/pthread.h"
  48. /****************************************************************************
  49. * Private Functions
  50. ****************************************************************************/
  51. /****************************************************************************
  52. * Name: pthread_mutex_add
  53. *
  54. * Description:
  55. * Add the mutex to the list of mutexes held by this pthread.
  56. *
  57. * Input Parameters:
  58. * mutex - The mutex to be locked
  59. *
  60. * Returned Value:
  61. * None
  62. *
  63. ****************************************************************************/
  64. static void pthread_mutex_add(FAR struct pthread_mutex_s *mutex)
  65. {
  66. FAR struct tcb_s *rtcb = this_task();
  67. DEBUGASSERT(mutex->flink == NULL);
  68. /* Check if this is a pthread. The main thread may also lock and unlock
  69. * mutexes. The main thread, however, does not participate in the mutex
  70. * consistency logic. Presumably, when the main thread exits, all of the
  71. * child pthreads will also terminate.
  72. *
  73. * REVISIT: NuttX does not support that behavior at present; child pthreads
  74. * will persist after the main thread exits.
  75. */
  76. if ((rtcb->flags & TCB_FLAG_TTYPE_MASK) == TCB_FLAG_TTYPE_PTHREAD)
  77. {
  78. FAR struct pthread_tcb_s *ptcb = (FAR struct pthread_tcb_s *)rtcb;
  79. irqstate_t flags;
  80. /* Add the mutex to the list of mutexes held by this pthread */
  81. flags = enter_critical_section();
  82. mutex->flink = ptcb->mhead;
  83. ptcb->mhead = mutex;
  84. leave_critical_section(flags);
  85. }
  86. }
  87. /****************************************************************************
  88. * Name: pthread_mutex_remove
  89. *
  90. * Description:
  91. * Remove the mutex to the list of mutexes held by this pthread.
  92. *
  93. * Input Parameters:
  94. * mutex - The mutex to be locked
  95. *
  96. * Returned Value:
  97. * None
  98. *
  99. ****************************************************************************/
  100. static void pthread_mutex_remove(FAR struct pthread_mutex_s *mutex)
  101. {
  102. FAR struct tcb_s *rtcb = this_task();
  103. /* Check if this is a pthread. The main thread may also lock and unlock
  104. * mutexes. The main thread, however, does not participate in the mutex
  105. * consistency logic.
  106. */
  107. if ((rtcb->flags & TCB_FLAG_TTYPE_MASK) == TCB_FLAG_TTYPE_PTHREAD)
  108. {
  109. FAR struct pthread_tcb_s *ptcb = (FAR struct pthread_tcb_s *)rtcb;
  110. FAR struct pthread_mutex_s *curr;
  111. FAR struct pthread_mutex_s *prev;
  112. irqstate_t flags;
  113. flags = enter_critical_section();
  114. /* Remove the mutex from the list of mutexes held by this task */
  115. for (prev = NULL, curr = ptcb->mhead;
  116. curr != NULL && curr != mutex;
  117. prev = curr, curr = curr->flink);
  118. DEBUGASSERT(curr == mutex);
  119. /* Remove the mutex from the list. prev == NULL means that the mutex
  120. * to be removed is at the head of the list.
  121. */
  122. if (prev == NULL)
  123. {
  124. ptcb->mhead = mutex->flink;
  125. }
  126. else
  127. {
  128. prev->flink = mutex->flink;
  129. }
  130. mutex->flink = NULL;
  131. leave_critical_section(flags);
  132. }
  133. }
  134. /****************************************************************************
  135. * Public Functions
  136. ****************************************************************************/
  137. /****************************************************************************
  138. * Name: pthread_mutex_take
  139. *
  140. * Description:
  141. * Take the pthread_mutex, waiting if necessary. If successful, add the
  142. * mutex to the list of mutexes held by this thread.
  143. *
  144. * Input Parameters:
  145. * mutex - The mutex to be locked
  146. * intr - false: ignore EINTR errors when locking; true treat EINTR as
  147. * other errors by returning the errno value
  148. *
  149. * Returned Value:
  150. * 0 on success or an errno value on failure.
  151. *
  152. ****************************************************************************/
  153. int pthread_mutex_take(FAR struct pthread_mutex_s *mutex, bool intr)
  154. {
  155. int ret = EINVAL;
  156. /* Verify input parameters */
  157. DEBUGASSERT(mutex != NULL);
  158. if (mutex != NULL)
  159. {
  160. /* Make sure that no unexpected context switches occur */
  161. sched_lock();
  162. /* Error out if the mutex is already in an inconsistent state. */
  163. if ((mutex->flags & _PTHREAD_MFLAGS_INCONSISTENT) != 0)
  164. {
  165. ret = EOWNERDEAD;
  166. }
  167. else
  168. {
  169. /* Take semaphore underlying the mutex. pthread_sem_take
  170. * returns zero on success and a positive errno value on failure.
  171. */
  172. ret = pthread_sem_take(&mutex->sem, intr);
  173. if (ret == OK)
  174. {
  175. /* Check if the holder of the mutex has terminated without
  176. * releasing. In that case, the state of the mutex is
  177. * inconsistent and we return EOWNERDEAD.
  178. */
  179. if ((mutex->flags & _PTHREAD_MFLAGS_INCONSISTENT) != 0)
  180. {
  181. ret = EOWNERDEAD;
  182. }
  183. /* Add the mutex to the list of mutexes held by this task */
  184. else
  185. {
  186. pthread_mutex_add(mutex);
  187. }
  188. }
  189. }
  190. sched_unlock();
  191. }
  192. return ret;
  193. }
  194. /****************************************************************************
  195. * Name: pthread_mutex_trytake
  196. *
  197. * Description:
  198. * Try to take the pthread_mutex without waiting. If successful, add the
  199. * mutex to the list of mutexes held by this thread.
  200. *
  201. * Input Parameters:
  202. * mutex - The mutex to be locked
  203. * intr - false: ignore EINTR errors when locking; true treat EINTR as
  204. * other errors by returning the errno value
  205. *
  206. * Returned Value:
  207. * 0 on success or an errno value on failure.
  208. *
  209. ****************************************************************************/
  210. int pthread_mutex_trytake(FAR struct pthread_mutex_s *mutex)
  211. {
  212. int ret = EINVAL;
  213. /* Verify input parameters */
  214. DEBUGASSERT(mutex != NULL);
  215. if (mutex != NULL)
  216. {
  217. /* Make sure that no unexpected context switches occur */
  218. sched_lock();
  219. /* Error out if the mutex is already in an inconsistent state. */
  220. if ((mutex->flags & _PTHREAD_MFLAGS_INCONSISTENT) != 0)
  221. {
  222. ret = EOWNERDEAD;
  223. }
  224. else
  225. {
  226. /* Try to take the semaphore underlying the mutex */
  227. ret = nxsem_trywait(&mutex->sem);
  228. if (ret < 0)
  229. {
  230. ret = -ret;
  231. }
  232. else
  233. {
  234. /* Add the mutex to the list of mutexes held by this task */
  235. pthread_mutex_add(mutex);
  236. }
  237. }
  238. sched_unlock();
  239. }
  240. return ret;
  241. }
  242. /****************************************************************************
  243. * Name: pthread_mutex_give
  244. *
  245. * Description:
  246. * Take the pthread_mutex and, if successful, add the mutex to the ist of
  247. * mutexes held by this thread.
  248. *
  249. * Input Parameters:
  250. * mutex - The mutex to be unlocked
  251. *
  252. * Returned Value:
  253. * 0 on success or an errno value on failure.
  254. *
  255. ****************************************************************************/
  256. int pthread_mutex_give(FAR struct pthread_mutex_s *mutex)
  257. {
  258. int ret = EINVAL;
  259. /* Verify input parameters */
  260. DEBUGASSERT(mutex != NULL);
  261. if (mutex != NULL)
  262. {
  263. /* Remove the mutex from the list of mutexes held by this task */
  264. pthread_mutex_remove(mutex);
  265. /* Now release the underlying semaphore */
  266. ret = pthread_sem_give(&mutex->sem);
  267. }
  268. return ret;
  269. }