lwp_tid.c 7.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260
  1. /*
  2. * Copyright (c) 2006-2025 RT-Thread Development Team
  3. *
  4. * SPDX-License-Identifier: Apache-2.0
  5. *
  6. * Change Logs:
  7. * Date Author Notes
  8. * 2021-01-15 shaojinchun first version
  9. * 2023-11-16 xqyjlj Fix the case where tid is 0
  10. */
  11. #define DBG_TAG "lwp.tid"
  12. #define DBG_LVL DBG_LOG
  13. #include <rtdbg.h>
  14. #include <rthw.h>
  15. #include <rtthread.h>
  16. #include "lwp_internal.h"
  17. #ifdef ARCH_MM_MMU
  18. #include "lwp_user_mm.h"
  19. #endif
  20. #define TID_MAX 10000
  21. #define TID_CT_ASSERT(name, x) \
  22. struct assert_##name {char ary[2 * (x) - 1];}
  23. TID_CT_ASSERT(tid_min_nr, LWP_TID_MAX_NR > 1);
  24. TID_CT_ASSERT(tid_max_nr, LWP_TID_MAX_NR < TID_MAX);
  25. static struct lwp_avl_struct lwp_tid_ary[LWP_TID_MAX_NR];
  26. static struct lwp_avl_struct *lwp_tid_free_head = RT_NULL;
  27. static int lwp_tid_ary_alloced = 0;
  28. static struct lwp_avl_struct *lwp_tid_root = RT_NULL;
  29. static int current_tid = 0;
  30. static struct rt_mutex tid_lock;
  31. /**
  32. * @brief Initialize the thread ID manager
  33. *
  34. * @return int Returns RT_EOK (0) on success, error code on failure
  35. *
  36. * @note This function initializes a mutex lock used for thread ID management.
  37. */
  38. int lwp_tid_init(void)
  39. {
  40. return rt_mutex_init(&tid_lock, "tidmtx", RT_IPC_FLAG_PRIO);
  41. }
  42. /**
  43. * @brief Allocates a thread ID (TID) from available resources
  44. *
  45. * @return int The allocated thread ID, or 0 if no TID available (with warning log)
  46. *
  47. * @note This function performs thread-safe allocation of a TID by:
  48. * 1. First checking the free list of available TIDs
  49. * 2. If none available, allocating from the TID array if space remains
  50. * 3. Performing a two-phase search for unused TIDs (current_tid+1 to TID_MAX, then 1 to current_tid)
  51. * 4. Inserting the allocated TID into the AVL tree for tracking
  52. */
  53. int lwp_tid_get(void)
  54. {
  55. struct lwp_avl_struct *p;
  56. int tid = 0;
  57. lwp_mutex_take_safe(&tid_lock, RT_WAITING_FOREVER, 0);
  58. p = lwp_tid_free_head;
  59. if (p)
  60. {
  61. lwp_tid_free_head = (struct lwp_avl_struct *)p->avl_right;
  62. }
  63. else if (lwp_tid_ary_alloced < LWP_TID_MAX_NR)
  64. {
  65. p = lwp_tid_ary + lwp_tid_ary_alloced;
  66. lwp_tid_ary_alloced++;
  67. }
  68. if (p)
  69. {
  70. int found_noused = 0;
  71. RT_ASSERT(p->data == RT_NULL);
  72. for (tid = current_tid + 1; tid < TID_MAX; tid++)
  73. {
  74. if (!lwp_avl_find(tid, lwp_tid_root))
  75. {
  76. found_noused = 1;
  77. break;
  78. }
  79. }
  80. if (!found_noused)
  81. {
  82. for (tid = 1; tid <= current_tid; tid++)
  83. {
  84. if (!lwp_avl_find(tid, lwp_tid_root))
  85. {
  86. found_noused = 1;
  87. break;
  88. }
  89. }
  90. }
  91. p->avl_key = tid;
  92. lwp_avl_insert(p, &lwp_tid_root);
  93. current_tid = tid;
  94. }
  95. lwp_mutex_release_safe(&tid_lock);
  96. if (tid <= 0)
  97. {
  98. LOG_W("resource TID exhausted.");
  99. }
  100. return tid;
  101. }
  102. /**
  103. * @brief Releases a thread ID (TID) and associated resources
  104. *
  105. * @param[in] tid The thread ID to release
  106. *
  107. * @note This function performs thread-safe release of a TID by:
  108. * 1. Finding the TID in the AVL tree and removing it
  109. * 2. Adding the freed TID structure to the free list for reuse
  110. * 3. Handling thread reference counting and potential suspension
  111. */
  112. void lwp_tid_put(int tid)
  113. {
  114. struct lwp_avl_struct *p;
  115. rt_thread_t thread;
  116. rt_thread_t current;
  117. lwp_mutex_take_safe(&tid_lock, RT_WAITING_FOREVER, 0);
  118. p = lwp_avl_find(tid, lwp_tid_root);
  119. if (p)
  120. {
  121. thread = p->data;
  122. p->data = RT_NULL;
  123. lwp_avl_remove(p, &lwp_tid_root);
  124. p->avl_right = lwp_tid_free_head;
  125. lwp_tid_free_head = p;
  126. }
  127. else
  128. thread = RT_NULL;
  129. if (thread && thread->tid_ref_count)
  130. {
  131. current = rt_thread_self();
  132. RT_ASSERT(thread->susp_recycler == RT_NULL);
  133. thread->susp_recycler = current;
  134. rt_enter_critical();
  135. rt_thread_suspend_with_flag(current, RT_UNINTERRUPTIBLE);
  136. lwp_mutex_release_safe(&tid_lock);
  137. rt_exit_critical();
  138. rt_schedule();
  139. }
  140. else
  141. lwp_mutex_release_safe(&tid_lock);
  142. }
  143. /**
  144. * @brief Retrieves the thread object associated with a thread ID (TID)
  145. *
  146. * @param[in] tid The thread ID to look up
  147. *
  148. * @return rt_thread_t The associated thread object, or RT_NULL if not found
  149. */
  150. rt_thread_t lwp_tid_get_thread_raw(int tid)
  151. {
  152. struct lwp_avl_struct *p;
  153. rt_thread_t thread = RT_NULL;
  154. p = lwp_avl_find(tid, lwp_tid_root);
  155. if (p)
  156. {
  157. thread = (rt_thread_t)p->data;
  158. }
  159. return thread;
  160. }
  161. /**
  162. * @brief Retrieves a thread object by TID and increments its reference count
  163. *
  164. * @param[in] tid The thread ID to look up (0 means current thread)
  165. *
  166. * @return rt_thread_t The associated thread object, or RT_NULL if not found
  167. *
  168. * @note This function provides thread-safe access to a thread object while:
  169. * 1. Acquiring the tid_lock mutex for synchronization
  170. * 2. Looking up the thread by TID (or returning current thread if tid=0)
  171. * 3. Incrementing the thread's reference count if found
  172. * 4. Releasing the mutex before returning
  173. */
  174. rt_thread_t lwp_tid_get_thread_and_inc_ref(int tid)
  175. {
  176. rt_thread_t thread = RT_NULL;
  177. lwp_mutex_take_safe(&tid_lock, RT_WAITING_FOREVER, 0);
  178. thread = tid ? lwp_tid_get_thread_raw(tid) : rt_thread_self();
  179. if (thread != RT_NULL)
  180. {
  181. thread->tid_ref_count += 1;
  182. }
  183. lwp_mutex_release_safe(&tid_lock);
  184. return thread;
  185. }
  186. /**
  187. * @brief Decrement the reference count of a thread and potentially resume its suspender
  188. *
  189. * @param[in] thread The thread object whose reference count needs to be decremented
  190. *
  191. * @note This function safely decreases the reference count of a thread object. If the reference
  192. * count reaches zero and there is a suspender thread waiting (susp_recycler), it will
  193. * be resumed.
  194. */
  195. void lwp_tid_dec_ref(rt_thread_t thread)
  196. {
  197. rt_thread_t susp_putter;
  198. if (thread)
  199. {
  200. RT_ASSERT(rt_object_get_type(&thread->parent) == RT_Object_Class_Thread);
  201. susp_putter = thread->susp_recycler;
  202. lwp_mutex_take_safe(&tid_lock, RT_WAITING_FOREVER, 0);
  203. RT_ASSERT(thread->tid_ref_count > 0);
  204. thread->tid_ref_count -= 1;
  205. if (!thread->tid_ref_count && susp_putter)
  206. {
  207. rt_thread_resume(susp_putter);
  208. }
  209. lwp_mutex_release_safe(&tid_lock);
  210. }
  211. }
  212. /**
  213. * @brief Associate a thread with a given TID in the thread ID management system
  214. *
  215. * @param[in] tid The thread ID to associate with the thread
  216. * @param[in] thread The thread object to be associated with the TID
  217. *
  218. * @note This function safely associates a thread object with a specified thread ID (TID)
  219. * in the system's AVL tree. The operation is protected by a mutex to ensure thread safety.
  220. */
  221. void lwp_tid_set_thread(int tid, rt_thread_t thread)
  222. {
  223. struct lwp_avl_struct *p;
  224. lwp_mutex_take_safe(&tid_lock, RT_WAITING_FOREVER, 0);
  225. p = lwp_avl_find(tid, lwp_tid_root);
  226. if (p)
  227. {
  228. RT_ASSERT(p->data == RT_NULL);
  229. p->data = thread;
  230. }
  231. lwp_mutex_release_safe(&tid_lock);
  232. }