优先级越高值越低,同优先级线程按先进先出加入就绪线程链表,正在执行的线程始终在就绪线程链表的表头(线程调度时不会从就绪线程链表删除)。
线程的抢占阈值大于线程的优先级时,表示线程启用了抢占,也就是该线程可以抢占同优先级线程以及优先级比该线程抢占阈值低的线程;内核保证抢占阈值不会小于线程优先级,否则抢占阈值是错误的,因此只要抢占阈值不等与线程优先级就表示抢占阈值高于线程优先级;
没有启用抢占的线程按优先级及时间片调度,抢占阈值只对启用了抢占的线程正在执行时以及恢复执行时起作用:
也可以以另外一种方式理解,可能更容易理解,线程被执行时,该线程的优先级就等于线程的抢占阈值threshold,该线程并没有加到threshold对应就绪线程链表,该线程被抢占出去的时候,下次并不能在threshold对应优先级链表找到,因此需要通过_tx_thread_preempted_maps找到threshold对应优先级线程,可以理解_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低优先级线程的抢占阈值。
之前介绍时间片的时候介绍过启用抢占的线程时间片用尽时不会调度同优先级的下一个就绪线程,在此略过;内核只有在线程唤醒时,才可能导致当前执行线程的优先级不是最高的情况,因此,抢占只可能发生在线程唤醒时。
主要实现代码在_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 }
阻塞/挂起线程恢复执行是在_tx_thread_system_resume里面实现的,前面已经介绍过了,这里只介绍就绪线程恢复执行;
就绪线程不能执行那么肯定有高优先级线程在执行或者同优先级线程还没执行完(时间片没有用尽,还没轮到自己执行),时间片用尽前面介绍过,后面介绍线程退出时恢复线程的过程;
线程退出时,正常情况选择下一个高优先级线程执行即可,但是ThreadX启用了抢占,多了一个检查抢占的过程,就绪线程的优先级还需要跟之前被抢占线程的抢占阈值比较,以便能够恢复被抢占的启用了抢占的线程,启用了抢占的被抢占的动态优先级等于抢占阈值,按优先级并不能找到,因此要在_tx_thread_preempted_maps里面找有没有高优先级(抢占阈值高)的线程就绪;
ThreadX线程挂起一个线程的过程比较复杂,流程图大致如下所示:
线程挂起代码如下:
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 }