1
0

pthread_mutex.c 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584
  1. /*
  2. * Copyright (c) 2006-2024 RT-Thread Development Team
  3. *
  4. * SPDX-License-Identifier: Apache-2.0
  5. *
  6. * Change Logs:
  7. * Date Author Notes
  8. * 2010-10-26 Bernard the first version
  9. */
  10. #include <rtthread.h>
  11. #include "pthread.h"
  12. #define MUTEXATTR_SHARED_MASK 0x0010
  13. #define MUTEXATTR_TYPE_MASK 0x000f
  14. const pthread_mutexattr_t pthread_default_mutexattr = PTHREAD_PROCESS_PRIVATE;
  15. /**
  16. * @brief Initializes a mutex attributes object.
  17. *
  18. * This function initializes a mutex attributes object pointed to by `attr` with
  19. * default attribute values. Once initialized, the attributes object can be used
  20. * to customize the behavior of mutexes created using it.
  21. *
  22. * @param[out] attr Pointer to the mutex attributes object to be initialized.
  23. *
  24. * @return
  25. * - 0 on success.
  26. * - Non-zero error code on failure.
  27. *
  28. * @note
  29. * After initialization, the mutex attributes object must be destroyed with
  30. * `pthread_mutexattr_destroy()` when it is no longer needed.
  31. *
  32. * @warning
  33. * Using an uninitialized mutex attributes object may result in undefined behavior.
  34. *
  35. * @see pthread_mutexattr_destroy, pthread_mutex_init
  36. */
  37. int pthread_mutexattr_init(pthread_mutexattr_t *attr)
  38. {
  39. if (attr)
  40. {
  41. *attr = pthread_default_mutexattr;
  42. return 0;
  43. }
  44. return EINVAL;
  45. }
  46. RTM_EXPORT(pthread_mutexattr_init);
  47. /**
  48. * @brief Destroys a mutex attributes object.
  49. *
  50. * This function releases any resources associated with the mutex attributes object
  51. * pointed to by `attr`. After the attributes object is destroyed, it should not
  52. * be used unless it is re-initialized with `pthread_mutexattr_init()`.
  53. *
  54. * @param[in,out] attr Pointer to the mutex attributes object to be destroyed.
  55. *
  56. * @return
  57. * - 0 on success.
  58. * - Non-zero error code on failure, including:
  59. * - `EINVAL`: The attributes object is invalid or uninitialized.
  60. *
  61. * @note
  62. * Destroying an uninitialized or already destroyed attributes object results in undefined behavior.
  63. *
  64. * @warning
  65. * Ensure that no mutexes are being initialized or created using this attributes object
  66. * at the time of its destruction.
  67. *
  68. * @see pthread_mutexattr_init, pthread_mutex_init
  69. */
  70. int pthread_mutexattr_destroy(pthread_mutexattr_t *attr)
  71. {
  72. if (attr)
  73. {
  74. *attr = -1;
  75. return 0;
  76. }
  77. return EINVAL;
  78. }
  79. RTM_EXPORT(pthread_mutexattr_destroy);
  80. /**
  81. * @brief Retrieves the type attribute of a mutex attributes object.
  82. *
  83. * This function retrieves the mutex type attribute from the attributes object
  84. * pointed to by `attr` and stores it in the integer pointed to by `type`.
  85. *
  86. * @param[in] attr Pointer to the mutex attributes object.
  87. * @param[out] type Pointer to an integer where the mutex type will be stored.
  88. * Possible values include:
  89. * - `PTHREAD_MUTEX_NORMAL`: Default mutex type.
  90. * - `PTHREAD_MUTEX_ERRORCHECK`: Mutex with error-checking.
  91. * - `PTHREAD_MUTEX_RECURSIVE`: Recursive mutex.
  92. *
  93. * @return
  94. * - 0 on success.
  95. * - Non-zero error code on failure, including:
  96. * - `EINVAL`: The attributes object or the `type` pointer is invalid.
  97. *
  98. * @note
  99. * Use this function to check the type of a mutex attributes object that has
  100. * already been initialized or configured.
  101. *
  102. * @see pthread_mutexattr_settype, pthread_mutexattr_init
  103. */
  104. int pthread_mutexattr_gettype(const pthread_mutexattr_t *attr, int *type)
  105. {
  106. if (attr && type)
  107. {
  108. int atype = (*attr & MUTEXATTR_TYPE_MASK);
  109. if (atype >= PTHREAD_MUTEX_NORMAL && atype <= PTHREAD_MUTEX_ERRORCHECK)
  110. {
  111. *type = atype;
  112. return 0;
  113. }
  114. }
  115. return EINVAL;
  116. }
  117. RTM_EXPORT(pthread_mutexattr_gettype);
  118. /**
  119. * @brief Sets the type attribute of a mutex attributes object.
  120. *
  121. * This function sets the type of the mutex to be initialized using the
  122. * attributes object pointed to by `attr`. The `type` can be one of the
  123. * following values:
  124. * - `PTHREAD_MUTEX_NORMAL`: Default mutex type. The mutex does not allow
  125. * a thread to unlock it if it was not locked by that thread (this results
  126. * in undefined behavior).
  127. * - `PTHREAD_MUTEX_ERRORCHECK`: Error-checking mutex type. A thread trying to
  128. * lock a mutex it already holds will return an error.
  129. * - `PTHREAD_MUTEX_RECURSIVE`: Recursive mutex type. The same thread can lock
  130. * the mutex multiple times without causing a deadlock, but it must unlock it
  131. * the same number of times.
  132. *
  133. * @param[in,out] attr Pointer to the mutex attributes object.
  134. * @param[in] type The type to set for the mutex. One of the following:
  135. * - `PTHREAD_MUTEX_NORMAL`
  136. * - `PTHREAD_MUTEX_ERRORCHECK`
  137. * - `PTHREAD_MUTEX_RECURSIVE`
  138. *
  139. * @return
  140. * - 0 on success.
  141. * - Non-zero error code on failure, including:
  142. * - `EINVAL`: The specified type is invalid.
  143. *
  144. * @note
  145. * The type must be set before the mutex attributes object is used to
  146. * initialize a mutex with `pthread_mutex_init()`.
  147. *
  148. * @warning
  149. * Attempting to set an invalid mutex type will result in an error.
  150. *
  151. * @see pthread_mutexattr_gettype, pthread_mutexattr_init, pthread_mutex_init
  152. */
  153. int pthread_mutexattr_settype(pthread_mutexattr_t *attr, int type)
  154. {
  155. if (attr && type >= PTHREAD_MUTEX_NORMAL && type <= PTHREAD_MUTEX_ERRORCHECK)
  156. {
  157. *attr = (*attr & ~MUTEXATTR_TYPE_MASK) | type;
  158. return 0;
  159. }
  160. return EINVAL;
  161. }
  162. RTM_EXPORT(pthread_mutexattr_settype);
  163. /**
  164. * @brief Sets the shared attribute of a mutex attributes object.
  165. *
  166. * This function sets the `pshared` attribute of the mutex attributes object
  167. * pointed to by `attr`. The `pshared` attribute determines whether the mutex
  168. * is shared between threads of the same process or can be shared between
  169. * threads of different processes.
  170. *
  171. * @param[in,out] attr Pointer to the mutex attributes object.
  172. * @param[in] pshared The sharing behavior of the mutex. This can be one of the following:
  173. * - `PTHREAD_PROCESS_PRIVATE`: The mutex is only shared between threads
  174. * of the same process (this is the default behavior).
  175. * - `PTHREAD_PROCESS_SHARED`: The mutex can be shared between threads
  176. * of different processes (requires the mutex to be allocated in
  177. * shared memory).
  178. *
  179. * @return
  180. * - 0 on success.
  181. * - Non-zero error code on failure, including:
  182. * - `EINVAL`: Invalid `pshared` value or invalid attributes object.
  183. *
  184. * @note
  185. * The `pshared` attribute must be set before the mutex attributes object is
  186. * used to initialize a mutex with `pthread_mutex_init()`. For shared mutexes
  187. * (`PTHREAD_PROCESS_SHARED`), the mutex object must be allocated in shared memory.
  188. *
  189. * @warning
  190. * Attempting to set an invalid `pshared` value will result in an error.
  191. *
  192. * @see pthread_mutexattr_getpshared, pthread_mutexattr_init, pthread_mutex_init
  193. */
  194. int pthread_mutexattr_setpshared(pthread_mutexattr_t *attr, int pshared)
  195. {
  196. if (!attr)
  197. return EINVAL;
  198. switch (pshared)
  199. {
  200. case PTHREAD_PROCESS_PRIVATE:
  201. *attr &= ~MUTEXATTR_SHARED_MASK;
  202. return 0;
  203. case PTHREAD_PROCESS_SHARED:
  204. *attr |= MUTEXATTR_SHARED_MASK;
  205. return 0;
  206. }
  207. return EINVAL;
  208. }
  209. RTM_EXPORT(pthread_mutexattr_setpshared);
  210. /**
  211. * @brief Retrieves the shared attribute of a mutex attributes object.
  212. *
  213. * This function retrieves the `pshared` attribute from the mutex attributes
  214. * object pointed to by `attr` and stores it in the integer pointed to by `pshared`.
  215. * The `pshared` attribute indicates whether the mutex can be shared between threads
  216. * of different processes or only within the same process.
  217. *
  218. * @param[in] attr Pointer to the mutex attributes object.
  219. * @param[out] pshared Pointer to an integer where the shared attribute will be stored.
  220. * Possible values are:
  221. * - `PTHREAD_PROCESS_PRIVATE`: Mutex is shared only within the same process.
  222. * - `PTHREAD_PROCESS_SHARED`: Mutex can be shared between threads of different processes.
  223. *
  224. * @return
  225. * - 0 on success.
  226. * - Non-zero error code on failure, including:
  227. * - `EINVAL`: Invalid attributes object or the `pshared` pointer is NULL.
  228. *
  229. * @note
  230. * Use this function to check the shared attribute of an already initialized
  231. * mutex attributes object.
  232. *
  233. * @warning
  234. * Attempting to get the `pshared` attribute of an uninitialized or invalid
  235. * attributes object will result in an error.
  236. *
  237. * @see pthread_mutexattr_setpshared, pthread_mutexattr_init, pthread_mutex_init
  238. */
  239. int pthread_mutexattr_getpshared(pthread_mutexattr_t *attr, int *pshared)
  240. {
  241. if (!attr || !pshared)
  242. return EINVAL;
  243. *pshared = (*attr & MUTEXATTR_SHARED_MASK) ? PTHREAD_PROCESS_SHARED
  244. : PTHREAD_PROCESS_PRIVATE;
  245. return 0;
  246. }
  247. RTM_EXPORT(pthread_mutexattr_getpshared);
  248. /**
  249. * @brief Initializes a mutex with optional attributes.
  250. *
  251. * This function initializes a mutex object pointed to by `mutex`. The mutex
  252. * can optionally be initialized with attributes specified by `attr`. If
  253. * `attr` is `NULL`, default attributes are used.
  254. *
  255. * @param[in,out] mutex Pointer to the mutex to be initialized.
  256. * @param[in] attr Pointer to the mutex attributes object. Pass `NULL` to use
  257. * default attributes.
  258. *
  259. * @return
  260. * - 0 on success.
  261. * - Non-zero error code on failure, including:
  262. * - `EINVAL`: Invalid parameters or result.
  263. *
  264. * @note
  265. * The mutex object must be destroyed using `pthread_mutex_destroy()` after it
  266. * is no longer needed to free associated resources.
  267. *
  268. * @warning
  269. * A mutex should not be re-initialized while it is already in use.
  270. *
  271. * @see pthread_mutex_destroy, pthread_mutex_lock, pthread_mutex_unlock
  272. */
  273. int pthread_mutex_init(pthread_mutex_t *mutex, const pthread_mutexattr_t *attr)
  274. {
  275. rt_err_t result;
  276. char name[RT_NAME_MAX];
  277. static rt_uint16_t pthread_mutex_number = 0;
  278. if (!mutex)
  279. return EINVAL;
  280. /* build mutex name */
  281. rt_snprintf(name, sizeof(name), "pmtx%02d", pthread_mutex_number ++);
  282. if (attr == RT_NULL)
  283. mutex->attr = pthread_default_mutexattr;
  284. else
  285. mutex->attr = *attr;
  286. /* init mutex lock */
  287. result = rt_mutex_init(&(mutex->lock), name, RT_IPC_FLAG_PRIO);
  288. if (result != RT_EOK)
  289. return EINVAL;
  290. /* detach the object from system object container */
  291. rt_object_detach(&(mutex->lock.parent.parent));
  292. mutex->lock.parent.parent.type = RT_Object_Class_Mutex;
  293. return 0;
  294. }
  295. RTM_EXPORT(pthread_mutex_init);
  296. /**
  297. * @brief Destroys a mutex object.
  298. *
  299. * This function releases any resources associated with the mutex object
  300. * pointed to by `mutex`. After the mutex has been destroyed, it cannot
  301. * be used unless it is re-initialized with `pthread_mutex_init()`.
  302. *
  303. * @param[in,out] mutex Pointer to the mutex to be destroyed.
  304. *
  305. * @return
  306. * - 0 on success.
  307. * - Non-zero error code on failure, including:
  308. * - `EBUSY`: The mutex is currently locked or being used by another thread.
  309. * - `EINVAL`: The mutex is invalid or has not been initialized.
  310. *
  311. * @note
  312. * Before calling this function, ensure that the mutex is not locked or in use
  313. * by any thread. Destroying a locked mutex results in undefined behavior.
  314. *
  315. * @warning
  316. * Attempting to destroy a mutex that is still in use can cause resource leaks
  317. * or undefined behavior.
  318. *
  319. * @see pthread_mutex_init, pthread_mutex_lock, pthread_mutex_unlock
  320. */
  321. int pthread_mutex_destroy(pthread_mutex_t *mutex)
  322. {
  323. if (!mutex || mutex->attr == -1)
  324. return EINVAL;
  325. /* it's busy */
  326. if (mutex->lock.owner != RT_NULL)
  327. return EBUSY;
  328. rt_memset(mutex, 0, sizeof(pthread_mutex_t));
  329. mutex->attr = -1;
  330. return 0;
  331. }
  332. RTM_EXPORT(pthread_mutex_destroy);
  333. /**
  334. * @brief Locks a mutex.
  335. *
  336. * This function locks the mutex object pointed to by `mutex`. If the mutex is
  337. * already locked by another thread, the calling thread will block until the
  338. * mutex becomes available.
  339. *
  340. * @param[in,out] mutex Pointer to the mutex to be locked.
  341. *
  342. * @return
  343. * - 0 on success.
  344. * - Non-zero error code on failure, including:
  345. * - `EDEADLK`: A deadlock condition was detected (e.g., the current thread
  346. * already holds the mutex in a recursive locking scenario).
  347. * - `EINVAL`: The mutex is invalid or uninitialized.
  348. *
  349. * @note
  350. * If the mutex is initialized with the `PTHREAD_MUTEX_RECURSIVE` attribute,
  351. * the same thread can lock the mutex multiple times without causing a deadlock.
  352. * However, the mutex must be unlocked an equal number of times before it
  353. * becomes available to other threads.
  354. *
  355. * @warning
  356. * Attempting to lock an uninitialized or already destroyed mutex results in
  357. * undefined behavior.
  358. *
  359. * @see pthread_mutex_unlock, pthread_mutex_trylock, pthread_mutex_init
  360. */
  361. int pthread_mutex_lock(pthread_mutex_t *mutex)
  362. {
  363. int mtype;
  364. rt_err_t result;
  365. if (!mutex)
  366. return EINVAL;
  367. if (mutex->attr == -1)
  368. {
  369. /* init mutex */
  370. pthread_mutex_init(mutex, RT_NULL);
  371. }
  372. mtype = mutex->attr & MUTEXATTR_TYPE_MASK;
  373. rt_enter_critical();
  374. if (mutex->lock.owner == rt_thread_self() &&
  375. mtype != PTHREAD_MUTEX_RECURSIVE)
  376. {
  377. rt_exit_critical();
  378. return EDEADLK;
  379. }
  380. rt_exit_critical();
  381. result = rt_mutex_take(&(mutex->lock), RT_WAITING_FOREVER);
  382. if (result == RT_EOK)
  383. return 0;
  384. return EINVAL;
  385. }
  386. RTM_EXPORT(pthread_mutex_lock);
  387. /**
  388. * @brief Unlocks a mutex.
  389. *
  390. * This function unlocks the mutex object pointed to by `mutex`. If other threads
  391. * are blocked waiting for the mutex, one of them will acquire the lock once it is
  392. * released. The calling thread must hold the lock on the mutex before calling
  393. * this function.
  394. *
  395. * @param[in,out] mutex Pointer to the mutex to be unlocked.
  396. *
  397. * @return
  398. * - 0 on success.
  399. * - Non-zero error code on failure, including:
  400. * - `EPERM`: The current thread does not hold the lock on the mutex.
  401. * - `EINVAL`: The mutex is invalid or uninitialized.
  402. *
  403. * @note
  404. * If the mutex was initialized with the `PTHREAD_MUTEX_RECURSIVE` attribute,
  405. * the mutex will only be unlocked after the calling thread unlocks it as many
  406. * times as it was locked.
  407. *
  408. * @warning
  409. * Attempting to unlock an uninitialized, destroyed, or unlocked mutex results
  410. * in undefined behavior.
  411. *
  412. * @see pthread_mutex_lock, pthread_mutex_trylock, pthread_mutex_init
  413. */
  414. int pthread_mutex_unlock(pthread_mutex_t *mutex)
  415. {
  416. rt_err_t result;
  417. if (!mutex)
  418. return EINVAL;
  419. if (mutex->attr == -1)
  420. {
  421. /* init mutex */
  422. pthread_mutex_init(mutex, RT_NULL);
  423. }
  424. if (mutex->lock.owner != rt_thread_self())
  425. {
  426. int mtype;
  427. mtype = mutex->attr & MUTEXATTR_TYPE_MASK;
  428. /* error check, return EPERM */
  429. if (mtype == PTHREAD_MUTEX_ERRORCHECK)
  430. return EPERM;
  431. /* no thread waiting on this mutex */
  432. if (mutex->lock.owner == RT_NULL)
  433. return 0;
  434. }
  435. result = rt_mutex_release(&(mutex->lock));
  436. if (result == RT_EOK)
  437. return 0;
  438. return EINVAL;
  439. }
  440. RTM_EXPORT(pthread_mutex_unlock);
  441. /**
  442. * @brief Attempts to lock a mutex without blocking.
  443. *
  444. * This function attempts to lock the mutex object pointed to by `mutex`. If the mutex
  445. * is already locked by another thread, the function returns immediately with an error
  446. * code instead of blocking.
  447. *
  448. * @param[in,out] mutex Pointer to the mutex to be locked.
  449. *
  450. * @return
  451. * - 0 on success (the mutex was successfully locked).
  452. * - Non-zero error code on failure, including:
  453. * - `EBUSY`: The mutex is already locked by another thread.
  454. * - `EINVAL`: The mutex is invalid or uninitialized.
  455. *
  456. * @note
  457. * This function is useful for implementing non-blocking mutex acquisition. If the mutex
  458. * was initialized with the `PTHREAD_MUTEX_RECURSIVE` attribute, the calling thread can
  459. * lock it multiple times, but must unlock it the same number of times.
  460. *
  461. * @warning
  462. * Attempting to trylock an uninitialized or destroyed mutex results in undefined behavior.
  463. *
  464. * @see pthread_mutex_lock, pthread_mutex_unlock, pthread_mutex_init
  465. */
  466. int pthread_mutex_trylock(pthread_mutex_t *mutex)
  467. {
  468. rt_err_t result;
  469. int mtype;
  470. if (!mutex)
  471. return EINVAL;
  472. if (mutex->attr == -1)
  473. {
  474. /* init mutex */
  475. pthread_mutex_init(mutex, RT_NULL);
  476. }
  477. mtype = mutex->attr & MUTEXATTR_TYPE_MASK;
  478. rt_enter_critical();
  479. if (mutex->lock.owner == rt_thread_self() &&
  480. mtype != PTHREAD_MUTEX_RECURSIVE)
  481. {
  482. rt_exit_critical();
  483. return EDEADLK;
  484. }
  485. rt_exit_critical();
  486. result = rt_mutex_take(&(mutex->lock), 0);
  487. if (result == RT_EOK) return 0;
  488. return EBUSY;
  489. }
  490. RTM_EXPORT(pthread_mutex_trylock);
  491. int pthread_mutexattr_getprioceiling(const pthread_mutexattr_t *attr, int *prioceiling)
  492. {
  493. return EINVAL;
  494. }
  495. RTM_EXPORT(pthread_mutexattr_getprioceiling);
  496. int pthread_mutexattr_setprioceiling(const pthread_mutexattr_t *attr, int prioceiling)
  497. {
  498. return EINVAL;
  499. }
  500. RTM_EXPORT(pthread_mutexattr_setprioceiling);
  501. int pthread_mutexattr_getprotocol(const pthread_mutexattr_t *attr, int *protocol)
  502. {
  503. return EINVAL;
  504. }
  505. RTM_EXPORT(pthread_mutexattr_getprotocol);
  506. int pthread_mutexattr_setprotocol(const pthread_mutexattr_t *attr, int protocol)
  507. {
  508. return EINVAL;
  509. }
  510. RTM_EXPORT(pthread_mutexattr_setprotocol);
  511. int pthread_mutex_getprioceiling(const pthread_mutex_t *mutex, int *prioceiling)
  512. {
  513. return pthread_mutexattr_getprioceiling(&mutex->attr, prioceiling);
  514. }
  515. RTM_EXPORT(pthread_mutex_getprioceiling);
  516. int pthread_mutex_setprioceiling(pthread_mutex_t *mutex, int prioceiling, int *old_ceiling)
  517. {
  518. *old_ceiling = pthread_mutexattr_getprioceiling(&mutex->attr, old_ceiling);
  519. if(*old_ceiling != 0)
  520. {
  521. return EINVAL;
  522. }
  523. return pthread_mutexattr_setprioceiling(&mutex->attr, prioceiling);
  524. }
  525. RTM_EXPORT(pthread_mutex_setprioceiling);