1 /***************************************************************************
2  * Copyright (c) 2024 Microsoft Corporation
3  *
4  * This program and the accompanying materials are made available under the
5  * terms of the MIT License which is available at
6  * https://opensource.org/licenses/MIT.
7  *
8  * SPDX-License-Identifier: MIT
9  **************************************************************************/
10 
11 
12 /**************************************************************************/
13 /**************************************************************************/
14 /**                                                                       */
15 /** ThreadX Component                                                     */
16 /**                                                                       */
17 /**   Thread                                                              */
18 /**                                                                       */
19 /**************************************************************************/
20 /**************************************************************************/
21 #define TX_SOURCE_CODE
22 
23 /* Include necessary system files.  */
24 #include "tx_api.h"
25 #include "tx_trace.h"
26 #include "tx_thread.h"
27 #ifdef TX_INLINE_THREAD_RESUME_SUSPEND
28 #ifndef TX_NO_TIMER
29 #include "tx_timer.h"
30 #endif
31 #endif
32 /**************************************************************************/
33 /*                                                                        */
34 /*  FUNCTION                                               RELEASE        */
35 /*                                                                        */
36 /*    _tx_thread_suspend                                  PORTABLE C      */
37 /*                                                           6.1.1        */
38 /*  AUTHOR                                                                */
39 /*                                                                        */
40 /*    William E. Lamie, Microsoft Corporation                             */
41 /*                                                                        */
42 /*  DESCRIPTION                                                           */
43 /*                                                                        */
44 /*    This function handles application suspend requests.  If the suspend */
45 /*    requires actual processing, this function calls the actual suspend  */
46 /*    thread routine.                                                     */
47 /*                                                                        */
48 /*  INPUT                                                                 */
49 /*                                                                        */
50 /*    thread_ptr                            Pointer to thread to suspend  */
51 /*                                                                        */
52 /*  OUTPUT                                                                */
53 /*                                                                        */
54 /*    status                                Return completion status      */
55 /*                                                                        */
56 /*  CALLS                                                                 */
57 /*                                                                        */
58 /*    _tx_thread_system_suspend         Actual thread suspension          */
59 /*    _tx_thread_system_ni_suspend      Non-interruptable suspend thread  */
60 /*                                                                        */
61 /*  CALLED BY                                                             */
62 /*                                                                        */
63 /*    Application code                                                    */
64 /*                                                                        */
65 /*  RELEASE HISTORY                                                       */
66 /*                                                                        */
67 /*    DATE              NAME                      DESCRIPTION             */
68 /*                                                                        */
69 /*  05-19-2020     William E. Lamie         Initial Version 6.0           */
70 /*  09-30-2020     Yuxin Zhou               Modified comment(s),          */
71 /*                                            resulting in version 6.1    */
72 /*  10-16-2020     Yuxin Zhou               Modified comment(s), and      */
73 /*                                            added type cast to address  */
74 /*                                            a MISRA compliance issue,   */
75 /*                                            resulting in version 6.1.1  */
76 /*                                                                        */
77 /**************************************************************************/
_tx_thread_suspend(TX_THREAD * thread_ptr)78 UINT  _tx_thread_suspend(TX_THREAD *thread_ptr)
79 {
80 
81 TX_INTERRUPT_SAVE_AREA
82 
83 TX_THREAD  *current_thread;
84 UINT        status;
85 
86 
87 #ifndef TX_INLINE_THREAD_RESUME_SUSPEND
88 
89     /* Lockout interrupts while the thread is being suspended.  */
90     TX_DISABLE
91 
92     /* Pickup thread pointer.  */
93     TX_THREAD_GET_CURRENT(current_thread)
94 
95     /* If trace is enabled, insert this event into the trace buffer.  */
96     TX_TRACE_IN_LINE_INSERT(TX_TRACE_THREAD_SUSPEND_API, thread_ptr, thread_ptr -> tx_thread_state, TX_POINTER_TO_ULONG_CONVERT(&status), 0, TX_TRACE_THREAD_EVENTS)
97 
98     /* Log this kernel call.  */
99     TX_EL_THREAD_SUSPEND_INSERT
100 
101     /* Check the specified thread's current status.  */
102     if (thread_ptr -> tx_thread_state == TX_READY)
103     {
104 
105         /* Initialize status to success.  */
106         status =  TX_SUCCESS;
107 
108         /* Determine if we are in a thread context.  */
109         if (TX_THREAD_GET_SYSTEM_STATE() == ((ULONG) 0))
110         {
111 
112             /* Yes, we are in a thread context.  */
113 
114             /* Determine if the current thread is also the suspending thread.  */
115             if (current_thread == thread_ptr)
116             {
117 
118                 /* Now determine if the preempt disable flag is non-zero.  */
119                 if (_tx_thread_preempt_disable != ((UINT) 0))
120                 {
121 
122                     /* Current thread cannot suspend when the preempt disable flag is non-zero,
123                        return an error.  */
124                     status =  TX_SUSPEND_ERROR;
125                 }
126             }
127         }
128 
129         /* Determine if the status is still successful.  */
130         if (status == TX_SUCCESS)
131         {
132 
133             /* Set the state to suspended.  */
134             thread_ptr -> tx_thread_state =    TX_SUSPENDED;
135 
136 #ifdef TX_NOT_INTERRUPTABLE
137 
138             /* Call actual non-interruptable thread suspension routine.  */
139             _tx_thread_system_ni_suspend(thread_ptr, ((ULONG) 0));
140 
141             /* Restore interrupts.  */
142             TX_RESTORE
143 #else
144 
145             /* Set the suspending flag. */
146             thread_ptr -> tx_thread_suspending =  TX_TRUE;
147 
148             /* Setup for no timeout period.  */
149             thread_ptr -> tx_thread_timer.tx_timer_internal_remaining_ticks =  ((ULONG) 0);
150 
151             /* Temporarily disable preemption.  */
152             _tx_thread_preempt_disable++;
153 
154             /* Restore interrupts.  */
155             TX_RESTORE
156 
157             /* Call actual thread suspension routine.  */
158             _tx_thread_system_suspend(thread_ptr);
159 #endif
160 
161 #ifdef TX_MISRA_ENABLE
162 
163             /* Disable interrupts.  */
164             TX_DISABLE
165 
166             /* Return success.  */
167             status =  TX_SUCCESS;
168 #else
169 
170             /* If MISRA is not enabled, return directly.  */
171             return(TX_SUCCESS);
172 #endif
173         }
174     }
175     else if (thread_ptr -> tx_thread_state == TX_TERMINATED)
176     {
177 
178         /* Thread is terminated.  */
179         status =  TX_SUSPEND_ERROR;
180     }
181     else if (thread_ptr -> tx_thread_state == TX_COMPLETED)
182     {
183 
184         /* Thread is completed.  */
185         status =  TX_SUSPEND_ERROR;
186     }
187     else if (thread_ptr -> tx_thread_state == TX_SUSPENDED)
188     {
189 
190         /* Already suspended, just set status to success.  */
191         status =  TX_SUCCESS;
192     }
193     else
194     {
195 
196         /* Just set the delayed suspension flag.  */
197         thread_ptr -> tx_thread_delayed_suspend =  TX_TRUE;
198 
199         /* Set status to success.  */
200         status =  TX_SUCCESS;
201     }
202 
203     /* Restore interrupts.  */
204     TX_RESTORE
205 
206     /* Always return success, since this function does not perform error
207        checking.  */
208     return(status);
209 
210 #else
211 
212     /* In-line thread suspension processing follows, which is effectively just taking the
213        logic in tx_thread_system_suspend.c and placing it here!  */
214 
215 UINT            priority;
216 UINT            base_priority;
217 ULONG           priority_map;
218 ULONG           priority_bit;
219 ULONG           combined_flags;
220 TX_THREAD       *ready_next;
221 TX_THREAD       *ready_previous;
222 
223 #if TX_MAX_PRIORITIES > 32
224 UINT            map_index;
225 #endif
226 
227 #ifdef TX_ENABLE_EVENT_TRACE
228 TX_TRACE_BUFFER_ENTRY       *entry_ptr;
229 ULONG                       time_stamp =  ((ULONG) 0);
230 #endif
231 
232 
233     /* Pickup thread pointer.  */
234     TX_THREAD_GET_CURRENT(current_thread)
235 
236 #ifdef TX_ENABLE_STACK_CHECKING
237 
238     /* Check this thread's stack.  */
239     TX_THREAD_STACK_CHECK(thread_ptr)
240 #endif
241 
242     /* Lockout interrupts while the thread is being suspended.  */
243     TX_DISABLE
244 
245 #ifndef TX_NO_TIMER
246 
247     /* Determine if this is the current thread.  */
248     if (thread_ptr == current_thread)
249     {
250 
251         /* Yes, current thread is suspending - reset time slice for current thread.  */
252         _tx_timer_time_slice =  thread_ptr -> tx_thread_new_time_slice;
253     }
254 #endif
255 
256     /* If trace is enabled, insert this event into the trace buffer.  */
257     TX_TRACE_IN_LINE_INSERT(TX_TRACE_THREAD_SUSPEND_API, thread_ptr, thread_ptr -> tx_thread_state, TX_POINTER_TO_ULONG_CONVERT(&status), 0, TX_TRACE_THREAD_EVENTS)
258 
259     /* Log this kernel call.  */
260     TX_EL_THREAD_SUSPEND_INSERT
261 
262     /* Check the specified thread's current status.  */
263     if (thread_ptr -> tx_thread_state == TX_READY)
264     {
265 
266         /* Initialize status to success.  */
267         status =  TX_SUCCESS;
268 
269         /* Determine if we are in a thread context.  */
270         if (TX_THREAD_GET_SYSTEM_STATE() == ((ULONG) 0))
271         {
272 
273             /* Yes, we are in a thread context.  */
274 
275             /* Determine if the current thread is also the suspending thread.  */
276             if (current_thread == thread_ptr)
277             {
278 
279                 /* Now determine if the preempt disable flag is non-zero.  */
280                 if (_tx_thread_preempt_disable != ((UINT) 0))
281                 {
282 
283                     /* Current thread cannot suspend when the preempt disable flag is non-zero,
284                        return an error.  */
285                     status =  TX_SUSPEND_ERROR;
286                 }
287             }
288         }
289 
290         /* Determine if the status is still successful.  */
291         if (status == TX_SUCCESS)
292         {
293 
294 #ifdef TX_THREAD_ENABLE_PERFORMANCE_INFO
295 
296             /* Increment the thread's suspend count.  */
297             thread_ptr -> tx_thread_performance_suspend_count++;
298 
299             /* Increment the total number of thread suspensions.  */
300             _tx_thread_performance_suspend_count++;
301 #endif
302 
303             /* Set the state to suspended.  */
304             thread_ptr -> tx_thread_state =    TX_SUSPENDED;
305 
306             /* Thread state change.  */
307             TX_THREAD_STATE_CHANGE(thread_ptr, TX_SUSPENDED)
308 
309             /* Log the thread status change.  */
310             TX_EL_THREAD_STATUS_CHANGE_INSERT(thread_ptr, thread_ptr -> tx_thread_state)
311 
312 #ifdef TX_ENABLE_EVENT_TRACE
313 
314             /* If trace is enabled, save the current event pointer.  */
315             entry_ptr =  _tx_trace_buffer_current_ptr;
316 #endif
317 
318             /* Log the thread status change.  */
319             TX_TRACE_IN_LINE_INSERT(TX_TRACE_THREAD_SUSPEND, thread_ptr, ((ULONG) thread_ptr -> tx_thread_state), TX_POINTER_TO_ULONG_CONVERT(&priority), TX_POINTER_TO_ULONG_CONVERT(_tx_thread_execute_ptr), TX_TRACE_INTERNAL_EVENTS)
320 
321 #ifdef TX_ENABLE_EVENT_TRACE
322 
323             /* Save the time stamp for later comparison to verify that
324                the event hasn't been overwritten by the time we have
325                computed the next thread to execute.  */
326             if (entry_ptr != TX_NULL)
327             {
328 
329                 /* Save time stamp.  */
330                 time_stamp =  entry_ptr -> tx_trace_buffer_entry_time_stamp;
331             }
332 #endif
333 
334             /* Pickup priority of thread.  */
335             priority =  thread_ptr -> tx_thread_priority;
336 
337             /* Pickup the previous and next ready thread pointers.  */
338             ready_next =      thread_ptr -> tx_thread_ready_next;
339             ready_previous =  thread_ptr -> tx_thread_ready_previous;
340 
341             /* Determine if there are other threads at this priority that are
342                ready.  */
343             if (ready_next != thread_ptr)
344             {
345 
346                 /* Yes, there are other threads at this priority ready.  */
347 
348                 /* Just remove this thread from the priority list.  */
349                 ready_next -> tx_thread_ready_previous =    ready_previous;
350                 ready_previous -> tx_thread_ready_next =    ready_next;
351 
352                 /* Determine if this is the head of the priority list.  */
353                 if (_tx_thread_priority_list[priority] == thread_ptr)
354                 {
355 
356                     /* Update the head pointer of this priority list.  */
357                     _tx_thread_priority_list[priority] =  ready_next;
358 
359 #ifndef TX_DISABLE_PREEMPTION_THRESHOLD
360 
361 #if TX_MAX_PRIORITIES > 32
362 
363                     /* Calculate the index into the bit map array.  */
364                     map_index =  priority/((UINT) 32);
365 #endif
366 
367                     /* Check for a thread preempted that had preemption threshold set.  */
368                     if (_tx_thread_preempted_maps[MAP_INDEX] != ((ULONG) 0))
369                     {
370 
371                         /* Ensure that this thread's priority is clear in the preempt map.  */
372                         TX_MOD32_BIT_SET(priority, priority_bit)
373                         _tx_thread_preempted_maps[MAP_INDEX] =  _tx_thread_preempted_maps[MAP_INDEX] & (~(priority_bit));
374 
375 #if TX_MAX_PRIORITIES > 32
376 
377                         /* Determine if there are any other bits set in this preempt map.  */
378                         if (_tx_thread_preempted_maps[MAP_INDEX] == ((ULONG) 0))
379                         {
380 
381                             /* No, clear the active bit to signify this preempt map has nothing set.  */
382                             TX_DIV32_BIT_SET(priority, priority_bit)
383                             _tx_thread_preempted_map_active =  _tx_thread_preempted_map_active & (~(priority_bit));
384                         }
385 #endif
386                     }
387 #endif
388                 }
389             }
390             else
391             {
392 
393                 /* This is the only thread at this priority ready to run.  Set the head
394                    pointer to NULL.  */
395                 _tx_thread_priority_list[priority] =    TX_NULL;
396 
397 #if TX_MAX_PRIORITIES > 32
398 
399                 /* Calculate the index into the bit map array.  */
400                 map_index =  priority/((UINT) 32);
401 #endif
402 
403                 /* Clear this priority bit in the ready priority bit map.  */
404                 TX_MOD32_BIT_SET(priority, priority_bit)
405                 _tx_thread_priority_maps[MAP_INDEX] =  _tx_thread_priority_maps[MAP_INDEX] & (~(priority_bit));
406 
407 #if TX_MAX_PRIORITIES > 32
408 
409                 /* Determine if there are any other bits set in this priority map.  */
410                 if (_tx_thread_priority_maps[MAP_INDEX] == ((ULONG) 0))
411                 {
412 
413                     /* No, clear the active bit to signify this priority map has nothing set.  */
414                     TX_DIV32_BIT_SET(priority, priority_bit)
415                     _tx_thread_priority_map_active =  _tx_thread_priority_map_active & (~(priority_bit));
416                 }
417 #endif
418 
419 #ifndef TX_DISABLE_PREEMPTION_THRESHOLD
420 
421                 /* Check for a thread preempted that had preemption-threshold set.  */
422                 if (_tx_thread_preempted_maps[MAP_INDEX] != ((ULONG) 0))
423                 {
424 
425                     /* Ensure that this thread's priority is clear in the preempt map.  */
426                     TX_MOD32_BIT_SET(priority, priority_bit)
427                     _tx_thread_preempted_maps[MAP_INDEX] =  _tx_thread_preempted_maps[MAP_INDEX] & (~(priority_bit));
428 
429 #if TX_MAX_PRIORITIES > 32
430 
431                     /* Determine if there are any other bits set in this preempt map.  */
432                     if (_tx_thread_preempted_maps[MAP_INDEX] == ((ULONG) 0))
433                     {
434 
435                         /* No, clear the active bit to signify this preempted map has nothing set.  */
436                         TX_DIV32_BIT_SET(priority, priority_bit)
437                         _tx_thread_preempted_map_active =  _tx_thread_preempted_map_active & (~(priority_bit));
438                     }
439 #endif
440                 }
441 #endif
442 
443 #if TX_MAX_PRIORITIES > 32
444 
445                 /* Calculate the index to find the next highest priority thread ready for execution.  */
446                 priority_map =    _tx_thread_priority_map_active;
447 
448                 /* Determine if there is anything.   */
449                 if (priority_map != ((ULONG) 0))
450                 {
451 
452                     /* Calculate the lowest bit set in the priority map. */
453                     TX_LOWEST_SET_BIT_CALCULATE(priority_map, map_index)
454                 }
455 
456                 /* Calculate the base priority as well.  */
457                 base_priority =  map_index * ((UINT) 32);
458 #else
459 
460                 /* Setup the base priority to zero.  */
461                 base_priority =   ((UINT) 0);
462 #endif
463 
464                 /* Setup working variable for the priority map.  */
465                 priority_map =    _tx_thread_priority_maps[MAP_INDEX];
466 
467                 /* Make a quick check for no other threads ready for execution.  */
468                 if (priority_map == ((ULONG) 0))
469                 {
470 
471                     /* Nothing else is ready.  Set highest priority and execute thread
472                        accordingly.  */
473                     _tx_thread_highest_priority =  ((UINT) TX_MAX_PRIORITIES);
474                     _tx_thread_execute_ptr =       TX_NULL;
475 
476 #ifndef TX_MISRA_ENABLE
477 
478 #ifdef TX_ENABLE_EVENT_TRACE
479 
480                     /* Check that the event time stamp is unchanged.  A different
481                        timestamp means that a later event wrote over the thread
482                        suspend event. In that case, do nothing here.  */
483                     if (entry_ptr != TX_NULL)
484                     {
485 
486                         /* Is the timestamp the same?  */
487                         if (time_stamp == entry_ptr -> tx_trace_buffer_entry_time_stamp)
488                         {
489 
490                             /* Timestamp is the same, set the "next thread pointer" to the new value of the
491                                next thread to execute. This can be used by the trace analysis tool to keep
492                                track of next thread execution.  */
493                             entry_ptr -> tx_trace_buffer_entry_information_field_4 =  0;
494                         }
495                     }
496 #endif
497 
498                     /* Restore interrupts.  */
499                     TX_RESTORE
500 
501                     /* Determine if preemption should take place. This is only possible if the current thread pointer is
502                        not the same as the execute thread pointer AND the system state and preempt disable flags are clear.  */
503                     TX_THREAD_SYSTEM_RETURN_CHECK(combined_flags)
504                     if (combined_flags == ((ULONG) 0))
505                     {
506 
507 #ifdef TX_THREAD_ENABLE_PERFORMANCE_INFO
508 
509                         /* Yes, increment the return to idle return count.  */
510                         _tx_thread_performance_idle_return_count++;
511 #endif
512 
513                         /* Preemption is needed - return to the system!  */
514                         _tx_thread_system_return();
515                     }
516 
517                     /* Return to caller.  */
518                     return(TX_SUCCESS);
519 #endif
520                 }
521                 else
522                 {
523 
524                     /* Calculate the lowest bit set in the priority map. */
525                     TX_LOWEST_SET_BIT_CALCULATE(priority_map, priority_bit)
526 
527                     /* Setup the next highest priority variable.  */
528                     _tx_thread_highest_priority =  base_priority + priority_bit;
529                 }
530             }
531 
532             /* Determine if this thread is the thread designated to execute.  */
533             if (thread_ptr == _tx_thread_execute_ptr)
534             {
535 
536                 /* Pickup the highest priority thread to execute.  */
537                 _tx_thread_execute_ptr =  _tx_thread_priority_list[_tx_thread_highest_priority];
538 
539 #ifndef TX_DISABLE_PREEMPTION_THRESHOLD
540 
541                 /* Determine if a previous thread with preemption-threshold was preempted.  */
542 #if TX_MAX_PRIORITIES > 32
543                 if (_tx_thread_preempted_map_active != ((ULONG) 0))
544 #else
545                 if (_tx_thread_preempted_maps[MAP_INDEX] != ((ULONG) 0))
546 #endif
547                 {
548 
549                     /* Yes, there was a thread preempted when it was using preemption-threshold.  */
550 
551 #ifndef TX_NOT_INTERRUPTABLE
552 
553                     /* Disable preemption.  */
554                     _tx_thread_preempt_disable++;
555 
556                     /* Restore interrupts.  */
557                     TX_RESTORE
558 
559                     /* Interrupts are enabled briefly here to keep the interrupt
560                        lockout time deterministic.  */
561 
562                     /* Disable interrupts again.  */
563                     TX_DISABLE
564 
565                     /* Decrement the preemption disable variable.  */
566                     _tx_thread_preempt_disable--;
567 #endif
568 
569                     /* Calculate the thread with preemption threshold set that
570                        was interrupted by a thread above the preemption level.  */
571 
572 #if TX_MAX_PRIORITIES > 32
573 
574                     /* Calculate the index to find the next highest priority thread ready for execution.  */
575                     priority_map =    _tx_thread_preempted_map_active;
576 
577                     /* Calculate the lowest bit set in the priority map. */
578                     TX_LOWEST_SET_BIT_CALCULATE(priority_map, map_index)
579 
580                     /* Calculate the base priority as well.  */
581                     base_priority =  map_index * ((UINT) 32);
582 #else
583 
584                     /* Setup the base priority to zero.  */
585                     base_priority =   ((UINT) 0);
586 #endif
587 
588                     /* Setup temporary preempted map.  */
589                     priority_map =  _tx_thread_preempted_maps[MAP_INDEX];
590 
591                     /* Calculate the lowest bit set in the priority map. */
592                     TX_LOWEST_SET_BIT_CALCULATE(priority_map, priority_bit)
593 
594                     /* Setup the highest priority preempted thread.  */
595                     priority =  base_priority + priority_bit;
596 
597                     /* Determine if the next highest priority thread is above the highest priority threshold value.  */
598                     if (_tx_thread_highest_priority >= (_tx_thread_priority_list[priority] -> tx_thread_preempt_threshold))
599                     {
600 
601                         /* Thread not allowed to execute until earlier preempted thread finishes or lowers its
602                            preemption-threshold.  */
603                         _tx_thread_execute_ptr =  _tx_thread_priority_list[priority];
604 
605 #ifdef TX_ENABLE_EVENT_TRACE
606 
607                         /* Check that the event time stamp is unchanged.  A different
608                            timestamp means that a later event wrote over the thread
609                            suspend event. In that case, do nothing here.  */
610                         if (entry_ptr != TX_NULL)
611                         {
612 
613                             /* Is the timestamp the same?  */
614                             if (time_stamp == entry_ptr -> tx_trace_buffer_entry_time_stamp)
615                             {
616 
617                                 /* Timestamp is the same, set the "next thread pointer" to the new value of the
618                                    next thread to execute. This can be used by the trace analysis tool to keep
619                                    track of next thread execution.  */
620 #ifdef TX_MISRA_ENABLE
621                                 entry_ptr -> tx_trace_buffer_entry_info_4 =  TX_POINTER_TO_ULONG_CONVERT(_tx_thread_execute_ptr);
622 #else
623                                 entry_ptr -> tx_trace_buffer_entry_information_field_4 =  TX_POINTER_TO_ULONG_CONVERT(_tx_thread_execute_ptr);
624 #endif
625                             }
626                         }
627 #endif
628 
629                         /* Clear the corresponding bit in the preempted map, since the preemption has been restored.  */
630                         TX_MOD32_BIT_SET(priority, priority_bit)
631                         _tx_thread_preempted_maps[MAP_INDEX] =  _tx_thread_preempted_maps[MAP_INDEX] & (~(priority_bit));
632 
633 #if TX_MAX_PRIORITIES > 32
634 
635                         /* Determine if there are any other bits set in this preempt map.  */
636                         if (_tx_thread_preempted_maps[MAP_INDEX] == ((ULONG) 0))
637                         {
638 
639                             /* No, clear the active bit to signify this preempt map has nothing set.  */
640                             TX_DIV32_BIT_SET(priority, priority_bit)
641                             _tx_thread_preempted_map_active =  _tx_thread_preempted_map_active & (~(priority_bit));
642                         }
643 #endif
644                     }
645                 }
646 #endif
647 
648 #ifndef TX_MISRA_ENABLE
649 
650 #ifdef TX_THREAD_ENABLE_PERFORMANCE_INFO
651 
652                 /* Is the execute pointer different?  */
653                 if (_tx_thread_performance_execute_log[_tx_thread_performance__execute_log_index] != _tx_thread_execute_ptr)
654                 {
655 
656                     /* Move to next entry.  */
657                     _tx_thread_performance__execute_log_index++;
658 
659                     /* Check for wrap condition.  */
660                     if (_tx_thread_performance__execute_log_index >= TX_THREAD_EXECUTE_LOG_SIZE)
661                     {
662 
663                         /* Set the index to the beginning.  */
664                         _tx_thread_performance__execute_log_index =  ((UINT) 0);
665                     }
666 
667                     /* Log the new execute pointer.  */
668                     _tx_thread_performance_execute_log[_tx_thread_performance__execute_log_index] =  _tx_thread_execute_ptr;
669                 }
670 #endif
671 
672 #ifdef TX_ENABLE_EVENT_TRACE
673 
674                 /* Check that the event time stamp is unchanged.  A different
675                    timestamp means that a later event wrote over the thread
676                    suspend event. In that case, do nothing here.  */
677                 if (entry_ptr != TX_NULL)
678                 {
679 
680                     /* Is the timestamp the same?  */
681                     if (time_stamp == entry_ptr -> tx_trace_buffer_entry_time_stamp)
682                     {
683 
684                         /* Timestamp is the same, set the "next thread pointer" to the new value of the
685                            next thread to execute. This can be used by the trace analysis tool to keep
686                            track of next thread execution.  */
687                         entry_ptr -> tx_trace_buffer_entry_information_field_4 =  0;
688                     }
689                 }
690 #endif
691 
692                 /* Restore interrupts.  */
693                 TX_RESTORE
694 
695                 /* Determine if preemption should take place. This is only possible if the current thread pointer is
696                    not the same as the execute thread pointer AND the system state and preempt disable flags are clear.  */
697                 TX_THREAD_SYSTEM_RETURN_CHECK(combined_flags)
698                 if (combined_flags == ((ULONG) 0))
699                 {
700 
701 #ifdef TX_THREAD_ENABLE_PERFORMANCE_INFO
702 
703                     /* No, there is another thread ready to run and will be scheduled upon return.  */
704                     _tx_thread_performance_non_idle_return_count++;
705 #endif
706 
707                     /* Preemption is needed - return to the system!  */
708                     _tx_thread_system_return();
709                 }
710 
711                 /* Return to caller.  */
712                 return(TX_SUCCESS);
713 #endif
714             }
715 
716 #ifdef TX_THREAD_ENABLE_PERFORMANCE_INFO
717 
718             /* Is the execute pointer different?  */
719             if (_tx_thread_performance_execute_log[_tx_thread_performance__execute_log_index] != _tx_thread_execute_ptr)
720             {
721 
722                 /* Move to next entry.  */
723                 _tx_thread_performance__execute_log_index++;
724 
725                 /* Check for wrap condition.  */
726                 if (_tx_thread_performance__execute_log_index >= TX_THREAD_EXECUTE_LOG_SIZE)
727                 {
728 
729                     /* Set the index to the beginning.  */
730                     _tx_thread_performance__execute_log_index =  ((UINT) 0);
731                 }
732 
733                 /* Log the new execute pointer.  */
734                 _tx_thread_performance_execute_log[_tx_thread_performance__execute_log_index] =  _tx_thread_execute_ptr;
735             }
736 #endif
737 
738 #ifdef TX_ENABLE_EVENT_TRACE
739 
740             /* Check that the event time stamp is unchanged.  A different
741                timestamp means that a later event wrote over the thread
742                suspend event. In that case, do nothing here.  */
743             if (entry_ptr != TX_NULL)
744             {
745 
746                 /* Is the timestamp the same?  */
747                 if (time_stamp == entry_ptr -> tx_trace_buffer_entry_time_stamp)
748                 {
749 
750                     /* Timestamp is the same, set the "next thread pointer" to the new value of the
751                        next thread to execute. This can be used by the trace analysis tool to keep
752                        track of next thread execution.  */
753 #ifdef TX_MISRA_ENABLE
754                     entry_ptr -> tx_trace_buffer_entry_info_4 =  TX_POINTER_TO_ULONG_CONVERT(_tx_thread_execute_ptr);
755 #else
756                     entry_ptr -> tx_trace_buffer_entry_information_field_4 =  TX_POINTER_TO_ULONG_CONVERT(_tx_thread_execute_ptr);
757 #endif
758                 }
759             }
760 #endif
761 
762             /* Restore interrupts.  */
763             TX_RESTORE
764 
765             /* Determine if a preemption condition is present.  */
766             if (current_thread != _tx_thread_execute_ptr)
767             {
768 
769 #ifdef TX_ENABLE_STACK_CHECKING
770 
771                 /* Pickup the next execute pointer.  */
772                 thread_ptr =  _tx_thread_execute_ptr;
773 
774                 /* Check this thread's stack.  */
775                 TX_THREAD_STACK_CHECK(thread_ptr)
776 #endif
777 
778                 /* Determine if preemption should take place. This is only possible if the current thread pointer is
779                    not the same as the execute thread pointer AND the system state and preempt disable flags are clear.  */
780                 TX_THREAD_SYSTEM_RETURN_CHECK(combined_flags)
781                 if (combined_flags == ((ULONG) 0))
782                 {
783 
784 #ifdef TX_THREAD_ENABLE_PERFORMANCE_INFO
785 
786                     /* Determine if an idle system return is present.  */
787                     if (_tx_thread_execute_ptr == TX_NULL)
788                     {
789 
790                         /* Yes, increment the return to idle return count.  */
791                         _tx_thread_performance_idle_return_count++;
792                     }
793                     else
794                     {
795 
796                         /* No, there is another thread ready to run and will be scheduled upon return.  */
797                         _tx_thread_performance_non_idle_return_count++;
798                     }
799 #endif
800 
801                     /* Preemption is needed - return to the system!  */
802                     _tx_thread_system_return();
803                 }
804             }
805 
806             /* Disable interrupts.  */
807             TX_DISABLE
808 
809             /* Return success.  */
810             status =  TX_SUCCESS;
811         }
812     }
813     else if (thread_ptr -> tx_thread_state == TX_TERMINATED)
814     {
815 
816         /* Thread is terminated.  */
817         status =  TX_SUSPEND_ERROR;
818     }
819     else if (thread_ptr -> tx_thread_state == TX_COMPLETED)
820     {
821 
822         /* Thread is completed.  */
823         status =  TX_SUSPEND_ERROR;
824     }
825     else if (thread_ptr -> tx_thread_state == TX_SUSPENDED)
826     {
827 
828         /* Already suspended, just set status to success.  */
829         status =  TX_SUCCESS;
830     }
831     else
832     {
833 
834         /* Just set the delayed suspension flag.  */
835         thread_ptr -> tx_thread_delayed_suspend =  TX_TRUE;
836 
837         /* Set status to success.  */
838         status =  TX_SUCCESS;
839     }
840 
841     /* Restore interrupts.  */
842     TX_RESTORE
843 
844     /* Return completion status.  */
845     return(status);
846 #endif
847 }
848 
849