ThreadX内核源码分析 - 优先级及抢占阈值抢占(arm)

1、就绪线程链表_tx_thread_priority_list

优先级越高值越低,同优先级线程按先进先出加入就绪线程链表,正在执行的线程始终在就绪线程链表的表头(线程调度时不会从就绪线程链表删除)。

ThreadX内核源码分析 - 优先级及抢占阈值抢占(arm)_第1张图片

2、抢占阈值threshold

线程的抢占阈值大于线程的优先级时,表示线程启用了抢占,也就是该线程可以抢占同优先级线程以及优先级比该线程抢占阈值低的线程;内核保证抢占阈值不会小于线程优先级,否则抢占阈值是错误的,因此只要抢占阈值不等与线程优先级就表示抢占阈值高于线程优先级;

没有启用抢占的线程按优先级及时间片调度,抢占阈值只对启用了抢占的线程正在执行时以及恢复执行时起作用:

  • 启用抢占的线程正在执行时,如果时间片用尽或者有高优先级线程就绪,那么下一个可能需要调度的线程的优先级必须高于当前正在执行的线程的抢占阈值,被抢占时需要在_tx_thread_preempted_maps标记被抢占的线程(对应优先级位设置为1即可),否则正在执行的线程抢占高优先级线程及同优先级线程继续执行;这里也就是抢占阈值对正在执行的线程有作用,不会判断被唤醒线程的抢占阈值是否高于正在执行线程的优先级及抢占阈值;
  • 高优先级线程退出,高优先级就绪线程链表变为空(如果同优先级线程有就绪线程,那么同优先级就绪线程的优先级仍然高于被抢占的启用了抢占阈值线程的抢占阈值),需要调度下一个高优先级就绪线程链表线程时,下一个高优先级的优先级可能高于当前退出线程的优先级也可能低于当前退出线程的优先级(正在执行线程启用了抢占,有高优先级线程在等待执行,或者没有高优先级线程就绪),不管哪种情况,被抢占的启用了抢占的线程的抢占阈值都可能高于下一个需要调度的线程的优先级,如果有被抢占的启用了抢占的线程的抢占阈值高于下一个高优先级就绪线程,那么优先恢复启用了抢占被抢占出去的线程;这也就是为什么启用了抢占的线程被抢占的时候要在_tx_thread_preempted_maps里面标记了,也就是抢占阈值在被抢占线程在恢复执行时起作用的原因。

也可以以另外一种方式理解,可能更容易理解,线程被执行时,该线程的优先级就等于线程的抢占阈值threshold,该线程并没有加到threshold对应就绪线程链表,该线程被抢占出去的时候,下次并不能在threshold对应优先级链表找到,因此需要通过_tx_thread_preempted_maps找到threshold对应优先级线程,可以理解_tx_thread_preempted_maps就是一个临时的就绪线程链表,内核有两个就绪线程链表,调度线程时需要检查两个就绪线程链表而已。

3、抢占位图_tx_thread_preempted_maps

启用抢占的线程一定意义上是以threshold优先级在执行,被抢占时,threshold对应优先级链表找不到被抢占的线程,借助_tx_thread_preempted_maps来找到threshold优先级的线程;

启用抢占的正在执行的线程被抢占时,_tx_thread_preempted_maps对应优先级位设置为1,通过优先级找到线程的控制块,通过控制块找到线程的threshold,threshold也就是该线程执行时的动态优先级,有高优先级退出时,要检查threshold是否可以抢占其他就绪线程。

需要特别理解的是,_tx_thread_preempted_maps高优先级线程的优先级一定高于低优先级抢占阈值,把_tx_thread_preempted_maps当作就绪线程链表,那么可以理解_tx_thread_preempted_maps是按优先级排序的;启用抢占的高优先级线程被抢占的前提是高优先级线程需要执行,而执行的前提是,高优先级线程的优先级不能被_tx_thread_preempted_maps里面的线程的抢占阈值抢占,也就是高优先级线程的优先级高于_tx_thread_preempted_maps里面线程的抢占阈值,自然而然_tx_thread_preempted_maps高优先级线程的抢占阈值也高于_tx_thread_preempted_maps低优先级线程的抢占阈值。

4、优先级抢占

之前介绍时间片的时候介绍过启用抢占的线程时间片用尽时不会调度同优先级的下一个就绪线程,在此略过;内核只有在线程唤醒时,才可能导致当前执行线程的优先级不是最高的情况,因此,抢占只可能发生在线程唤醒时。

主要实现代码在_tx_thread_system_resume函数里面,_tx_thread_system_resume主要过程是:

  • 去激活线程的定时器(这些定时器主要也是用来唤醒线程的,线程已经唤醒就不需要这些定时器了)
  • 线程状态检查,多线程对同一个线程进行唤醒操作或者线程本来就不是挂起状态,对线程进行唤醒并不能真正唤醒线程
  • 对唤醒线程检查是否可以抢占正在执行的线程,可以抢占的话,如果被抢占的线程已经启用了抢占,那么还得标记一下被抢占的线程,设置下一个执行的线程,返回系统,系统调度下一个需要执行的线程,否则加到就绪线程链表即可

tx_thread_system_resume代码实现如下:

081 VOID  _tx_thread_system_resume(TX_THREAD *thread_ptr)
082 #ifndef TX_NOT_INTERRUPTABLE
083 {
084 
085 TX_INTERRUPT_SAVE_AREA
086 
087 UINT            priority;
088 ULONG           priority_bit;
089 TX_THREAD       *head_ptr;
090 TX_THREAD       *tail_ptr;
091 TX_THREAD       *execute_ptr;
092 TX_THREAD       *current_thread;
093 ULONG           combined_flags;
094 
095 #ifdef TX_ENABLE_EVENT_TRACE
096 TX_TRACE_BUFFER_ENTRY       *entry_ptr;
097 ULONG                       time_stamp =  ((ULONG) 0);
098 #endif
099 
100 #if TX_MAX_PRIORITIES > 32
101 UINT            map_index;
102 #endif
103 
104 
105 #ifdef TX_ENABLE_STACK_CHECKING
106 
107     /* Check this thread's stack.  */
108     TX_THREAD_STACK_CHECK(thread_ptr)
109 #endif
110 
111     /* Lockout interrupts while the thread is being resumed.  */
112     TX_DISABLE
113 
114 #ifndef TX_NO_TIMER
115 
116     /* Deactivate the timeout timer if necessary.  */
117     if (thread_ptr -> tx_thread_timer.tx_timer_internal_list_head != TX_NULL) // tx_timer_internal_list_head指向超时链表表头,激活的定时器应该都会挂载到_tx_timer_list对应的超时定时器链表里面,如果tx_timer_internal_list_head为空,则说明定时器不在链表里面,也就是没有激活,否则定时器已经激活;ThreadX内核主要用这个定时器来唤醒线程,sleep/timeout等作用,既然这里唤醒线程,那么对应的定时器就不需要了,if分支就是去激活定时器,从超时定时器链表删除
118     {
119 
120         /* Deactivate the thread's timeout timer.  */
121         _tx_timer_system_deactivate(&(thread_ptr -> tx_thread_timer)); // 去激活线程超时定时器(与else分支比较,_tx_timer_system_deactivate没有清除tx_timer_internal_remaining_ticks;Nucleus Plus内核在发送信号给阻塞线程的时候,并不会停止线程的定时器,信号处理比较紧急,Nucleus Plus内核会暂时唤醒线程来处理信号,等信号处理完成后,线程仍然需要回到阻塞状态,等待定时器超时唤醒线程,因此Nucleus Plus内核的阻塞超时定时器并不会因为信号唤醒线程而停止)
122     }
123     else
124     {
125 
126         /* Clear the remaining time to ensure timer doesn't get activated.  */
127         thread_ptr -> tx_thread_timer.tx_timer_internal_remaining_ticks =  ((ULONG) 0); // tx_timer_internal_remaining_ticks设置为0,确保不会获取到定时器激活状态(没有超时时间挂起线程的定时器的tx_timer_internal_remaining_ticks为TX_WAIT_FOREVER,该线程是不会激活定时器的,不会挂载到超时定时器链表)
128     }
129 #endif
130 
131 #ifdef TX_ENABLE_EVENT_TRACE
132 
133     /* If trace is enabled, save the current event pointer.  */
134     entry_ptr =  _tx_trace_buffer_current_ptr;
135 #endif
136 
137     /* Log the thread status change.  */
138     TX_TRACE_IN_LINE_INSERT(TX_TRACE_THREAD_RESUME, thread_ptr, thread_ptr -> tx_thread_state, TX_POINTER_TO_ULONG_CONVERT(&execute_ptr), TX_POINTER_TO_ULONG_CONVERT(_tx_thread_execute_ptr), TX_TRACE_INTERNAL_EVENTS)
139 
140 #ifdef TX_ENABLE_EVENT_TRACE
141 
142     /* Save the time stamp for later comparison to verify that
143        the event hasn't been overwritten by the time we have 
144        computed the next thread to execute.  */
145     if (entry_ptr != TX_NULL)
146     {
147 
148         /* Save time stamp.  */
149         time_stamp =  entry_ptr -> tx_trace_buffer_entry_time_stamp;
150     }
151 #endif
152 
153     /* Decrease the preempt disabled count.  */
154     _tx_thread_preempt_disable--; //  禁止抢占计数器_tx_thread_preempt_disable减1(_tx_thread_system_resume进入前,已经禁止抢占了,但是中断还是开着的,如果不禁止抢占,那么唤醒过程就可能被抢占,唤醒过程就不能及时处理;这里虽然允许抢占了,但是中断还是关着的)
155 
156     /* Determine if the thread is in the process of suspending.  If so, the thread
157        control block is already on the linked list so nothing needs to be done.  */
158     if (thread_ptr -> tx_thread_suspending == TX_FALSE) // 唤醒非挂起过程中的线程(挂起中的线程被没有被真正挂起,还在就绪线程链表里面;真正被挂起的线程已经不在就绪线程链表里面,需要重新加入就绪线程链表)
159     {
160 
161         /* Thread is not in the process of suspending. Now check to make sure the thread 
162            has not already been resumed.  */
163         if (thread_ptr -> tx_thread_state != TX_READY) // 检查线程是否已经被唤醒(一般调用唤醒函数前都会对禁止抢占计数器加1,然后打开中断,虽然唤醒期间不会被抢占,但是不能保证中断服务程序不会唤醒线程,例如驱动中断服务程序的信号量就会唤醒等待信号量的线程)
164         {
165 
166             /* No, now check to see if the delayed suspension flag is set.  */
167             if (thread_ptr -> tx_thread_delayed_suspend == TX_FALSE) // 非延迟挂起状态(挂起一个非就绪/非挂起的线程,会设置tx_thread_delayed_suspend,tx_thread_delayed_suspend也就是有个挂起操作由于线程处于等待信号量或者其他状态而没能立即被挂起,需要等线程唤醒后再挂起,也就是当前函数_tx_thread_system_resume后面会使线程进入挂起状态)
168             {
169     
170                 /* Resume the thread!  */
171                 
172                 /* Make this thread ready.  */
173 
174                 /* Change the state to ready.  */
175                 thread_ptr -> tx_thread_state =  TX_READY; // 线程状态变为就绪状态
176 
177                 /* Pickup priority of thread.  */
178                 priority =  thread_ptr -> tx_thread_priority;
179 
180                 /* Thread state change.  */
181                 TX_THREAD_STATE_CHANGE(thread_ptr, TX_READY)
182 
183                 /* Log the thread status change.  */
184                 TX_EL_THREAD_STATUS_CHANGE_INSERT(thread_ptr, TX_READY)
185 
186 #ifdef TX_THREAD_ENABLE_PERFORMANCE_INFO
187 
188                 /* Increment the total number of thread resumptions.  */
189                 _tx_thread_performance_resume_count++;
190 
191                 /* Increment this thread's resume count.  */
192                 thread_ptr -> tx_thread_performance_resume_count++;
193 #endif
194 
195                 /* Determine if there are other threads at this priority that are
196                    ready.  */
197                 head_ptr =  _tx_thread_priority_list[priority]; // 线程所在就绪线程链表
198                 if (head_ptr == TX_NULL) // 被唤醒线程的就绪线程链表没有其他就绪线程,那么就要一个先优先级的线程就绪,可能存在墙正在;如果过该优先级有其他其他就绪线程,被唤醒线程加到就绪线程链表末尾即可(内核调度的要么是当前优先级的第一个就绪线程或者更高优先级线程,当前被唤醒的线程怎么也不可能抢占线程被唤醒前的就绪线程)
199                 {
200 
201                     /* First thread at this priority ready.  Add to the front of the list.  */
202                     _tx_thread_priority_list[priority] =       thread_ptr; // 该优先级的就绪线程链表(就只有当前被唤醒线程)
203                     thread_ptr -> tx_thread_ready_next =       thread_ptr;
204                     thread_ptr -> tx_thread_ready_previous =   thread_ptr;
205 
206 #if TX_MAX_PRIORITIES > 32
207 
208                     /* Calculate the index into the bit map array.  */
209                     map_index =  priority/((UINT) 32);
210 
211                     /* Set the active bit to remember that the priority map has something set.  */
212                     TX_DIV32_BIT_SET(priority, priority_bit)
213                     _tx_thread_priority_map_active =  _tx_thread_priority_map_active | priority_bit;
214 #endif
215 
216                     /* Or in the thread's priority bit.  */
217                     TX_MOD32_BIT_SET(priority, priority_bit)
218                     _tx_thread_priority_maps[MAP_INDEX] =  _tx_thread_priority_maps[MAP_INDEX] | priority_bit; // _tx_thread_priority_maps中,priority优先级对应的bit位设置为1,表示该优先级有就绪线程
219 
220                     /* Determine if this newly ready thread is the highest priority.  */
221                     if (priority < _tx_thread_highest_priority) // 被唤醒线程的优先级高于被唤醒前的就绪线程的最高优先级
222                     {
223 
224                         /* A new highest priority thread is present. */
225 
226                         /* Update the highest priority variable.  */
227                         _tx_thread_highest_priority =  priority; // 更新就绪线程的最高优先级
228 
229                         /* Pickup the execute pointer. Since it is going to be referenced multiple
230                            times, it is placed in a local variable.  */
231                         execute_ptr =  _tx_thread_execute_ptr; // 获取_tx_thread_execute_ptr(_tx_thread_execute_ptr不一定是当前正在执行的线程,_tx_thread_execute_ptr只是调度程序选出来的下一个应该要执行的线程,优先级高或者抢占阈值高,但是因为禁止抢占等原因,_tx_thread_execute_ptr并不能立即执行或者还没来得及执行)
232                         
233                         /* Determine if no thread is currently executing.  */
234                         if (execute_ptr == TX_NULL) // _tx_thread_execute_ptr为0的话,表示之前没有就绪线程(当前唤醒操作可能是在中断服务程序里面执行),那么当前线程就是下一个需要调度的线程
235                         {
236 
237                             /* Simply setup the execute pointer.  */
238                             _tx_thread_execute_ptr =  thread_ptr; // 设置被唤醒的线程为执行线程
239                         }
240                         else // 虽然被唤醒线程优先级高,但是被唤醒前调度器正要执行_tx_thread_execute_ptr线程,由于抢占阈值,被唤醒线程还得检查_tx_thread_execute_ptr是否启用了抢占,如果_tx_thread_execute_ptr启用了抢占,如果_tx_thread_execute_ptr抢占优先级高于被唤醒线程优先级,那么正在执行的_tx_thread_execute_ptr抢占被唤醒的高优先级线程...
241                         {
242                         
243                             /* Another thread has been scheduled for execution.  */
244                
245                             /* Check to see if this is a higher priority thread and determine if preemption is allowed.  */
246                             if (priority < execute_ptr -> tx_thread_preempt_threshold) // 正在执行的线程不能抢占被唤醒的线程
247                             {
248 
249 #ifndef TX_DISABLE_PREEMPTION_THRESHOLD
250 
251                                 /* Determine if the preempted thread had preemption-threshold set.  */
252                                 if (execute_ptr -> tx_thread_preempt_threshold != execute_ptr -> tx_thread_priority) // 如果正在执行的线程启用了抢占,启用了抢占的线程正在执行时,被抢占而换出cpu的话,那么需要标记一下,如果有高优先级线程退出的话,尽量尽快恢复被抢占的低优先级线程(ThreadX内核抢占阈值并不是在任何时候都有用,而是线程正在执行时以及恢复执行时才有用,线程创建及唤醒时,都是添加到就绪线程链表末尾,并不会用抢占阈值去抢占高优先级线程)
253                                 {
254 
255 #if TX_MAX_PRIORITIES > 32
256 
257                                     /* Calculate the index into the bit map array.  */
258                                     map_index =  (execute_ptr -> tx_thread_priority)/((UINT) 32);
259 
260                                     /* Set the active bit to remember that the preempt map has something set.  */
261                                     TX_DIV32_BIT_SET(execute_ptr -> tx_thread_priority, priority_bit)
262                                     _tx_thread_preempted_map_active =  _tx_thread_preempted_map_active | priority_bit;
263 #endif
264 
265                                     /* Remember that this thread was preempted by a thread above the thread's threshold.  */
266                                     TX_MOD32_BIT_SET(execute_ptr -> tx_thread_priority, priority_bit)
267                                     _tx_thread_preempted_maps[MAP_INDEX] =  _tx_thread_preempted_maps[MAP_INDEX] | priority_bit; // 设置启用了抢占的被抢占的线程的优先级在_tx_thread_preempted_map_active的对应bit位(被抢占出去的正在执行的线程还在就绪线程链表的表头,找到该优先级的就绪线程链表即可找到被抢占的线程;_tx_thread_preempted_map_active后续是从高优先级到低优先级来检查是否可以抢占最高优先级线程的,如果某个高优先级线程退出了,那么会检查_tx_thread_preempted_map_active标记的被抢占切换出去的线程的抢占阈值是否可以抢占下一个高优先级的线程;为什么要从高优先级开始检查呢,因为_tx_thread_preempted_map_active标记的高优先级线程的抢占阈值一定高于_tx_thread_preempted_map_active标记的低优先级线程的抢占阈值,_tx_thread_preempted_map_active高优先级线程要被标记的前提是该线程要在执行时被高优先级线程抢占,而高优先级线程要执行的前提是不能被_tx_thread_preempted_map_active标记的低优先级线程抢占)
268                                 }
269 #endif
270 
271 #ifdef TX_THREAD_ENABLE_PERFORMANCE_INFO
272 
273                                 /* Determine if the caller is an interrupt or from a thread.  */
274                                 if (TX_THREAD_GET_SYSTEM_STATE() == ((ULONG) 0))
275                                 {
276 
277                                     /* Caller is a thread, so this is a solicited preemption.  */
278                                     _tx_thread_performance_solicited_preemption_count++;
279 
280                                     /* Increment the thread's solicited preemption counter.  */
281                                     execute_ptr -> tx_thread_performance_solicited_preemption_count++;
282                                 }
283                                 else
284                                 {
285                                   
286                                     if (TX_THREAD_GET_SYSTEM_STATE() < TX_INITIALIZE_IN_PROGRESS)
287                                     {
288 
289                                         /* Caller is an interrupt, so this is an interrupt preemption.  */
290                                         _tx_thread_performance_interrupt_preemption_count++;
291 
292                                         /* Increment the thread's interrupt preemption counter.  */
293                                         execute_ptr -> tx_thread_performance_interrupt_preemption_count++;
294                                     }
295                                 }
296 
297                                 /* Remember the thread that preempted this thread.  */
298                                 execute_ptr -> tx_thread_performance_last_preempting_thread =  thread_ptr;
299 
300 #endif
301 
302                                 /* Yes, modify the execute thread pointer.  */
303                                 _tx_thread_execute_ptr =  thread_ptr; // 被唤醒线程的优先级最高,并且正在执行的线程不能抢占被唤醒的线程,设置被唤醒线程为执行线程
304                                 
305 #ifndef TX_MISRA_ENABLE
306 
307                                 /* If MISRA is not-enabled, insert a preemption and return in-line for performance.  */
308 
309 #ifdef TX_THREAD_ENABLE_PERFORMANCE_INFO
310 
311                                 /* Is the execute pointer different?  */
312                                 if (_tx_thread_performance_execute_log[_tx_thread_performance__execute_log_index] != _tx_thread_execute_ptr)
313                                 {
314                      
315                                     /* Move to next entry.  */
316                                     _tx_thread_performance__execute_log_index++;
317             
318                                     /* Check for wrap condition.  */
319                                     if (_tx_thread_performance__execute_log_index >= TX_THREAD_EXECUTE_LOG_SIZE)
320                                     {
321           
322                                         /* Set the index to the beginning.  */
323                                         _tx_thread_performance__execute_log_index =  ((UINT) 0);
324                                     }
325             
326                                     /* Log the new execute pointer.  */
327                                     _tx_thread_performance_execute_log[_tx_thread_performance__execute_log_index] =  _tx_thread_execute_ptr;
328                                 }
329 #endif
330 
331 #ifdef TX_ENABLE_EVENT_TRACE
332 
333                                 /* Check that the event time stamp is unchanged.  A different
334                                    timestamp means that a later event wrote over the thread
335                                    resume event. In that case, do nothing here.  */
336                                 if (entry_ptr != TX_NULL)
337                                 {
338     
339                                     /* Is the timestamp the same?  */
340                                     if (time_stamp == entry_ptr -> tx_trace_buffer_entry_time_stamp)
341                                     {
342         
343                                         /* Timestamp is the same, set the "next thread pointer" to NULL. This can
344                                            be used by the trace analysis tool to show idle system conditions.  */
345                                         entry_ptr -> tx_trace_buffer_entry_information_field_4 =  TX_POINTER_TO_ULONG_CONVERT(_tx_thread_execute_ptr);
346                                     }
347                                 }
348 #endif
349 
350                                 /* Restore interrupts.  */
351                                 TX_RESTORE // 开中断
352 
353 #ifdef TX_ENABLE_STACK_CHECKING
354 
355                                 /* Pickup the next execute pointer.  */
356                                 thread_ptr =  _tx_thread_execute_ptr;
357 
358                                 /* Check this thread's stack.  */
359                                 TX_THREAD_STACK_CHECK(thread_ptr)
360 #endif
361 
362                                 /* Now determine if preemption should take place. This is only possible if the current thread pointer is
363                                    not the same as the execute thread pointer AND the system state and preempt disable flags are clear.  */
364                                 TX_THREAD_SYSTEM_RETURN_CHECK(combined_flags) // 检查_tx_thread_preempt_disable是否禁止抢占以及是否在系统初始化阶段(禁止抢占或者还在系统初始化阶段,还得继续执行当前线程,不能进行线程切换)
365                                 if (combined_flags == ((ULONG) 0))
366                                 {
367 
368 #ifdef TX_THREAD_ENABLE_PERFORMANCE_INFO
369 
370                                     /* There is another thread ready to run and will be scheduled upon return.  */
371                                     _tx_thread_performance_non_idle_return_count++;
372 #endif
373 
374                                     /* Preemption is needed - return to the system!  */
375                                     _tx_thread_system_return(); // 非系统初始化阶段也没有禁止抢占,返回系统执行调度程序,调度被唤醒线程_tx_thread_execute_ptr
376                                 }
377 
378                                 /* Return in-line when MISRA is not enabled.  */
379                                 return;
380 #endif
381                             }
382                         }
383                     }
384                 }
385                 else // 被唤醒线程优先级所在就绪线程链表不为空,将被唤醒线程加入就绪线程链表即可(从下面代码可以看到线程加入的就绪线程链表末尾,也就是就绪线程链表是先进先出的,并不会因为抢占阈值而改变顺序)
386                 {
387 
388                     /* No, there are other threads at this priority already ready.  */
389 
390                     /* Just add this thread to the priority list.  */
391                     tail_ptr =                                 head_ptr -> tx_thread_ready_previous;
392                     tail_ptr -> tx_thread_ready_next =         thread_ptr;
393                     head_ptr -> tx_thread_ready_previous =     thread_ptr;
394                     thread_ptr -> tx_thread_ready_previous =   tail_ptr;
395                     thread_ptr -> tx_thread_ready_next =       head_ptr;
396                 }
397             }
398 
399             /* Else, delayed suspend flag was set.  */
400             else // 延迟挂起标志位被设置,执行未执行完的挂起操作即可(例如线程等待互斥锁进入阻塞状态,别的线程调用挂起操作试图挂起等待互斥锁的线程,那么就会将阻塞的线程设置为等待挂起状态,阻塞的线程等到互斥锁后被唤醒,这里的else分支就会继续被挂起,不会真正唤醒线程,只是状态从阻塞变为挂起状态而已)
401             {
402 
403                 /* Clear the delayed suspend flag and change the state.  */
404                 thread_ptr -> tx_thread_delayed_suspend =  TX_FALSE;
405                 thread_ptr -> tx_thread_state =            TX_SUSPENDED;
406             }
407         }
408     }
409     else // tx_thread_suspending被设置,线程挂起前还没调用_tx_thread_system_suspend的时候会设置tx_thread_suspending,说明有其他挂起操作还在进行中(tx_thread_suspending操作过程线程还没从就绪链表删除,另外线程结束时也调用挂起操作)
410     {
411     
412         /* A resumption occurred in the middle of a previous thread suspension.  */
413         
414         /* Make sure the type of suspension under way is not a terminate or
415            thread completion.  In either of these cases, do not void the 
416            interrupted suspension processing.  */
417         if (thread_ptr -> tx_thread_state != TX_COMPLETED) // 检查线程是否处于TX_COMPLETED状态,线程是否已经结束,如果线程结束了,那么不需要唤醒线程
418         {
419             
420             /* Make sure the thread isn't terminated.  */
421             if (thread_ptr -> tx_thread_state != TX_TERMINATED) // 检查线程是否被终止,线程终止了也不需要唤醒线程
422             {
423 
424                 /* No, now check to see if the delayed suspension flag is set.  */
425                 if (thread_ptr -> tx_thread_delayed_suspend == TX_FALSE)
426                 {
427 
428                     /* Clear the suspending flag.  */
429                     thread_ptr -> tx_thread_suspending =   TX_FALSE;
430 
431                     /* Restore the state to ready.  */
432                     thread_ptr -> tx_thread_state =        TX_READY;
433 
434                     /* Thread state change.  */
435                     TX_THREAD_STATE_CHANGE(thread_ptr, TX_READY) // 唤醒线程(挂起中的线程没有从就绪链表删除,无需重新加入就绪链表)
436 
437                     /* Log the thread status change.  */
438                     TX_EL_THREAD_STATUS_CHANGE_INSERT(thread_ptr, TX_READY)
439                 }
440                 else // tx_thread_suspending
441                 {
442                 
443                     /* Clear the delayed suspend flag and change the state.  */
444                     thread_ptr -> tx_thread_delayed_suspend =  TX_FALSE;
445                     thread_ptr -> tx_thread_state =            TX_SUSPENDED;
446                 }
447 
448 #ifdef TX_THREAD_ENABLE_PERFORMANCE_INFO
449 
450                 /* Increment the total number of thread resumptions.  */
451                 _tx_thread_performance_resume_count++;
452 
453                 /* Increment this thread's resume count.  */
454                 thread_ptr -> tx_thread_performance_resume_count++;
455 #endif
456             }
457         }
458     }
459 
460 #ifdef TX_THREAD_ENABLE_PERFORMANCE_INFO
461 
462     /* Is the execute pointer different?  */
463     if (_tx_thread_performance_execute_log[_tx_thread_performance__execute_log_index] != _tx_thread_execute_ptr)
464     {
465                      
466         /* Move to next entry.  */
467         _tx_thread_performance__execute_log_index++;
468             
469         /* Check for wrap condition.  */
470         if (_tx_thread_performance__execute_log_index >= TX_THREAD_EXECUTE_LOG_SIZE)
471         {
472           
473             /* Set the index to the beginning.  */
474             _tx_thread_performance__execute_log_index =  ((UINT) 0);
475         }
476             
477         /* Log the new execute pointer.  */
478         _tx_thread_performance_execute_log[_tx_thread_performance__execute_log_index] =  _tx_thread_execute_ptr;
479     }
480 #endif
481 
482 #ifdef TX_ENABLE_EVENT_TRACE
483 
484     /* Check that the event time stamp is unchanged.  A different
485        timestamp means that a later event wrote over the thread
486        resume event. In that case, do nothing here.  */
487     if (entry_ptr != TX_NULL)
488     {
489     
490         /* Is the timestamp the same?  */
491         if (time_stamp == entry_ptr -> tx_trace_buffer_entry_time_stamp)
492         {
493         
494             /* Timestamp is the same, set the "next thread pointer" to NULL. This can
495                be used by the trace analysis tool to show idle system conditions.  */
496 #ifdef TX_MISRA_ENABLE
497             entry_ptr -> tx_trace_buffer_entry_info_4 =  TX_POINTER_TO_ULONG_CONVERT(_tx_thread_execute_ptr);
498 #else
499             entry_ptr -> tx_trace_buffer_entry_information_field_4 =  TX_POINTER_TO_ULONG_CONVERT(_tx_thread_execute_ptr);
500 #endif
501         }
502     }
503 #endif
504 
505     /* Pickup thread pointer.  */
506     TX_THREAD_GET_CURRENT(current_thread)
507 
508     /* Restore interrupts.  */
509     TX_RESTORE
510 
511     /* Determine if a preemption condition is present.  */
512     if (current_thread != _tx_thread_execute_ptr)
513     {
514 
515 #ifdef TX_ENABLE_STACK_CHECKING
516 
517         /* Pickup the next execute pointer.  */
518         thread_ptr =  _tx_thread_execute_ptr;
519 
520         /* Check this thread's stack.  */
521         TX_THREAD_STACK_CHECK(thread_ptr)
522 #endif
523 
524         /* Now determine if preemption should take place. This is only possible if the current thread pointer is
525            not the same as the execute thread pointer AND the system state and preempt disable flags are clear.  */
526         TX_THREAD_SYSTEM_RETURN_CHECK(combined_flags)
527         if (combined_flags == ((ULONG) 0))
528         {
529 
530 #ifdef TX_THREAD_ENABLE_PERFORMANCE_INFO
531 
532             /* There is another thread ready to run and will be scheduled upon return.  */
533             _tx_thread_performance_non_idle_return_count++;
534 #endif
535 
536             /* Preemption is needed - return to the system!  */
537             _tx_thread_system_return();
538         }
539     }
540 }

5、线程恢复执行

5.1、线程挂起过程恢复其他线程流程

阻塞/挂起线程恢复执行是在_tx_thread_system_resume里面实现的,前面已经介绍过了,这里只介绍就绪线程恢复执行;

就绪线程不能执行那么肯定有高优先级线程在执行或者同优先级线程还没执行完(时间片没有用尽,还没轮到自己执行),时间片用尽前面介绍过,后面介绍线程退出时恢复线程的过程;

线程退出时,正常情况选择下一个高优先级线程执行即可,但是ThreadX启用了抢占,多了一个检查抢占的过程,就绪线程的优先级还需要跟之前被抢占线程的抢占阈值比较,以便能够恢复被抢占的启用了抢占的线程,启用了抢占的被抢占的动态优先级等于抢占阈值,按优先级并不能找到,因此要在_tx_thread_preempted_maps里面找有没有高优先级(抢占阈值高)的线程就绪;

ThreadX线程挂起一个线程的过程比较复杂,流程图大致如下所示:

ThreadX内核源码分析 - 优先级及抢占阈值抢占(arm)_第2张图片

5.2、线程挂起时恢复其他线程代码 

线程挂起代码如下:

083 VOID  _tx_thread_system_suspend(TX_THREAD *thread_ptr)
084 #ifndef TX_NOT_INTERRUPTABLE
085 {
086 
087 TX_INTERRUPT_SAVE_AREA
088  
089 UINT            priority;
090 UINT            base_priority;
091 ULONG           priority_map;
092 ULONG           priority_bit;
093 ULONG           combined_flags;
094 TX_THREAD       *ready_next;
095 TX_THREAD       *ready_previous;
096 TX_THREAD       *current_thread;
097 
098 #if TX_MAX_PRIORITIES > 32
099 UINT            map_index;
100 #endif
101 
102 #ifndef TX_NO_TIMER
103 ULONG           timeout;
104 #endif
105 
106 #ifdef TX_ENABLE_EVENT_TRACE
107 TX_TRACE_BUFFER_ENTRY       *entry_ptr;
108 ULONG                       time_stamp =  ((ULONG) 0);
109 #endif
110 
111     /* Pickup thread pointer.  */
112     TX_THREAD_GET_CURRENT(current_thread)
113 
114 #ifdef TX_ENABLE_STACK_CHECKING
115 
116     /* Check this thread's stack.  */
117     TX_THREAD_STACK_CHECK(thread_ptr)
118 #endif
119 
120     /* Lockout interrupts while the thread is being suspended.  */
121     TX_DISABLE
122 
123 #ifndef TX_NO_TIMER
124 
125     /* Is the current thread suspending?  */
126     if (thread_ptr == current_thread) // 挂起自己线程(可能是调用sleep或者等待信号量等导致的阻塞,可能需要超时唤醒)
127     {
128 
129         /* Pickup the wait option.  */
130         timeout =  thread_ptr -> tx_thread_timer.tx_timer_internal_remaining_ticks; // 获取超时时间,sleep或者等待信号量前会设置好tx_timer_internal_remaining_ticks
131 
132         /* Determine if an activation is needed.  */
133         if (timeout != TX_NO_WAIT) // TX_NO_WAIT表示不等待,不用启动定时器
134         {
135 
136             /* Make sure the suspension is not a wait-forever.  */
137             if (timeout != TX_WAIT_FOREVER) // TX_WAIT_FOREVER表示没有超时时间,信号量等只有等到了才返回
138             {
139             
140                 /* Activate the thread timer with the timeout value setup in the caller.  */
141                 _tx_timer_system_activate(&(thread_ptr -> tx_thread_timer)); // 激活超时定时器(挂载到超时定时器链表等)
142             }
143         }
144 
145         /* Yes, reset time slice for current thread.  */
146         _tx_timer_time_slice =  thread_ptr -> tx_thread_new_time_slice; // 重置当前线程的时间片(后面保存线程上下文的时候会把_tx_timer_time_slice保存到线程里面,下次唤醒后以新的时间片调度)
147     }
148 #endif
149     
150     /* Decrease the preempt disabled count.  */
151     _tx_thread_preempt_disable--;
152 
153 #ifdef TX_THREAD_ENABLE_PERFORMANCE_INFO
154 
155     /* Increment the thread's suspend count.  */
156     thread_ptr -> tx_thread_performance_suspend_count++;
157 
158     /* Increment the total number of thread suspensions.  */
159     _tx_thread_performance_suspend_count++;
160 #endif
161 
162     /* Check to make sure the thread suspending flag is still set.  If not, it
163        has already been resumed.  */
164     if (thread_ptr -> tx_thread_suspending == TX_TRUE) // 挂起过程没被其他线程或者中断服务程序唤醒
165     {
166 
167         /* Thread state change.  */
168         TX_THREAD_STATE_CHANGE(thread_ptr, thread_ptr -> tx_thread_state)
169 
170         /* Log the thread status change.  */
171         TX_EL_THREAD_STATUS_CHANGE_INSERT(thread_ptr, thread_ptr -> tx_thread_state)
172 
173 #ifdef TX_ENABLE_EVENT_TRACE
174 
175         /* If trace is enabled, save the current event pointer.  */
176         entry_ptr =  _tx_trace_buffer_current_ptr;
177 #endif
178 
179         /* Log the thread status change.  */
180         TX_TRACE_IN_LINE_INSERT(TX_TRACE_THREAD_SUSPEND, thread_ptr, thread_ptr -> tx_thread_state, TX_POINTER_TO_ULONG_CONVERT(&priority), TX_POINTER_TO_ULONG_CONVERT(_tx_thread_execute_ptr), TX_TRACE_INTERNAL_EVENTS)
181 
182 #ifdef TX_ENABLE_EVENT_TRACE
183 
184         /* Save the time stamp for later comparison to verify that
185            the event hasn't been overwritten by the time we have 
186            computed the next thread to execute.  */
187         if (entry_ptr != TX_NULL)
188         {
189 
190             /* Save time stamp.  */
191             time_stamp =  entry_ptr -> tx_trace_buffer_entry_time_stamp;
192         }
193 #endif
194 
195         /* Actually suspend this thread.  But first, clear the suspending flag.  */
196         thread_ptr -> tx_thread_suspending =  TX_FALSE; // tx_thread_suspending设置为TX_FALSE,这里已经关闭了中断,这个过程不会再被中断
197 
198         /* Pickup priority of thread.  */
199         priority =  thread_ptr -> tx_thread_priority; // 被挂起线程的优先级
200 
201         /* Pickup the next ready thread pointer.  */
202         ready_next =      thread_ptr -> tx_thread_ready_next;
203 
204         /* Determine if there are other threads at this priority that are
205            ready.  */
206         if (ready_next != thread_ptr) // 被挂起线程的就绪线程链表有其他线程
207         {
208 
209             /* Yes, there are other threads at this priority ready.  */
210 
211             /* Pickup the previous ready thread pointer.  */
212             ready_previous =  thread_ptr -> tx_thread_ready_previous;
213 
214             /* Just remove this thread from the priority list.  */ // 接下来几行代码将挂起线程从就绪线程链表删除
215             ready_next -> tx_thread_ready_previous =    ready_previous;
216             ready_previous -> tx_thread_ready_next =    ready_next;
217 
218             /* Determine if this is the head of the priority list.  */
219             if (_tx_thread_priority_list[priority] == thread_ptr) // 检查被挂起线程是不是就绪线程链表的表头线程(是的话,需要更新就绪线程链表表头)
220             {
221 
222                 /* Update the head pointer of this priority list.  */
223                 _tx_thread_priority_list[priority] =  ready_next; // 更新就绪线程链表表头
224 
225 #ifndef TX_DISABLE_PREEMPTION_THRESHOLD
226 
227 #if TX_MAX_PRIORITIES > 32
228 
229                 /* Calculate the index into the bit map array.  */
230                 map_index =  priority/((UINT) 32);
231 #endif
232 
233                 /* Check for a thread preempted that had preemption threshold set.  */
234                 if (_tx_thread_preempted_maps[MAP_INDEX] != ((ULONG) 0)) // 前面有介绍,线程被执行的时候,线程仍在就绪线程链表表头,如果_tx_thread_preempted_maps被标记的话,需要清除该标记,因为现在的就绪线程链表的表头线程还没执行,不存在被抢占情况
235                 {
236 
237                     /* Ensure that this thread's priority is clear in the preempt map.  */
238                     TX_MOD32_BIT_SET(priority, priority_bit)
239                     _tx_thread_preempted_maps[MAP_INDEX] =  _tx_thread_preempted_maps[MAP_INDEX] & (~(priority_bit)); // 清除抢占标记
240 
241 #if TX_MAX_PRIORITIES > 32
242 
243                     /* Determine if there are any other bits set in this preempt map.  */
244                     if (_tx_thread_preempted_maps[MAP_INDEX] == ((ULONG) 0))
245                     {
246 
247                         /* No, clear the active bit to signify this preempt map has nothing set.  */
248                         TX_DIV32_BIT_SET(priority, priority_bit)
249                         _tx_thread_preempted_map_active =  _tx_thread_preempted_map_active & (~(priority_bit));
250                     }
251 #endif
252                 }
253 #endif
254             }
255         }
256         else // 被挂起线程的下一个就绪线程指向自己(就绪线程链表里面没有其他线程了)
257         {
258 
259             /* This is the only thread at this priority ready to run.  Set the head 
260                pointer to NULL.  */
261             _tx_thread_priority_list[priority] =    TX_NULL; // 将被挂起线程的就绪线程链表清空即可
262 
263 #if TX_MAX_PRIORITIES > 32
264 
265             /* Calculate the index into the bit map array.  */
266             map_index =  priority/((UINT) 32);
267 #endif
268 
269             /* Clear this priority bit in the ready priority bit map.  */
270             TX_MOD32_BIT_SET(priority, priority_bit)
271             _tx_thread_priority_maps[MAP_INDEX] =  _tx_thread_priority_maps[MAP_INDEX] & (~(priority_bit)); // 该优先级已经没有其他就绪线程了,清除对应的位
272 
273 #if TX_MAX_PRIORITIES > 32
274 
275             /* Determine if there are any other bits set in this priority map.  */
276             if (_tx_thread_priority_maps[MAP_INDEX] == ((ULONG) 0))
277             {
278 
279                 /* No, clear the active bit to signify this priority map has nothing set.  */
280                 TX_DIV32_BIT_SET(priority, priority_bit)
281                 _tx_thread_priority_map_active =  _tx_thread_priority_map_active & (~(priority_bit));
282             }
283 #endif
284 
285 #ifndef TX_DISABLE_PREEMPTION_THRESHOLD
286 
287             /* Check for a thread preempted that had preemption-threshold set.  */
288             if (_tx_thread_preempted_maps[MAP_INDEX] != ((ULONG) 0)) // _tx_thread_preempted_maps抢占标志位有被设置(不一定有标记被挂起的线程)
289             {
290 
291                 /* Ensure that this thread's priority is clear in the preempt map.  */
292                 TX_MOD32_BIT_SET(priority, priority_bit)
293                 _tx_thread_preempted_maps[MAP_INDEX] =  _tx_thread_preempted_maps[MAP_INDEX] & (~(priority_bit)); // 清除被挂起线程优先级的抢占标记(被挂起线程有没有标记都要清除;有的话,线程已经挂起,没必要再调度)
294 
295 #if TX_MAX_PRIORITIES > 32
296 
297                 /* Determine if there are any other bits set in this preempt map.  */
298                 if (_tx_thread_preempted_maps[MAP_INDEX] == ((ULONG) 0))
299                 {
300 
301                     /* No, clear the active bit to signify this preempted map has nothing set.  */
302                     TX_DIV32_BIT_SET(priority, priority_bit)
303                     _tx_thread_preempted_map_active =  _tx_thread_preempted_map_active & (~(priority_bit));
304                 }
305 #endif
306             }
307 #endif
308 
309 #if TX_MAX_PRIORITIES > 32
310 
311             /* Calculate the index to find the next highest priority thread ready for execution.  */
312             priority_map =    _tx_thread_priority_map_active;
313 
314             /* Determine if there is anything.   */
315             if (priority_map != ((ULONG) 0))
316             {
317 
318                 /* Calculate the lowest bit set in the priority map. */
319                 TX_LOWEST_SET_BIT_CALCULATE(priority_map, map_index)
320             }
321 
322             /* Calculate the base priority as well.  */
323             base_priority =  map_index * ((UINT) 32);
324 #else
325 
326             /* Setup the base priority to zero.  */
327             base_priority =   ((UINT) 0);
328 #endif
329 
330             /* Setup working variable for the priority map.  */
331             priority_map =    _tx_thread_priority_maps[MAP_INDEX]; // 检查是否有就绪线程(_tx_thread_priority_maps对应的位为1表示对应优先有就绪线程)
332 
333             /* Make a quick check for no other threads ready for execution.  */
334             if (priority_map == ((ULONG) 0)) // 没有就绪线程
335             {
336 
337                 /* Nothing else is ready.  Set highest priority and execute thread
338                    accordingly.  */
339                 _tx_thread_highest_priority =  ((UINT) TX_MAX_PRIORITIES); //最高就绪线程优先级TX_MAX_PRIORITIES
340                 _tx_thread_execute_ptr =       TX_NULL; // 需要调度的线程_tx_thread_execute_ptr设置为空,没有线程需要调度
341 
342 #ifndef TX_MISRA_ENABLE
343 
344 #ifdef TX_ENABLE_EVENT_TRACE
345 
346                 /* Check that the event time stamp is unchanged.  A different
347                    timestamp means that a later event wrote over the thread
348                    suspend event. In that case, do nothing here.  */
349                 if (entry_ptr != TX_NULL)
350                 {
351             
352                     /* Is the timestamp the same?  */
353                     if (time_stamp == entry_ptr -> tx_trace_buffer_entry_time_stamp)
354                     {
355     
356                         /* Timestamp is the same, set the "next thread pointer" to the new value of the
357                            next thread to execute. This can be used by the trace analysis tool to keep 
358                            track of next thread execution.  */
359                         entry_ptr -> tx_trace_buffer_entry_information_field_4 =  0;
360                     }
361                 }
362 #endif
363 
364                 /* Restore interrupts.  */
365                 TX_RESTORE
366 
367                 /* Determine if preemption should take place. This is only possible if the current thread pointer is
368                    not the same as the execute thread pointer AND the system state and preempt disable flags are clear.  */
369                 TX_THREAD_SYSTEM_RETURN_CHECK(combined_flags) // _tx_thread_preempt_disable等
370                 if (combined_flags == ((ULONG) 0)) // 检查是否禁止抢占是否在内核初始化过程,不是的话返回系统(没有就绪线程的话需要返回系统等待就绪线程)
371                 {
372 
373 #ifdef TX_THREAD_ENABLE_PERFORMANCE_INFO
374 
375                     /* Yes, increment the return to idle return count.  */
376                     _tx_thread_performance_idle_return_count++;
377 #endif
378 
379                     /* Preemption is needed - return to the system!  */
380                     _tx_thread_system_return(); // 返回系统等待就绪线程
381                 }
382 
383                 /* Return to caller.  */
384                 return;
385 #endif
386             }
387             else // 有就绪线程
388             {
389             
390                 /* Other threads at different priority levels are ready to run.  */
391             
392                 /* Calculate the lowest bit set in the priority map. */
393                 TX_LOWEST_SET_BIT_CALCULATE(priority_map, priority_bit)
394 
395                 /* Setup the next highest priority variable.  */
396                 _tx_thread_highest_priority =  base_priority + ((UINT) priority_bit); // 更新就绪线程最高优先级(被挂起线程优先级所在就绪线程链表没有其他线程)
397             }
398         }
399 
400         /* Determine if the suspending thread is the thread designated to execute.  */
401         if (thread_ptr == _tx_thread_execute_ptr) // 挂起正在执行的线程(没有其他就绪线程的情况,前面已经处理过了,这里应该就是有其他就绪线程的情况,需要调度别的就绪线程;挂起不在执行的线程不会导致线程调度)
402         {
403 
404             /* Pickup the highest priority thread to execute.  */
405             _tx_thread_execute_ptr =  _tx_thread_priority_list[_tx_thread_highest_priority]; // _tx_thread_execute_ptr指向最高优先级就绪线程
406 
407 #ifndef TX_DISABLE_PREEMPTION_THRESHOLD
408 
409             /* Determine if a previous thread with preemption-threshold was preempted.  */
410 #if TX_MAX_PRIORITIES > 32
411             if (_tx_thread_preempted_map_active != ((ULONG) 0))
412 #else
413             if (_tx_thread_preempted_maps[MAP_INDEX] != ((ULONG) 0)) // 检查是否有启用抢占的线程被抢占
414 #endif
415             {
416 
417                 /* Yes, there was a thread preempted when it was using preemption-threshold.  */
418 
419                 /* Disable preemption.  */
420                 _tx_thread_preempt_disable++; // 禁止抢占(后面开中断让中断得到及时处理,禁止抢占避免当前过程被其他线程中断)
421 
422                 /* Restore interrupts.  */
423                 TX_RESTORE
424 
425                 /* Interrupts are enabled briefly here to keep the interrupt
426                    lockout time deterministic.  */
427 
428                 /* Disable interrupts again.  */
429                 TX_DISABLE
430 
431                 /* Decrement the preemption disable variable.  */
432                 _tx_thread_preempt_disable--;
433 
434                 /* Calculate the thread with preemption threshold set that
435                    was interrupted by a thread above the preemption level.  */
436 
437 #if TX_MAX_PRIORITIES > 32
438 
439                 /* Calculate the index to find the next highest priority thread ready for execution.  */
440                 priority_map =    _tx_thread_preempted_map_active;
441 
442                 /* Calculate the lowest bit set in the priority map. */
443                 TX_LOWEST_SET_BIT_CALCULATE(priority_map, map_index)
444 
445                 /* Calculate the base priority as well.  */
446                 base_priority =  map_index * ((UINT) 32);
447 #else
448 
449                 /* Setup the base priority to zero.  */
450                 base_priority =   ((UINT) 0);
451 #endif
452 
453                 /* Setup temporary preempted map.  */
454                 priority_map =  _tx_thread_preempted_maps[MAP_INDEX];
455 
456                 /* Calculate the lowest bit set in the priority map. */
457                 TX_LOWEST_SET_BIT_CALCULATE(priority_map, priority_bit) // 获取最高优先级的抢占线程的标记位(前面讲过了,_tx_thread_preempted_maps里面的高优先级线程的优先级高于低优先级线程的抢占阈值,要调度的话也只可能是_tx_thread_preempted_maps里面高优先级线程)
458 
459                 /* Setup the highest priority preempted thread.  */
460                 priority =  base_priority + ((UINT) priority_bit); // 获取_tx_thread_preempted_maps标记的最高优先级线程的优先级
461 
462                 /* Determine if the next highest priority thread is above the highest priority threshold value.  */
463                 if (_tx_thread_highest_priority >= (_tx_thread_priority_list[priority] -> tx_thread_preempt_threshold)) // 最高优先级就绪线程的优先级不高于_tx_thread_preempted_maps被抢占线程的抢占阈值,_tx_thread_preempted_maps里面的高优先级线程抢占下一个就绪的最高优先级线程
464                 {
465 
466                     /* Thread not allowed to execute until earlier preempted thread finishes or lowers its 
467                        preemption-threshold.  */
468                     _tx_thread_execute_ptr =  _tx_thread_priority_list[priority]; // 获取_tx_thread_preempted_maps标记的被抢占的线程(被抢占的线程还在就绪线程链表_tx_thread_priority_list的表头)
469 
470                     /* Clear the corresponding bit in the preempted map, since the preemption has been restored.  */
471                     TX_MOD32_BIT_SET(priority, priority_bit)
472                     _tx_thread_preempted_maps[MAP_INDEX] =  _tx_thread_preempted_maps[MAP_INDEX] & (~(priority_bit)); // 清除_tx_thread_preempted_maps里面的抢占标记
473 
474 #if TX_MAX_PRIORITIES > 32
475 
476                     /* Determine if there are any other bits set in this preempt map.  */
477                     if (_tx_thread_preempted_maps[MAP_INDEX] == ((ULONG) 0))
478                     {
479     
480                         /* No, clear the active bit to signify this preempt map has nothing set.  */
481                         TX_DIV32_BIT_SET(priority, priority_bit)
482                         _tx_thread_preempted_map_active =  _tx_thread_preempted_map_active & (~(priority_bit));
483                     }
484 #endif
485                 }
486             }
487 #endif
488 
489 #ifndef TX_MISRA_ENABLE
490 
491 #ifdef TX_THREAD_ENABLE_PERFORMANCE_INFO
492 
493             /* Is the execute pointer different?  */
494             if (_tx_thread_performance_execute_log[_tx_thread_performance__execute_log_index] != _tx_thread_execute_ptr)
495             {
496                      
497                 /* Move to next entry.  */
498                 _tx_thread_performance__execute_log_index++;
499             
500                 /* Check for wrap condition.  */
501                 if (_tx_thread_performance__execute_log_index >= TX_THREAD_EXECUTE_LOG_SIZE)
502                 {
503           
504                     /* Set the index to the beginning.  */
505                     _tx_thread_performance__execute_log_index =  ((UINT) 0);
506                 }
507             
508                 /* Log the new execute pointer.  */
509                 _tx_thread_performance_execute_log[_tx_thread_performance__execute_log_index] =  _tx_thread_execute_ptr;
510             }
511 #endif
512 
513 #ifdef TX_ENABLE_EVENT_TRACE
514 
515             /* Check that the event time stamp is unchanged.  A different
516                timestamp means that a later event wrote over the thread
517                suspend event. In that case, do nothing here.  */
518             if (entry_ptr != TX_NULL)
519             {
520             
521                 /* Is the timestamp the same?  */
522                 if (time_stamp == entry_ptr -> tx_trace_buffer_entry_time_stamp)
523                 {
524     
525                     /* Timestamp is the same, set the "next thread pointer" to the new value of the
526                        next thread to execute. This can be used by the trace analysis tool to keep 
527                        track of next thread execution.  */
528                     entry_ptr -> tx_trace_buffer_entry_information_field_4 =  TX_POINTER_TO_ULONG_CONVERT(_tx_thread_execute_ptr);
529                 }
530             }
531 #endif
532 
533             /* Restore interrupts.  */
534             TX_RESTORE
535 
536             /* Determine if preemption should take place. This is only possible if the current thread pointer is
537                not the same as the execute thread pointer AND the system state and preempt disable flags are clear.  */
538             TX_THREAD_SYSTEM_RETURN_CHECK(combined_flags)
539             if (combined_flags == ((ULONG) 0)) // 与之前一样,检查是返回系统调度线程还是返回
540             {
541 
542 #ifdef TX_THREAD_ENABLE_PERFORMANCE_INFO
543 
544                 /* No, there is another thread ready to run and will be scheduled upon return.  */
545                 _tx_thread_performance_non_idle_return_count++;
546 #endif
547 
548                 /* Preemption is needed - return to the system!  */
549                 _tx_thread_system_return();
550             }
551 
552             /* Return to caller.  */
553             return; // 返回
554 #endif
555         }
556 
557 #ifdef TX_THREAD_ENABLE_PERFORMANCE_INFO
558 
559         /* Is the execute pointer different?  */
560         if (_tx_thread_performance_execute_log[_tx_thread_performance__execute_log_index] != _tx_thread_execute_ptr)
561         {
562                      
563             /* Move to next entry.  */
564             _tx_thread_performance__execute_log_index++;
565             
566             /* Check for wrap condition.  */
567             if (_tx_thread_performance__execute_log_index >= TX_THREAD_EXECUTE_LOG_SIZE)
568             {
569           
570                 /* Set the index to the beginning.  */
571                 _tx_thread_performance__execute_log_index =  ((UINT) 0);
572             }
573             
574             /* Log the new execute pointer.  */
575             _tx_thread_performance_execute_log[_tx_thread_performance__execute_log_index] =  _tx_thread_execute_ptr;
576         }
577 #endif
578 
579 #ifdef TX_ENABLE_EVENT_TRACE
580 
581          /* Check that the event time stamp is unchanged.  A different
582             timestamp means that a later event wrote over the thread
583             suspend event. In that case, do nothing here.  */
584          if (entry_ptr != TX_NULL)
585          {
586             
587             /* Is the timestamp the same?  */
588             if (time_stamp == entry_ptr -> tx_trace_buffer_entry_time_stamp)
589             {
590     
591                 /* Timestamp is the same, set the "next thread pointer" to the new value of the
592                    next thread to execute. This can be used by the trace analysis tool to keep 
593                    track of next thread execution.  */
594 #ifdef TX_MISRA_ENABLE
595                 entry_ptr -> tx_trace_buffer_entry_info_4 =  TX_POINTER_TO_ULONG_CONVERT(_tx_thread_execute_ptr);
596 #else
597                 entry_ptr -> tx_trace_buffer_entry_information_field_4 =  TX_POINTER_TO_ULONG_CONVERT(_tx_thread_execute_ptr);
598 #endif
599             }
600         }
601 #endif
602     }
603 
604     /* Restore interrupts.  */
605     TX_RESTORE
606 
607     /* Determine if a preemption condition is present.  */
608     if (current_thread != _tx_thread_execute_ptr)
609     {
610 
611 #ifdef TX_ENABLE_STACK_CHECKING
612 
613         /* Pickup the next execute pointer.  */
614         thread_ptr =  _tx_thread_execute_ptr;
615 
616         /* Check this thread's stack.  */
617         TX_THREAD_STACK_CHECK(thread_ptr)
618 #endif
619 
620         /* Determine if preemption should take place. This is only possible if the current thread pointer is
621            not the same as the execute thread pointer AND the system state and preempt disable flags are clear.  */
622         TX_THREAD_SYSTEM_RETURN_CHECK(combined_flags)
623         if (combined_flags == ((ULONG) 0))
624         {
625 
626 #ifdef TX_THREAD_ENABLE_PERFORMANCE_INFO
627 
628             /* Determine if an idle system return is present.  */
629             if (_tx_thread_execute_ptr == TX_NULL)
630             {
631 
632                 /* Yes, increment the return to idle return count.  */
633                 _tx_thread_performance_idle_return_count++;
634             }
635             else
636             {
637 
638                 /* No, there is another thread ready to run and will be scheduled upon return.  */
639                 _tx_thread_performance_non_idle_return_count++;
640             }
641 #endif
642 
643             /* Preemption is needed - return to the system!  */
644             _tx_thread_system_return();
645         }
646     }
647 
648     /* Return to caller.  */
649     return;
650 }

你可能感兴趣的:(ThreadX,arm,嵌入式硬件,threadx,线程调度,抢占)