1 /*
2  * Copyright (c) 2006-2021, 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 
12 #define DBG_TAG    "lwp.tid"
13 #define DBG_LVL    DBG_LOG
14 #include <rtdbg.h>
15 
16 #include <rthw.h>
17 #include <rtthread.h>
18 
19 #include "lwp_internal.h"
20 
21 #ifdef ARCH_MM_MMU
22 #include "lwp_user_mm.h"
23 #endif
24 
25 #define TID_MAX 10000
26 
27 #define TID_CT_ASSERT(name, x) \
28     struct assert_##name {char ary[2 * (x) - 1];}
29 
30 TID_CT_ASSERT(tid_min_nr, LWP_TID_MAX_NR > 1);
31 TID_CT_ASSERT(tid_max_nr, LWP_TID_MAX_NR < TID_MAX);
32 
33 static struct lwp_avl_struct lwp_tid_ary[LWP_TID_MAX_NR];
34 static struct lwp_avl_struct *lwp_tid_free_head = RT_NULL;
35 static int lwp_tid_ary_alloced = 0;
36 static struct lwp_avl_struct *lwp_tid_root = RT_NULL;
37 static int current_tid = 0;
38 
39 static struct rt_mutex tid_lock;
40 
lwp_tid_init(void)41 int lwp_tid_init(void)
42 {
43     return rt_mutex_init(&tid_lock, "tidmtx", RT_IPC_FLAG_PRIO);
44 }
45 
lwp_tid_get(void)46 int lwp_tid_get(void)
47 {
48     struct lwp_avl_struct *p;
49     int tid = 0;
50 
51     lwp_mutex_take_safe(&tid_lock, RT_WAITING_FOREVER, 0);
52     p = lwp_tid_free_head;
53     if (p)
54     {
55         lwp_tid_free_head = (struct lwp_avl_struct *)p->avl_right;
56     }
57     else if (lwp_tid_ary_alloced < LWP_TID_MAX_NR)
58     {
59         p = lwp_tid_ary + lwp_tid_ary_alloced;
60         lwp_tid_ary_alloced++;
61     }
62     if (p)
63     {
64         int found_noused = 0;
65 
66         RT_ASSERT(p->data == RT_NULL);
67         for (tid = current_tid + 1; tid < TID_MAX; tid++)
68         {
69             if (!lwp_avl_find(tid, lwp_tid_root))
70             {
71                 found_noused = 1;
72                 break;
73             }
74         }
75         if (!found_noused)
76         {
77             for (tid = 1; tid <= current_tid; tid++)
78             {
79                 if (!lwp_avl_find(tid, lwp_tid_root))
80                 {
81                     found_noused = 1;
82                     break;
83                 }
84             }
85         }
86         p->avl_key = tid;
87         lwp_avl_insert(p, &lwp_tid_root);
88         current_tid = tid;
89     }
90     lwp_mutex_release_safe(&tid_lock);
91 
92     if (tid <= 0)
93     {
94         LOG_W("resource TID exhausted.");
95     }
96 
97     return tid;
98 }
99 
lwp_tid_put(int tid)100 void lwp_tid_put(int tid)
101 {
102     struct lwp_avl_struct *p;
103     rt_thread_t thread;
104     rt_thread_t current;
105 
106     lwp_mutex_take_safe(&tid_lock, RT_WAITING_FOREVER, 0);
107     p  = lwp_avl_find(tid, lwp_tid_root);
108     if (p)
109     {
110         thread = p->data;
111         p->data = RT_NULL;
112         lwp_avl_remove(p, &lwp_tid_root);
113         p->avl_right = lwp_tid_free_head;
114         lwp_tid_free_head = p;
115     }
116     else
117         thread = RT_NULL;
118 
119     if (thread && thread->tid_ref_count)
120     {
121         current = rt_thread_self();
122         RT_ASSERT(thread->susp_recycler == RT_NULL);
123         thread->susp_recycler = current;
124 
125         rt_enter_critical();
126         rt_thread_suspend_with_flag(current, RT_UNINTERRUPTIBLE);
127         lwp_mutex_release_safe(&tid_lock);
128         rt_exit_critical();
129 
130         rt_schedule();
131     }
132     else
133         lwp_mutex_release_safe(&tid_lock);
134 }
135 
lwp_tid_get_thread_raw(int tid)136 rt_thread_t lwp_tid_get_thread_raw(int tid)
137 {
138     struct lwp_avl_struct *p;
139     rt_thread_t thread = RT_NULL;
140 
141     p  = lwp_avl_find(tid, lwp_tid_root);
142     if (p)
143     {
144         thread = (rt_thread_t)p->data;
145     }
146     return thread;
147 }
148 
lwp_tid_get_thread_and_inc_ref(int tid)149 rt_thread_t lwp_tid_get_thread_and_inc_ref(int tid)
150 {
151     rt_thread_t thread = RT_NULL;
152 
153     lwp_mutex_take_safe(&tid_lock, RT_WAITING_FOREVER, 0);
154     thread = tid ? lwp_tid_get_thread_raw(tid) : rt_thread_self();
155     if (thread != RT_NULL)
156     {
157         thread->tid_ref_count += 1;
158     }
159     lwp_mutex_release_safe(&tid_lock);
160     return thread;
161 }
162 
lwp_tid_dec_ref(rt_thread_t thread)163 void lwp_tid_dec_ref(rt_thread_t thread)
164 {
165     rt_thread_t susp_putter;
166     if (thread)
167     {
168         RT_ASSERT(rt_object_get_type(&thread->parent) == RT_Object_Class_Thread);
169         susp_putter = thread->susp_recycler;
170         lwp_mutex_take_safe(&tid_lock, RT_WAITING_FOREVER, 0);
171 
172         RT_ASSERT(thread->tid_ref_count > 0);
173         thread->tid_ref_count -= 1;
174         if (!thread->tid_ref_count && susp_putter)
175         {
176             rt_thread_resume(susp_putter);
177         }
178         lwp_mutex_release_safe(&tid_lock);
179     }
180 }
181 
lwp_tid_set_thread(int tid,rt_thread_t thread)182 void lwp_tid_set_thread(int tid, rt_thread_t thread)
183 {
184     struct lwp_avl_struct *p;
185 
186     lwp_mutex_take_safe(&tid_lock, RT_WAITING_FOREVER, 0);
187     p  = lwp_avl_find(tid, lwp_tid_root);
188     if (p)
189     {
190         RT_ASSERT(p->data == RT_NULL);
191         p->data = thread;
192     }
193     lwp_mutex_release_safe(&tid_lock);
194 }
195