ThreadX内核源码分析 - 线程同步之互斥锁及动态优先级
Posted arm7star
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了ThreadX内核源码分析 - 线程同步之互斥锁及动态优先级相关的知识,希望对你有一定的参考价值。
1、ThreadX互斥锁介绍
互斥锁一般用来锁多线程都需要访问的临界资源,这些资源不能并发操作,例如对某个内存的互斥读写,这个读写很快,但是不能多线程同时进行,所以需要加互斥锁;
占用互斥锁的线程没能执行,可能是被高优先级线程抢占了或者临界资源里面调用了阻塞操作;高优先级线程想要访问临界资源就必须等待低优先级线程被调度然后释放互斥锁,如果低优先级线程不提高优先级不被执行的话,那么高优先级的线程就会阻塞,直到所有高优先级线程都阻塞了,才能轮到占用互斥锁的低优先级线程执行,这样高优先级线程就得不到及时处理,通常高优先级线程的任务都比较紧急;
ThreadX互斥锁实现了优先级继承,如果等待互斥锁的线程的优先级高于占用互斥锁的线程的优先级,那么将占用互斥锁线程的优先级调整到与等待互斥锁线程的优先级一样高,然占用互斥锁的线程尽快执行,尽快释放互斥锁,释放互斥锁时,线程优先级恢复原始优先级,让出cpu执行;
另外ThreadX互斥锁是可重复获取的,获取到了互斥锁的线程可以多次获取互斥锁,0表示互斥锁没有占用,非0表示互斥锁被占用,每获取一次互斥锁,互斥锁计数加1,获取互斥锁次数要与释放互斥锁次数相同,否则互斥锁不会被释放。
2、互斥锁获取_tx_mutex_get
2.1、互斥锁的获取_tx_mutex_get
互斥锁获取主要看互斥锁计数器:
- 如果互斥锁计数器为0,那么互斥锁没有被占用,获取互斥锁,互斥锁继承当前线程的优先级,互斥锁计数器加1
- 如果互斥锁已经被当前线程占用,互斥锁计数器加1即可;
- 如果互斥锁被其他线程占用,当前线程不能阻塞或者没有设置等待参数就返回互斥锁不可用,否则挂起当前线程,当前线程加入等待互斥锁线程链表,更新tx_mutex_highest_priority_waiting(所有等待互斥锁的线程的最高优先级),如果当前等待互斥锁线程的优先级高于占用互斥锁线程的优先级,那么将占用互斥锁线程的优先级设置改变成当前线程的优先级,让占用互斥锁的线程尽快处理临界资源并释放互斥锁,等待互斥锁的高优先级线程才能尽快获取到互斥锁。
_tx_mutex_get代码实现如下:
077 UINT _tx_mutex_get(TX_MUTEX *mutex_ptr, ULONG wait_option)
078
079
080 TX_INTERRUPT_SAVE_AREA
081
082 TX_THREAD *thread_ptr;
083 TX_MUTEX *next_mutex;
084 TX_MUTEX *previous_mutex;
085 TX_THREAD *mutex_owner;
086 TX_THREAD *next_thread;
087 TX_THREAD *previous_thread;
088 UINT status;
089
090
091 /* Disable interrupts to get an instance from the mutex. */
092 TX_DISABLE
093
094 #ifdef TX_MUTEX_ENABLE_PERFORMANCE_INFO
095
096 /* Increment the total mutex get counter. */
097 _tx_mutex_performance_get_count++;
098
099 /* Increment the number of attempts to get this mutex. */
100 mutex_ptr -> tx_mutex_performance_get_count++;
101 #endif
102
103 /* If trace is enabled, insert this event into the trace buffer. */
104 TX_TRACE_IN_LINE_INSERT(TX_TRACE_MUTEX_GET, mutex_ptr, wait_option, TX_POINTER_TO_ULONG_CONVERT(mutex_ptr -> tx_mutex_owner), mutex_ptr -> tx_mutex_ownership_count, TX_TRACE_MUTEX_EVENTS)
105
106 /* Log this kernel call. */
107 TX_EL_MUTEX_GET_INSERT
108
109 /* Pickup thread pointer. */
110 TX_THREAD_GET_CURRENT(thread_ptr)
111
112 /* Determine if this mutex is available. */
113 if (mutex_ptr -> tx_mutex_ownership_count == ((UINT) 0)) // 互斥锁没有被占用
114
115
116 /* Set the ownership count to 1. */
117 mutex_ptr -> tx_mutex_ownership_count = ((UINT) 1); // 互斥锁计数加1(互斥锁被占用)
118
119 /* Remember that the calling thread owns the mutex. */
120 mutex_ptr -> tx_mutex_owner = thread_ptr; // 记录占用互斥锁的线程为当前线程
121
122 /* Determine if the thread pointer is valid. */
123 if (thread_ptr != TX_NULL) // 当前线程是否有效(非线程上下文调用不用执行if分支,正常情况下都是在线程上下文调用互斥锁)
124
125
126 /* Determine if priority inheritance is required. */
127 if (mutex_ptr -> tx_mutex_inherit == TX_TRUE)
128
129
130 /* Remember the current priority of thread. */
131 mutex_ptr -> tx_mutex_original_priority = thread_ptr -> tx_thread_priority; // tx_mutex_original_priority记录线程获取互斥锁时的原始优先级(第一次获取互斥锁的时候才会执行到这里)
132
133 /* Setup the highest priority waiting thread. */
134 mutex_ptr -> tx_mutex_highest_priority_waiting = ((UINT) TX_MAX_PRIORITIES); // 正在等待互斥锁的线程的最高优先级,没有时默认就是TX_MAX_PRIORITIES(最低优先级)
135
136
137 /* Pickup next mutex pointer, which is the head of the list. */
138 next_mutex = thread_ptr -> tx_thread_owned_mutex_list; // 线程占用互斥锁链表
139
140 /* Determine if this thread owns any other mutexes that have priority inheritance. */
141 if (next_mutex != TX_NULL) // 线程占用其他互斥锁,将当前获取的互斥锁加入链表表头
142
143
144 /* Non-empty list. Link up the mutex. */
145
146 /* Pickup the next and previous mutex pointer. */
147 previous_mutex = next_mutex -> tx_mutex_owned_previous;
148
149 /* Place the owned mutex in the list. */
150 next_mutex -> tx_mutex_owned_previous = mutex_ptr;
151 previous_mutex -> tx_mutex_owned_next = mutex_ptr;
152
153 /* Setup this mutex's next and previous created links. */
154 mutex_ptr -> tx_mutex_owned_previous = previous_mutex;
155 mutex_ptr -> tx_mutex_owned_next = next_mutex;
156
157 else // 线程没有占用其他互斥锁,新建一个互斥锁链表,只有一个当前获取到的互斥锁
158
159
160 /* The owned mutex list is empty. Add mutex to empty list. */
161 thread_ptr -> tx_thread_owned_mutex_list = mutex_ptr;
162 mutex_ptr -> tx_mutex_owned_next = mutex_ptr;
163 mutex_ptr -> tx_mutex_owned_previous = mutex_ptr;
164
165
166 /* Increment the number of mutexes owned counter. */
167 thread_ptr -> tx_thread_owned_mutex_count++; // 线程占用互斥锁个数加1
168
169
170 /* Restore interrupts. */
171 TX_RESTORE
172
173 /* Return success. */
174 status = TX_SUCCESS;
175
176
177 /* Otherwise, see if the owning thread is trying to obtain the same mutex. */
178 else if (mutex_ptr -> tx_mutex_owner == thread_ptr) // 当前线程之前就已经占用了该互斥锁,再次获取该互斥锁,只需要增加互斥锁计数即可
179
180
181 /* The owning thread is requesting the mutex again, just
182 increment the ownership count. */
183 mutex_ptr -> tx_mutex_ownership_count++; // 互斥锁占用次数加1
184
185 /* Restore interrupts. */
186 TX_RESTORE
187
188 /* Return success. */
189 status = TX_SUCCESS;
190
191 else // 互斥锁被其他线程占用
192
193
194 /* Determine if the request specifies suspension. */
195 if (wait_option != TX_NO_WAIT) // 有设置等待选项
196
197
198 /* Determine if the preempt disable flag is non-zero. */
199 if (_tx_thread_preempt_disable != ((UINT) 0)) // 如果线程禁止抢占的话,那么不能阻塞当前线程,返回互斥锁不可用即可,否则其他线程被禁止抢占了就得不到执行
200
201
202 /* Restore interrupts. */
203 TX_RESTORE
204
205 /* Suspension is not allowed if the preempt disable flag is non-zero at this point - return error completion. */
206 status = TX_NOT_AVAILABLE;
207
208 else // 线程没有禁止抢占,那么需要挂起当前线程
209
210
211 /* Prepare for suspension of this thread. */
212
213 /* Pickup the mutex owner. */
214 mutex_owner = mutex_ptr -> tx_mutex_owner; // 获取占用互斥锁的线程
215
216 #ifdef TX_MUTEX_ENABLE_PERFORMANCE_INFO
217
218 /* Increment the total mutex suspension counter. */
219 _tx_mutex_performance_suspension_count++;
220
221 /* Increment the number of suspensions on this mutex. */
222 mutex_ptr -> tx_mutex_performance_suspension_count++;
223
224 /* Determine if a priority inversion is present. */
225 if (thread_ptr -> tx_thread_priority < mutex_owner -> tx_thread_priority)
226
227
228 /* Yes, priority inversion is present! */
229
230 /* Increment the total mutex priority inversions counter. */
231 _tx_mutex_performance_priority_inversion_count++;
232
233 /* Increment the number of priority inversions on this mutex. */
234 mutex_ptr -> tx_mutex_performance_priority_inversion_count++;
235
236 #ifdef TX_THREAD_ENABLE_PERFORMANCE_INFO
237
238 /* Increment the number of total thread priority inversions. */
239 _tx_thread_performance_priority_inversion_count++;
240
241 /* Increment the number of priority inversions for this thread. */
242 thread_ptr -> tx_thread_performance_priority_inversion_count++;
243 #endif
244
245 #endif
246
247 /* Setup cleanup routine pointer. */
248 thread_ptr -> tx_thread_suspend_cleanup = &(_tx_mutex_cleanup); // 等待互斥锁超时或者被中断时的清理函数(等待超时需要通过定时调用_tx_mutex_cleanup唤醒阻塞的线程)
249
250 /* Setup cleanup information, i.e. this mutex control
251 block. */
252 thread_ptr -> tx_thread_suspend_control_block = (VOID *) mutex_ptr; // 清理函数的参数(等待的互斥锁),线程会挂到互斥锁等待链表里面,超时时需要从等待链表里面删除当前线程
253
254 #ifndef TX_NOT_INTERRUPTABLE
255
256 /* Increment the suspension sequence number, which is used to identify
257 this suspension event. */
258 thread_ptr -> tx_thread_suspension_sequence++;
259 #endif
260
261 /* Setup suspension list. */
262 if (mutex_ptr -> tx_mutex_suspended_count == TX_NO_SUSPENSIONS) // 当前线程加入等待mutex_ptr的挂起线程链表tx_mutex_suspension_list里面
263
264
265 /* No other threads are suspended. Setup the head pointer and
266 just setup this threads pointers to itself. */
267 mutex_ptr -> tx_mutex_suspension_list = thread_ptr;
268 thread_ptr -> tx_thread_suspended_next = thread_ptr;
269 thread_ptr -> tx_thread_suspended_previous = thread_ptr;
270
271 else
272
273
274 /* This list is not NULL, add current thread to the end. */
275 next_thread = mutex_ptr -> tx_mutex_suspension_list;
276 thread_ptr -> tx_thread_suspended_next = next_thread;
277 previous_thread = next_thread -> tx_thread_suspended_previous;
278 thread_ptr -> tx_thread_suspended_previous = previous_thread;
279 previous_thread -> tx_thread_suspended_next = thread_ptr;
280 next_thread -> tx_thread_suspended_previous = thread_ptr;
281
282
283 /* Increment the suspension count. */
284 mutex_ptr -> tx_mutex_suspended_count++; // 等待互斥锁的线程计数加1
285
286 /* Set the state to suspended. */
287 thread_ptr -> tx_thread_state = TX_MUTEX_SUSP; // 当前线程修改为挂起状态
288
289 #ifdef TX_NOT_INTERRUPTABLE
290
291 /* Determine if we need to raise the priority of the thread
292 owning the mutex. */
293 if (mutex_ptr -> tx_mutex_inherit == TX_TRUE)
294
295
296 /* Determine if this is the highest priority to raise for this mutex. */
297 if (mutex_ptr -> tx_mutex_highest_priority_waiting > thread_ptr -> tx_thread_priority)
298
299
300 /* Remember this priority. */
301 mutex_ptr -> tx_mutex_highest_priority_waiting = thread_ptr -> tx_thread_priority;
302
303
304 /* Determine if we have to update inherit priority level of the mutex owner. */
305 if (thread_ptr -> tx_thread_priority < mutex_owner -> tx_thread_inherit_priority)
306
307
308 /* Remember the new priority inheritance priority. */
309 mutex_owner -> tx_thread_inherit_priority = thread_ptr -> tx_thread_priority;
310
311
312 /* Priority inheritance is requested, check to see if the thread that owns the mutex is lower priority. */
313 if (mutex_owner -> tx_thread_priority > thread_ptr -> tx_thread_priority)
314
315
316 /* Yes, raise the suspended, owning thread's priority to that
317 of the current thread. */
318 _tx_mutex_priority_change(mutex_owner, thread_ptr -> tx_thread_priority);
319
320 #ifdef TX_MUTEX_ENABLE_PERFORMANCE_INFO
321
322 /* Increment the total mutex priority inheritance counter. */
323 _tx_mutex_performance__priority_inheritance_count++;
324
325 /* Increment the number of priority inheritance situations on this mutex. */
326 mutex_ptr -> tx_mutex_performance__priority_inheritance_count++;
327 #endif
328
329
330
331 /* Call actual non-interruptable thread suspension routine. */
332 _tx_thread_system_ni_suspend(thread_ptr, wait_option);
333
334 /* Restore interrupts. */
335 TX_RESTORE
336 #else
337
338 /* Set the suspending flag. */
339 thread_ptr -> tx_thread_suspending = TX_TRUE; // 设置线程正在挂起(线程还没从就绪链表删除,还没真正挂起,其他挂起或者唤醒当前线程的操作需要检查tx_thread_suspending,不能唤醒挂起中的线程,延迟挂起挂起中线程,也就是互斥锁挂起之后,下次唤醒线程时再执行之前的挂起操作)
340
341 /* Setup the timeout period. */
342 thread_ptr -> tx_thread_timer.tx_timer_internal_remaining_ticks = wait_option; // 线程超时时间(挂起线程时会启动一个定时器,定时器超时调用前面设置的回调函数,唤醒阻塞线程)
343
344 /* Temporarily disable preemption. */
345 _tx_thread_preempt_disable++; // 禁止抢占,后面会打开中断,避免当前线程被抢占切换出去,等线程真正挂起之后才调度其他线程,线程挂起之后,后面还有部分重要操作要执行
346
347 /* Restore interrupts. */
348 TX_RESTORE
349
350 /* Determine if we need to raise the priority of the thread
351 owning the mutex. */
352 if (mutex_ptr -> tx_mutex_inherit == TX_TRUE) // 如果互斥锁继承为TX_TRUE,那么占用互斥锁的线程可以继承等待互斥锁线程的优先级
353
354
355 /* Determine if this is the highest priority to raise for this mutex. */
356 if (mutex_ptr -> tx_mutex_highest_priority_waiting > thread_ptr -> tx_thread_priority) // 当前线程是所有等待互斥锁的线程里面优先级最高的线程
357
358
359 /* Remember this priority. */
360 mutex_ptr -> tx_mutex_highest_priority_waiting = thread_ptr -> tx_thread_priority; // 更新等待互斥锁线程的最高优先级
361
362
363 /* Determine if we have to update inherit priority level of the mutex owner. */
364 if (thread_ptr -> tx_thread_priority < mutex_owner -> tx_thread_inherit_priority) // 当前线程的优先级高于占用互斥锁线程的继承优先级(线程的继承优先级默认是TX_MAX_PRIORITIES)
365
366
367 /* Remember the new priority inheritance priority. */
368 mutex_owner -> tx_thread_inherit_priority = thread_ptr -> tx_thread_priority; // 更新占用互斥锁线程的继承优先级
369
370
371 /* Priority inheritance is requested, check to see if the thread that owns the mutex is lower priority. */
372 if (mutex_owner -> tx_thread_priority > thread_ptr -> tx_thread_priority) // 占用互斥的锁线程的优先级低于当前等待互斥锁线程的优先级
373
374
375 /* Yes, raise the suspended, owning thread's priority to that
376 of the current thread. */
377 _tx_mutex_priority_change(mutex_owner, thread_ptr -> tx_thread_priority); // 调整占用互斥锁线程的优先级为当前线程的优先级(让占用互斥锁的线程尽快执行,然后释放互斥锁)
378
379 #ifdef TX_MUTEX_ENABLE_PERFORMANCE_INFO
380
381 /* Increment the total mutex priority inheritance counter. */
382 _tx_mutex_performance__priority_inheritance_count++;
383
384 /* Increment the number of priority inheritance situations on this mutex. */
385 mutex_ptr -> tx_mutex_performance__priority_inheritance_count++;
386 #endif
387
388
389
390 /* Call actual thread suspension routine. */
391 _tx_thread_system_suspend(thread_ptr); // 挂起当前线程
392 #endif
393 /* Return the completion status. */
394 status = thread_ptr -> tx_thread_suspend_status;
395
396
397 else // 没有等待选项,不等待互斥锁,那么返回互斥锁不可用即可
398
399
400 /* Restore interrupts. */
401 TX_RESTORE
402
403 /* Immediate return, return error completion. */
404 status = TX_NOT_AVAILABLE;
405
406
407
408 /* Return completion status. */
409 return(status);
410
2.2、线程优先级调整_tx_mutex_priority_change
调整优先级主要是将被改变优先级的线程从原来的就绪线程链表删除,加入到新的就绪线程链表,这个过程就导致被改变优先级的线程被加入到就绪线程链表末尾,而且还会导致内存重新选择下一个执行线程,例如:当前线程优先级为1,优先级1的线程只要当前线程就绪,优先级2有就绪线程,当前线程把自己的优先级将为2了,内核选择原来优先级2就绪链表的第一个就绪线程作为下一个执行的线程,很明显,应该让当前线程继续执行,那么就得再次把当前线程移动到表头,再例如:当前线程优先级为1,优先级1的线程只要当前线程就绪,就绪线程的次高优先级为5,优先级5的第一个就绪线程的抢占阈值为3,当前线程需要降低优先级为3,当前线程挂起时,内核选择优先级5的线程作为下一个执行线程,唤醒当前线程,虽然当前线程是最高优先级,但是优先级5的线程的抢占阈值为3,当前线程不能抢占阈值3的线程,理论上应该是抢占阈值3的线程不能抢占当前线程,当前线程就因为改变优先级而被不能抢占的线程抢占了,那么还得抢回来,将当前线程设置为下一个执行线程,并且移动到表头。(有些场景没看到内核怎么确保改变优先级的线程仍然在表头,而且有场景已经确认不能保证被标记抢占的线程不在就绪线程链表表头,不明白是bug能还是内核设计如此,向社区提交了issue,等待社区回复再具体分析!!!)
_tx_mutex_priority_change实现代码如下:
083 VOID _tx_mutex_priority_change(TX_THREAD *thread_ptr, UINT new_priority)
084
085
086 #ifndef TX_NOT_INTERRUPTABLE
087
088 TX_INTERRUPT_SAVE_AREA
089 #endif
090
091 TX_THREAD *execute_ptr;
092 TX_THREAD *next_execute_ptr;
093 UINT original_priority;
094 #ifndef TX_DISABLE_PREEMPTION_THRESHOLD
095 ULONG priority_bit;
096 #if TX_MAX_PRIORITIES > 32
097 UINT map_index;
098 #endif
099 #endif
100
101
102
103 #ifndef TX_NOT_INTERRUPTABLE
104
105 /* Lockout interrupts while the thread is being suspended. */
106 TX_DISABLE
107 #endif
108
109 /* Determine if this thread is currently ready. */
110 if (thread_ptr -> tx_thread_state != TX_READY) // 如果线程非就绪状态,简单改变线程的优先级、抢占阈值,因为阻塞线程不在就绪链表里面,不需要移动(抢占阈值不低于线程创建时用户指定的抢占阈值;线程占用互斥锁时,线程会继承高优先级等待互斥锁线程的优先级,互斥锁释放时,会降低恢复旧的优先级)
111
112
113 /* Change thread priority to the new mutex priority-inheritance priority. */
114 thread_ptr -> tx_thread_priority = new_priority; // 设置线程的新的优先级
115
116 /* Determine how to setup the thread's preemption-threshold. */
117 if (thread_ptr -> tx_thread_user_preempt_threshold < new_priority)
118
119
120 /* Change thread preemption-threshold to the user's preemption-threshold. */
121 thread_ptr -> tx_thread_preempt_threshold = thread_ptr -> tx_thread_user_preempt_threshold;
122
123 else
124
125
126 /* Change the thread preemption-threshold to the new threshold. */
127 thread_ptr -> tx_thread_preempt_threshold = new_priority;
128
129
130 #ifndef TX_NOT_INTERRUPTABLE
131 /* Restore interrupts. */
132 TX_RESTORE
133 #endif
134
135 else // 就绪状态的线程,改变优先级后,线程需要移动到新的优先级的就绪线程链表里面(从原来链表删除,再添加到新的就绪线程链表)
136
137
138 /* Pickup the next thread to execute. */
139 execute_ptr = _tx_thread_execute_ptr; // 保存当前时间下一个需要执行的线程
140
141 /* Save the original priority. */
142 original_priority = thread_ptr -> tx_thread_priority; // 记录线程的原始优先级(改变优先级前的优先级)
143
144 #ifdef TX_NOT_INTERRUPTABLE
145
146 /* Increment the preempt disable flag. */
147 _tx_thread_preempt_disable++;
148
149 /* Set the state to priority change. */
150 thread_ptr -> tx_thread_state = TX_PRIORITY_CHANGE;
151
152 /* Call actual non-interruptable thread suspension routine. */
153 _tx_thread_system_ni_suspend(thread_ptr, ((ULONG) 0));
154
155 /* At this point, the preempt disable flag is still set, so we still have
156 protection against all preemption. */
157
158 /* Change thread priority to the new mutex priority-inheritance priority. */
159 thread_ptr -> tx_thread_priority = new_priority;
160
161 /* Determine how to setup the thread's preemption-threshold. */
162 if (thread_ptr -> tx_thread_user_preempt_threshold < new_priority)
163
164
165 /* Change thread preemption-threshold to the user's preemption-threshold. */
166 thread_ptr -> tx_thread_preempt_threshold = thread_ptr -> tx_thread_user_preempt_threshold;
167
168 else
169
170
171 /* Change the thread preemption-threshold to the new threshold. */
172 thread_ptr -> tx_thread_preempt_threshold = new_priority;
173
174
175 /* Resume the thread with the new priority. */
176 _tx_thread_system_ni_resume(thread_ptr);
177
178 /* Decrement the preempt disable flag. */
179 _tx_thread_preempt_disable--;
180 #else
181
182 /* Increment the preempt disable flag. */
183 _tx_thread_preempt_disable = _tx_thread_preempt_disable + ((UINT) 2); // 禁止抢占计数器加2(主要因为移动线程到其他就绪线程链表需要挂起再唤醒该线程,挂起/唤醒会对禁止抢占计数器减1,如果_tx_thread_preempt_disable减为0,就会进行调度,对抢占计数器加2就是为了在挂起/唤醒过程中,禁止抢占当前线程,不管是否有高优先级线程,当前线程需要继续处理后续代码;调用_tx_mutex_priority_change函数前的代码已经禁止抢占了,所以_tx_mutex_priority_change不会被其他线程抢占!!!)
184
185 /* Set the state to priority change. */
186 thread_ptr -> tx_thread_state = TX_PRIORITY_CHANGE; // 将线程状态设置为TX_PRIORITY_CHANGE(主要是在挂起操作时,对TX_PRIORITY_CHANGE以及其他特殊状态的线程进行挂起,并不会立即挂起,而是会设置一个延迟挂起的标志,这些状态正在处理比较重要的事情,这个过程不能被挂起;延迟挂起被设置,那么下次唤醒线程时,就会执行延迟的挂起操作,挂起线程)
187
188 /* Set the suspending flag. */
189 thread_ptr -> tx_thread_suspending = TX_TRUE; // 设置挂起中(挂起中表示线程还没从就绪线程链表删除,如果有其他操作唤醒挂起中的线程,那么将状态改成就绪即可,因为线程还在就绪线程链表,不需要再次添加到就绪线程链表;_tx_thread_system_suspend只会对挂起中的线程进行挂起操作,线程的挂起中如果不为真,那么,可能线程挂起过程中,被其他线程唤醒了,就不要再继续挂起线程)
190
191 /* Setup the timeout period. */
192 thread_ptr -> tx_thread_timer.tx_timer_internal_remaining_ticks = ((ULONG) 0); // 本次挂起不需要启动定时器(本次挂起的目的主要是将线程从就绪线程链表删除)
193
194 /* Restore interrupts. */
195 TX_RESTORE
196
197 /* The thread is ready and must first be removed from the list. Call the
198 system suspend function to accomplish this. */
199 _tx_thread_system_suspend(thread_ptr); // 挂起线程,从就绪线程链表删除线程,会对禁止抢占计数器减1(_tx_thread_system_suspend并不知道本次挂起的目的,挂起thread_ptr,可能会选一个新的下一个被执行的线程,所以前面先记录了下一个被执行的线程)
200
201 /* Disable interrupts. */
202 TX_DISABLE
203
204 /* At this point, the preempt disable flag is still set, so we still have
205 protection against all preemption. */
206
207 /* Change thread priority to the new mutex priority-inheritance priority. */
208 thread_ptr -> tx_thread_priority = new_priority; // 设置新的线程优先级
209
210 /* Determine how to setup the thread's preemption-threshold. */
211 if (thread_ptr -> tx_thread_user_preempt_threshold < new_priority) // 抢占阈值更新
212
213
214 /* Change thread preemption-threshold to the user's preemption-threshold. */
215 thread_ptr -> tx_thread_preempt_threshold = thread_ptr -> tx_thread_user_preempt_threshold;
216
217 else
218
219
220 /* Change the thread preemption-threshold to the new threshold. */
221 thread_ptr -> tx_thread_preempt_threshold = new_priority;
222
223
224 /* Restore interrupts. */
225 TX_RESTORE
226
227 /* Resume the thread with the new priority. */
228 _tx_thread_system_resume(thread_ptr); // 唤醒线程,将线程加入就绪线程链表,会对禁止抢占计数器减1,前面加的2被减没了,但是_tx_mutex_priority_change被调用前,禁止抢占计数器都会先加1,所以_tx_thread_system_resume还是不能调度其他线程,不会切换线程,后续代码要重新对下一个要执行的线程进行计算
229 #endif
230
231 /* Optional processing extension. */
232 TX_MUTEX_PRIORITY_CHANGE_EXTENSION
233
234 #ifndef TX_NOT_INTERRUPTABLE
235
236 /* Disable interrupts. */
237 TX_DISABLE
238 #endif
239
240 /* Pickup the next thread to execute. */
241 next_execute_ptr = _tx_thread_execute_ptr; // 挂起/唤醒线程,允许中断过程可能有更高优先级线程就绪,获取当前下一个要执行的线程
242
243 /* Determine if this thread is not the next thread to execute. */
244 if (thread_ptr != next_execute_ptr) // 被改变优先级的线程不是下一个需要执行的线程
245
246
247 /* Make sure the thread is still ready. */
248 if (thread_ptr -> tx_thread_state == TX_READY) // _tx_thread_system_resume正常情况就会把线程设置为就绪状态,但是前面有解释延迟挂起,也就是在挂起线程中调用_tx_thread_system_resume之前,有其他操作挂起该线程并设置了延迟挂起,那么_tx_thread_system_resume就会挂起线程,而不会唤醒线程,因此这里还要再次判断线程状态
249
250
251 /* Now check and see if this thread has an equal or higher priority. */
252 if (thread_ptr -> tx_thread_priority <= next_execute_ptr -> tx_thread_priority) // 改变优先级的线程的优先级等于或者高于下一个需要执行的线程
253
254
255 /* Now determine if this thread was the previously executing thread. */
256 if (thread_ptr == execute_ptr) // 如果thread_ptr在改变优先级之前就是下一个需要执行的线程,并且thread_ptr现在的优先级也不比next_execute_ptr低,那么应该继续选择thread_ptr作为下一个要执行的线程(释放互斥锁时,恢复低优先级,可能降低到次优先级就绪线程链表或者更低优先级线程启用了抢占,导致降低优先级的线程不能抢占线程next_execute_ptr)
257
258
259 /* Yes, this thread was previously executing before we temporarily suspended and resumed
260 it in order to change the priority. A lower or same priority thread cannot be the next thread
261 to execute in this case since this thread really didn't suspend. Simply reset the execute
262 pointer to this thread. */
263 _tx_thread_execute_ptr = thread_ptr; // 让thread_ptr线程继续执行
264
265 /* Determine if we moved to a lower priority. If so, move the thread to the front of its priority list. */
266 if (original_priority < new_priority) // 如果线程的优先级被降低了,thread_ptr可能添加到了就绪线程链表末尾,需要将thread_ptr移动到就绪线程链表表头(释放互斥锁优先级升高情况,暂时有些疑问,没看到怎么保证thread_ptr在链表表头,提交了一个issues到社区,等待社区回复!!!)
267
268
269 /* Ensure that this thread is placed at the front of the priority list. */
270 _tx_thread_priority_list[thread_ptr -> tx_thread_priority] = thread_ptr; // 就绪线程链表表头指向thread_ptr(等价将thread_ptr移动到表头)
271
272
273
274 else // 1、提高优先级过程有更高优先级线程被中断服务程序唤醒,next_execute_ptr为被唤醒的高优先级线程 2、线程优先级降低,降低后已经不是最高优先级
275
276
277 /* Now determine if this thread's preemption-threshold needs to be enforced. */
278 if (thread_ptr -> tx_thread_preempt_threshold < thread_ptr -> tx_thread_priority) // thread_ptr启用了抢占,需要检查thread_ptr是否可以抢占next_execute_ptr(如果thread_ptr是当前释放互斥锁的线程,thread_ptr本来就是抢占了一些其他高优先级的线程,因为挂起恢复操作,内核选择了其他被抢占的高优先级线程执行,那么是不合理的,需要让thread_ptr继续抢占其他高优先级线程;如果有更高优先级线程被唤醒,且优先级高于thread_ptr的抢占阈值,那么thread_ptr需要标记被抢占)
279
280
281 /* Yes, preemption-threshold is in force for this thread. */
282
283 /* Compare the next thread to execute thread's priority against the thread's preemption-threshold. */
284 if (thread_ptr -> tx_thread_preempt_threshold <= next_execute_ptr -> tx_thread_priority) // thread_ptr的抢占阈值高于next_execute_ptr,thread_ptr抢占next_execute_ptr
285
286
287 /* We must swap execute pointers to enforce the preemption-threshold of a thread coming out of
288 priority inheritance. */
289 _tx_thread_execute_ptr = thread_ptr;
290
291 /* Determine if we moved to a lower priority. If so, move the thread to the front of its priority list. */
292 if (original_priority < new_priority) // 这里升高优先级也需要考虑,还有疑问,等待社区回复!!!
293
294
295 /* Ensure that this thread is placed at the front of the priority list. */
296 _tx_thread_priority_list[thread_ptr -> tx_thread_priority] = thread_ptr;
297
298
299
300 #ifndef TX_DISABLE_PREEMPTION_THRESHOLD
301
302 else // 下面的抢占标记似乎应该保证thread_ptr在链表表头,这个问题待社区回复(阅读threadx-6.1.2代码的时候,发现这个标记也有问题,然后查看官网最新代码已经修复了,写文章时顺道改了,旧的代码标记的是next_execute_ptr,实际是thread_ptr被抢占了,不是next_execute_ptr被抢占)
303
304
305 /* In this case, we need to mark the preempted map to indicate a thread executed above the
306 preemption-threshold. */
307
308 #if TX_MAX_PRIORITIES > 32
309
310 /* Calculate the index into the bit map array. */
311 map_index = (thread_ptr -> tx_thread_priority)/ ((UINT) 32);
312
313 /* Set the active bit to remember that the preempt map has something set. */
314 TX_DIV32_BIT_SET(thread_ptr -> tx_thread_priority, priority_bit)
315 _tx_thread_preempted_map_active = _tx_thread_preempted_map_active | priority_bit;
316 #endif
317
318 /* Remember that this thread was preempted by a thread above the thread's threshold. */
319 TX_MOD32_BIT_SET(thread_ptr -> tx_thread_priority, priority_bit)
320 _tx_thread_preempted_maps[MAP_INDEX] = _tx_thread_preempted_maps[MAP_INDEX] | priority_bit;
321
322 #endif
323
324
325
326
327
328 #ifndef TX_NOT_INTERRUPTABLE
329
330 /* Restore interrupts. */
331 TX_RESTORE
332 #endif
333
334
335
3、互斥锁释放_tx_mutex_put
互斥锁释放与互斥锁申请类似,因为互斥锁是可多次获取的,因此释放互斥锁也是要对互斥锁计数器减1,如果为0,才是真正释放互斥锁,因为存在继承优先级,释放互斥锁线程当前运行的优先级并不一定是创建时的优先级,如果没有占用其他互斥锁(不需要继承互斥锁优先级),那么就需要恢复创建时的优先级,如果还有占用其他线程,那么需要继承其他等待互斥锁线程的最高优先级,调整优先级跟获取互斥锁调整优先级一样的,前面小结已经介绍;
继承优先级,释放互斥锁时,是将互斥锁直接给等待互斥锁的最高优先级线程,也就是优先级高的线程先获取到互斥锁。
_tx_mutex_put实现代码如下:
047 UINT _tx_mutex_put(TX_MUTEX *mutex_ptr)
048
049
050 TX_INTERRUPT_SAVE_AREA
051
052 TX_THREAD *thread_ptr;
053 TX_THREAD *old_owner;
054 UINT old_priority;
055 UINT status;
056 TX_MUTEX *next_mutex;
057 TX_MUTEX *previous_mutex;
058 UINT owned_count;
059 UINT suspended_count;
060 TX_THREAD *current_thread;
061 TX_THREAD *next_thread;
062 TX_THREAD *previous_thread;
063 TX_THREAD *suspended_thread;
064 UINT inheritance_priority;
065
066
067 /* Setup status to indicate the processing is not complete. */
068 status = TX_NOT_DONE;
069
070 /* Disable interrupts to put an instance back to the mutex. */
071 TX_DISABLE
072
073 #ifdef TX_MUTEX_ENABLE_PERFORMANCE_INFO
074
075 /* Increment the total mutex put counter. */
076 _tx_mutex_performance_put_count++;
077
078 /* Increment the number of attempts to put this mutex. */
079 mutex_ptr -> tx_mutex_performance_put_count++;
080 #endif
081
082 /* If trace is enabled, insert this event into the trace buffer. */
083 TX_TRACE_IN_LINE_INSERT(TX_TRACE_MUTEX_PUT, mutex_ptr, TX_POINTER_TO_ULONG_CONVERT(mutex_ptr -> tx_mutex_owner), mutex_ptr -> tx_mutex_ownership_count, TX_POINTER_TO_ULONG_CONVERT(&old_priority), TX_TRACE_MUTEX_EVENTS)
084
085 /* Log this kernel call. */
086 TX_EL_MUTEX_PUT_INSERT
087
088 /* Determine if this mutex is owned. */
089 if (mutex_ptr -> tx_mutex_ownership_count != ((UINT) 0)) // 互斥锁计数器不为0才被占用
090
091
092 /* Pickup the owning thread pointer. */
093 thread_ptr = mutex_ptr -> tx_mutex_owner; // 获取占用互斥锁的线程
094
095 /* Pickup thread pointer. */
096 TX_THREAD_GET_CURRENT(current_thread) // 获取当前线程
097
098 /* Check to see if the mutex is owned by the calling thread. */
099 if (mutex_ptr -> tx_mutex_owner != current_thread) // 如果占用互斥锁的线程不是当前线程,设置状态为TX_NOT_OWNED,不能释放别的线程占用的互斥锁,返回
100
101
102 /* Determine if the preempt disable flag is set, indicating that
103 the caller is not the application but from ThreadX. In such
104 cases, the thread mutex owner does not need to match. */
105 if (_tx_thread_preempt_disable == ((UINT) 0)) // _tx_thread_preempt_disable为0表示是应用程序调用,应用程序不能释放其他线程占用的互斥锁
106
107
108 /* Invalid mutex release. */
109
110 /* Restore interrupts. */
111 TX_RESTORE
112
113 /* Caller does not own the mutex. */
114 status = TX_NOT_OWNED;
115
116
117
118 /* Determine if we should continue. */
119 if (status == TX_NOT_DONE)
120
121
122 /* Decrement the mutex ownership count. */
123 mutex_ptr -> tx_mutex_ownership_count--; // 互斥锁计数器减1
124
125 /* Determine if the mutex is still owned by the current thread. */
126 if (mutex_ptr -> tx_mutex_ownership_count != ((UINT) 0)) // 互斥锁嵌套占用,没有真正释放,设置状态为TX_SUCCESS,返回即可
127
128
129 /* Restore interrupts. */
130 TX_RESTORE
131
132 /* Mutex is still owned, just return successful status. */
133 status = TX_SUCCESS;
134
135 else // 互斥锁被释放
136
137
138 /* Check for a NULL thread pointer, which can only happen during initialization. */
139 if (thread_ptr == TX_NULL) // 内核初始化过程释放互斥锁,不需要处理
140
141
142 /* Restore interrupts. */
143 TX_RESTORE
144
145 /* Mutex is now available, return successful status. */
146 status = TX_SUCCESS;
147
148 else // 线程释放互斥锁
149
150
151 /* The mutex is now available. */
152
153 /* Remove this mutex from the owned mutex list. */
154
155 /* Decrement the ownership count. */
156 thread_ptr -> tx_thread_owned_mutex_count--; // 线程占用的互斥锁个数减1
157
158 /* Determine if this mutex was the only one on the list. */
159 if (thread_ptr -> tx_thread_owned_mutex_count == ((UINT) 0)) // 占用的互斥锁个数为0,占用互斥锁链表tx_thread_owned_mutex_list设置为0即可
160
161
162 /* Yes, the list is empty. Simply set the head pointer to NULL. */
163 thread_ptr -> tx_thread_owned_mutex_list = TX_NULL;
164
165 else // 将释放的互斥锁从tx_thread_owned_mutex_list删除
166
167
168 /* No, there are more mutexes on the list. */
169
170 /* Link-up the neighbors. */
171 next_mutex = mutex_ptr -> tx_mutex_owned_next;
172 previous_mutex = mutex_ptr -> tx_mutex_owned_previous;
173 next_mutex -> tx_mutex_owned_previous = previous_mutex;
174 previous_mutex -> tx_mutex_owned_next = next_mutex;
175
176 /* See if we have to update the created list head pointer. */
177 if (thread_ptr -> tx_thread_owned_mutex_list == mutex_ptr)
178
179
180 /* Yes, move the head pointer to the next link. */
181 thread_ptr -> tx_thread_owned_mutex_list = next_mutex;
182
183
184
185 /* Determine if the simple, non-suspension, non-priority inheritance case is present. */
186 if (mutex_ptr -> tx_mutex_suspension_list == TX_NULL) // 没有等待互斥锁的线程
187
188
189 /* Is this a priority inheritance mutex? */
190 if (mutex_ptr -> tx_mutex_inherit == TX_FALSE) // 如果没有继承优先级(占用互斥锁的线程不会动态调整优先级),返回即可
191
192
193 /* Yes, we are done - set the mutex owner to NULL. */
194 mutex_ptr -> tx_mutex_owner = TX_NULL;
195
196 /* Restore interrupts. */
197 TX_RESTORE
198
199 /* Mutex is now available, return successful status. */
200 status = TX_SUCCESS;
201
202
203
204 /* Determine if the processing is complete. */
205 if (status == TX_NOT_DONE) // 有等待互斥锁的线程或者有继承优先级(需要还原优先级)
206
207
208 /* Initialize original owner and thread priority. */
209 old_owner = TX_NULL;
210 old_priority = thread_ptr -> tx_thread_user_priority;
211
212 /* Does this mutex support priority inheritance? */
213 if (mutex_ptr -> tx_mutex_inherit == TX_TRUE) // 互斥锁支持继承优先级(if分支获取继承的优先级,如果继承的优先级比线程创建时的优先级还低,那么恢复到线程创建时的优先级(先记录,if后面恢复))
214
215
216 #ifndef TX_NOT_INTERRUPTABLE
217
218 /* Temporarily disable preemption. */
219 _tx_thread_preempt_disable++; // 禁止抢占
220
221 /* Restore interrupts. */
222 TX_RESTORE // 允许中断(抢占被禁止了,中断服务程序不会操作互斥锁相关的数据,所以可以允许中断)
223 #endif
224
225 /* Default the inheritance priority to disabled. */
226 inheritance_priority = ((UINT) TX_MAX_PRIORITIES); // 继承的优先级
227
228 /* Search the owned mutexes for this thread to determine the highest priority for this
229 former mutex owner to return to. */
230 next_mutex = thread_ptr -> tx_thread_owned_mutex_list; // 下一个互斥锁
231 while (next_mutex != TX_NULL) // 遍历互斥锁链表(查找当前线程需要继承的最高优先级)
232
233
234 /* Does this mutex support priority inheritance? */
235 if (next_mutex -> tx_mutex_inherit == TX_TRUE) // next_mutex支持继承优先级
236
237
238 /* Determine if highest priority field of the mutex is higher than the priority to
239 restore. */
240 if (next_mutex -> tx_mutex_highest_priority_waiting < inheritance_priority) // next_mutex等待互斥锁的线程的最高优先级高于inheritance_priority
241
242
243 /* Use this priority to return releasing thread to. */
244 inheritance_priority = next_mutex -> tx_mutex_highest_priority_waiting; // inheritance_priority更新为继承的最高优先级
245
246
247
248 /* Move mutex pointer to the next mutex in the list. */
249 next_mutex = next_mutex -> tx_mutex_owned_next;
250
251 /* Are we at the end of the list? */
252 if (next_mutex == thread_ptr -> tx_thread_owned_mutex_list)
253
254
255 /* Yes, set the next mutex to NULL. */
256 next_mutex = TX_NULL;
257
258
259
260 #ifndef TX_NOT_INTERRUPTABLE
261
262 /* Disable interrupts. */
263 TX_DISABLE // 关闭中断(可能中断会影响后面的代码或者性能,并且后面很快就会允许中断,所以禁止中断)
264
265 /* Undo the temporarily preemption disable. */
266 _tx_thread_preempt_disable--; // 取消临时的禁止抢占
267 #endif
268
269 /* Set the inherit priority to that of the highest priority thread waiting on the mutex. */
270 thread_ptr -> tx_thread_inherit_priority = inheritance_priority; // 设置线程继承优先级
271
272 /* Determine if the inheritance priority is less than the default old priority. */
273 if (inheritance_priority < old_priority) // 如果继承的优先级高于线程创建时指定的优先级,那么使用继承优先级做为线程的优先级(old_priority在后面会用于调整线程的优先级),否则释放互斥锁锁后恢复到线程创建时的优先级
274
275
276 /* Yes, update the old priority. */
277 old_priority = inheritance_priority;
278
279
280
281 /* Determine if priority inheritance is in effect and there are one or more
282 threads suspended on the mutex. */
283 if (mutex_ptr -> tx_mutex_suspended_count > ((UINT) 1)) // 有多于1个线程等待互斥锁mutex_ptr,并且互斥锁有优先级继承,那么需要唤醒最高优先级的等待线程
284
285
286 /* Is priority inheritance in effect? */
287 if (mutex_ptr -> tx_mutex_inherit == TX_TRUE)
288
289
290 /* Yes, this code is simply to ensure the highest priority thread is positioned
291 at the front of the suspension list. */
292
293 #ifndef TX_NOT_INTERRUPTABLE
294
295 /* Temporarily disable preemption. */
296 _tx_thread_preempt_disable++; // 禁止抢占(后面对等待互斥锁的线程链表进行处理,如果允许抢占的话,有等待互斥锁的线程超时的话,超时回调函数也会操作链表,就保证不了对链表的互斥操作)
297
298 /* Restore interrupts. */
299 TX_RESTORE // 允许中断(后面把等待互斥锁的最高优先级线程移动到链表前面需要一些时间,需要允许中断,否则定时器中断就不能及时响应)
300 #endif
301
302 /* Call the mutex prioritize processing to ensure the
303 highest priority thread is resumed. */
304 #ifdef TX_MISRA_ENABLE
305 do
306
307 status = _tx_mutex_prioritize(mutex_ptr);
308 while (status != TX_SUCCESS);
309 #else
310 _tx_mutex_prioritize(mutex_ptr); // 将等待互斥锁线程的最高优先级线程移动到等待链表前面(优先级高的线程先获取到互斥锁)
311 #endif
312
313 /* At this point, the highest priority thread is at the
314 front of the suspension list. */
315
316 /* Optional processing extension. */
317 TX_MUTEX_PUT_EXTENSION_1
318
319 #ifndef TX_NOT_INTERRUPTABLE
320
321 /* Disable interrupts. */
322 TX_DISABLE
323
324 /* Back off the preemption disable. */
325 _tx_thread_preempt_disable--;
326 #endif
327
328
329
330 /* Now determine if there are any threads still waiting on the mutex. */
331 if (mutex_ptr -> tx_mutex_suspension_list == TX_NULL) // 检查是否有线程仍然在等待互斥锁(前面检查过tx_mutex_suspension_list不为空,目前互斥锁等待超时是在超时线程里面处理,如果互斥锁超时在中断服务程序里面处理,那么tx_mutex_suspension_list倒可能被修改,暂时没看到其他场景,正常情况这里不会为空,先略过...)
332
333
334 /* No, there are no longer any threads waiting on the mutex. */
335
336 #ifndef TX_NOT_INTERRUPTABLE
337
338 /* Temporarily disable preemption. */
339 _tx_thread_preempt_disable++;
340
341 /* Restore interrupts. */
342 TX_RESTORE
343 #endif
344
345 /* Mutex is not owned, but it is possible that a thread that
346 caused a priority inheritance to occur is no longer waiting
347 on the mutex. */
348
349 /* Setup the highest priority waiting thread. */
350 mutex_ptr -> tx_mutex_highest_priority_waiting = (UINT) TX_MAX_PRIORITIES; // 没有等待互斥锁的线程,等待互斥锁线程的最高优先级设置为默认优先级TX_MAX_PRIORITIES
351
352 /* Determine if we need to restore priority. */
353 if ((mutex_ptr -> tx_mutex_owner) -> tx_thread_priority != old_priority) // (mutex_ptr -> tx_mutex_owner) -> tx_thread_priority记录占用互斥锁线程运行时的优先级,old_priority为前面检查出来的等待互斥锁线程的最高优先级或者线程创建时的优先级,也就是释放互斥锁后,线程该恢复的优先级,如果当前的优先级与要恢复的优先级不同,那么就调用_tx_mutex_priority_change调整/恢复线程优先级,mutex_ptr -> tx_mutex_owner前面已经检查了,就是current_thread
354
355
356 /* Yes, restore the priority of thread. */
357 _tx_mutex_priority_change(mutex_ptr -> tx_mutex_owner, old_priority); // 恢复线程创建时的优先级或者继承的最高优先级
358
359
360 #ifndef TX_NOT_INTERRUPTABLE
361
362 /* Disable interrupts again. */
363 TX_DISABLE
364
365 /* Back off the preemption disable. */
366 _tx_thread_preempt_disable--;
367 #endif
368
369 /* Set the mutex owner to NULL. */
370 mutex_ptr -> tx_mutex_owner = TX_NULL;
371
372 /* Restore interrupts. */
373 TX_RESTORE
374
375 /* Check for preemption. */
376 _tx_thread_system_preempt_check(); // 这里基本已经释放完了互斥锁,后续也没有其他操作要进行,因为前面禁止了抢占,释放互斥锁的上一级函数不会检查抢占,禁止抢占的过程中,可能有更高优先级线程就绪,所以在这里检查抢占,如果有被抢占的话,那么要重新调度
377
378 /* Set status to success. */
379 status = TX_SUCCESS;
380
381 else // 有线程等待互斥锁
382
383
384 /* Pickup the thread at the front of the suspension list. */
385 thread_ptr = mutex_ptr -> tx_mutex_suspension_list; // 获取等待互斥锁的最高优先级线程(前面已经将最高优先级线程移动到表头了)
386
387 /* Save the previous ownership information, if inheritance is
388 in effect. */
389 if (mutex_ptr -> tx_mutex_inherit == TX_TRUE) // 继承优先级
390
391
392 /* Remember the old mutex owner. */
393 old_owner = mutex_ptr -> tx_mutex_owner; // 记录旧的占用互斥锁的线程
394
395 /* Setup owner thread priority information. */
396 mutex_ptr -> tx_mutex_original_priority = thread_ptr -> tx_thread_priority; // 记录thread_ptr的原始优先级(thread_ptr即将获得互斥锁,因为继承优先级的关系,thread_ptr可能会改变优先级)
397
398 /* Setup the highest priority waiting thread. */
399 mutex_ptr -> tx_mutex_highest_priority_waiting = (UINT) TX_MAX_PRIORITIES;
400
401
402 /* Determine how many mutexes are owned by this thread. */
403 owned_count = thread_ptr -> tx_thread_owned_mutex_count; // thread_ptr之前占用多少互斥锁(互斥锁嵌套,线程可能占用多个互斥锁)
404
405 /* Determine if this thread owns any other mutexes that have priority inheritance. */
406 if (owned_count == ((UINT) 0)) // thread_ptr没有占用其他线程,那么当前互斥锁就是该线程唯一获得的互斥锁,一个互斥锁组成一个链表(线程占用互斥锁的链表tx_thread_owned_mutex_list)
407
408
409 /* The owned mutex list is empty. Add mutex to empty list. */
410 thread_ptr -> tx_thread_owned_mutex_list = mutex_ptr;
411 mutex_ptr -> tx_mutex_owned_next = mutex_ptr;
412 mutex_ptr -> tx_mutex_owned_previous = mutex_ptr;
413
414 else // 将互斥锁加入旧的占用互斥锁链表tx_thread_owned_mutex_list
415
416
417 /* Non-empty list. Link up the mutex. */
418
419 /* Pickup tail pointer. */
420 next_mutex = thread_ptr -> tx_thread_owned_mutex_list;
421 previous_mutex = next_mutex -> tx_mutex_owned_previous; // previous_mutex第一个节点的前一个节点,也就是尾节点
422
423 /* Place the owned mutex in the list. */
424 next_mutex -> tx_mutex_owned_previous = mutex_ptr;
425 previous_mutex -> tx_mutex_owned_next = mutex_ptr;
426
427 /* Setup this mutex's next and previous created links. */
428 mutex_ptr -> tx_mutex_owned_previous = previous_mutex;
429 mutex_ptr -> tx_mutex_owned_next = next_mutex;
430
431
432 /* Increment the number of mutexes owned counter. */
433 thread_ptr -> tx_thread_owned_mutex_count = owned_count + ((UINT) 1); // thread_ptr占用互斥锁个数加1(释放互斥锁的时候,直接将互斥锁给thread_ptr,不需要唤醒所有等待互斥锁的线程,让这些线程去抢占互斥锁)
434
435 /* Mark the Mutex as owned and fill in the corresponding information. */
436 mutex_ptr -> tx_mutex_ownership_count = (UINT) 1; // mutex_ptr第一次获取到互斥锁mutex_ptr
437 mutex_ptr -> tx_mutex_owner = thread_ptr; // 互斥锁mutex_ptr被线程thread_ptr占用
438
439 /* Remove the suspended thread from the list. */
440
441 /* Decrement the suspension count. */
442 mutex_ptr -> tx_mutex_suspended_count--以上是关于ThreadX内核源码分析 - 线程同步之互斥锁及动态优先级的主要内容,如果未能解决你的问题,请参考以下文章
ThreadX内核源码分析(SMP) - 核间互斥(arm)
ThreadX内核源码分析 - 定时器及线程时间片调度(arm)
ThreadX内核源码分析 - 定时器及线程时间片调度(arm)