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