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
22 #define TX_SOURCE_CODE
23
24
25 /* Include necessary system files. */
26
27 #include "tx_api.h"
28 #include "tx_trace.h"
29 #include "tx_timer.h"
30 #include "tx_thread.h"
31
32
33 /**************************************************************************/
34 /* */
35 /* FUNCTION RELEASE */
36 /* */
37 /* _tx_thread_system_suspend PORTABLE C */
38 /* 6.1 */
39 /* */
40 /* AUTHOR */
41 /* */
42 /* William E. Lamie, Microsoft Corporation */
43 /* */
44 /* DESCRIPTION */
45 /* */
46 /* This function suspends the specified thread and changes the thread */
47 /* state to the value specified. Note: delayed suspension processing */
48 /* is handled outside of this routine. */
49 /* */
50 /* INPUT */
51 /* */
52 /* thread_ptr Pointer to thread to suspend */
53 /* */
54 /* OUTPUT */
55 /* */
56 /* None */
57 /* */
58 /* CALLS */
59 /* */
60 /* _tx_thread_system_return Return to system */
61 /* _tx_thread_system_preempt_check System preemption check */
62 /* _tx_timer_system_activate Activate timer for timeout */
63 /* */
64 /* CALLED BY */
65 /* */
66 /* _tx_thread_priority_change Thread priority change */
67 /* _tx_thread_shell_entry Thread shell function */
68 /* _tx_thread_sleep Thread sleep */
69 /* _tx_thread_suspend Application thread suspend */
70 /* _tx_thread_terminate Thread terminate */
71 /* Other ThreadX Components */
72 /* */
73 /* RELEASE HISTORY */
74 /* */
75 /* DATE NAME DESCRIPTION */
76 /* */
77 /* 05-19-2020 William E. Lamie Initial Version 6.0 */
78 /* 09-30-2020 Yuxin Zhou Modified comment(s), */
79 /* resulting in version 6.1 */
80 /* */
81 /**************************************************************************/
_tx_thread_system_suspend(TX_THREAD * thread_ptr)82 VOID _tx_thread_system_suspend(TX_THREAD *thread_ptr)
83 #ifndef TX_NOT_INTERRUPTABLE
84 {
85
86 TX_INTERRUPT_SAVE_AREA
87
88 UINT priority;
89 UINT base_priority;
90 ULONG priority_map;
91 ULONG priority_bit;
92 ULONG combined_flags;
93 TX_THREAD *ready_next;
94 TX_THREAD *ready_previous;
95 TX_THREAD *current_thread;
96
97 #if TX_MAX_PRIORITIES > 32
98 UINT map_index;
99 #endif
100
101 #ifndef TX_NO_TIMER
102 ULONG timeout;
103 #endif
104
105 #ifdef TX_ENABLE_EVENT_TRACE
106 TX_TRACE_BUFFER_ENTRY *entry_ptr;
107 ULONG time_stamp = ((ULONG) 0);
108 #endif
109
110 /* Pickup thread pointer. */
111 TX_THREAD_GET_CURRENT(current_thread)
112
113 #ifdef TX_ENABLE_STACK_CHECKING
114
115 /* Check this thread's stack. */
116 TX_THREAD_STACK_CHECK(thread_ptr)
117 #endif
118
119 /* Lockout interrupts while the thread is being suspended. */
120 TX_DISABLE
121
122 #ifndef TX_NO_TIMER
123
124 /* Is the current thread suspending? */
125 if (thread_ptr == current_thread)
126 {
127
128 /* Pickup the wait option. */
129 timeout = thread_ptr -> tx_thread_timer.tx_timer_internal_remaining_ticks;
130
131 /* Determine if an activation is needed. */
132 if (timeout != TX_NO_WAIT)
133 {
134
135 /* Make sure the suspension is not a wait-forever. */
136 if (timeout != TX_WAIT_FOREVER)
137 {
138
139 /* Activate the thread timer with the timeout value setup in the caller. */
140 _tx_timer_system_activate(&(thread_ptr -> tx_thread_timer));
141 }
142 }
143
144 /* Yes, reset time slice for current thread. */
145 _tx_timer_time_slice = thread_ptr -> tx_thread_new_time_slice;
146 }
147 #endif
148
149 /* Decrease the preempt disabled count. */
150 _tx_thread_preempt_disable--;
151
152 #ifdef TX_THREAD_ENABLE_PERFORMANCE_INFO
153
154 /* Increment the thread's suspend count. */
155 thread_ptr -> tx_thread_performance_suspend_count++;
156
157 /* Increment the total number of thread suspensions. */
158 _tx_thread_performance_suspend_count++;
159 #endif
160
161 /* Check to make sure the thread suspending flag is still set. If not, it
162 has already been resumed. */
163 if (thread_ptr -> tx_thread_suspending == TX_TRUE)
164 {
165
166 /* Thread state change. */
167 TX_THREAD_STATE_CHANGE(thread_ptr, thread_ptr -> tx_thread_state)
168
169 /* Log the thread status change. */
170 TX_EL_THREAD_STATUS_CHANGE_INSERT(thread_ptr, thread_ptr -> tx_thread_state)
171
172 #ifdef TX_ENABLE_EVENT_TRACE
173
174 /* If trace is enabled, save the current event pointer. */
175 entry_ptr = _tx_trace_buffer_current_ptr;
176 #endif
177
178 /* Log the thread status change. */
179 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)
180
181 #ifdef TX_ENABLE_EVENT_TRACE
182
183 /* Save the time stamp for later comparison to verify that
184 the event hasn't been overwritten by the time we have
185 computed the next thread to execute. */
186 if (entry_ptr != TX_NULL)
187 {
188
189 /* Save time stamp. */
190 time_stamp = entry_ptr -> tx_trace_buffer_entry_time_stamp;
191 }
192 #endif
193
194 /* Actually suspend this thread. But first, clear the suspending flag. */
195 thread_ptr -> tx_thread_suspending = TX_FALSE;
196
197 /* Pickup priority of thread. */
198 priority = thread_ptr -> tx_thread_priority;
199
200 /* Pickup the next ready thread pointer. */
201 ready_next = thread_ptr -> tx_thread_ready_next;
202
203 /* Determine if there are other threads at this priority that are
204 ready. */
205 if (ready_next != thread_ptr)
206 {
207
208 /* Yes, there are other threads at this priority ready. */
209
210 /* Pickup the previous ready thread pointer. */
211 ready_previous = thread_ptr -> tx_thread_ready_previous;
212
213 /* Just remove this thread from the priority list. */
214 ready_next -> tx_thread_ready_previous = ready_previous;
215 ready_previous -> tx_thread_ready_next = ready_next;
216
217 /* Determine if this is the head of the priority list. */
218 if (_tx_thread_priority_list[priority] == thread_ptr)
219 {
220
221 /* Update the head pointer of this priority list. */
222 _tx_thread_priority_list[priority] = ready_next;
223
224 #ifndef TX_DISABLE_PREEMPTION_THRESHOLD
225
226 #if TX_MAX_PRIORITIES > 32
227
228 /* Calculate the index into the bit map array. */
229 map_index = priority/((UINT) 32);
230 #endif
231
232 /* Check for a thread preempted that had preemption threshold set. */
233 if (_tx_thread_preempted_maps[MAP_INDEX] != ((ULONG) 0))
234 {
235
236 /* Ensure that this thread's priority is clear in the preempt map. */
237 TX_MOD32_BIT_SET(priority, priority_bit)
238 _tx_thread_preempted_maps[MAP_INDEX] = _tx_thread_preempted_maps[MAP_INDEX] & (~(priority_bit));
239
240 #if TX_MAX_PRIORITIES > 32
241
242 /* Determine if there are any other bits set in this preempt map. */
243 if (_tx_thread_preempted_maps[MAP_INDEX] == ((ULONG) 0))
244 {
245
246 /* No, clear the active bit to signify this preempt map has nothing set. */
247 TX_DIV32_BIT_SET(priority, priority_bit)
248 _tx_thread_preempted_map_active = _tx_thread_preempted_map_active & (~(priority_bit));
249 }
250 #endif
251 }
252 #endif
253 }
254 }
255 else
256 {
257
258 /* This is the only thread at this priority ready to run. Set the head
259 pointer to NULL. */
260 _tx_thread_priority_list[priority] = TX_NULL;
261
262 #if TX_MAX_PRIORITIES > 32
263
264 /* Calculate the index into the bit map array. */
265 map_index = priority/((UINT) 32);
266 #endif
267
268 /* Clear this priority bit in the ready priority bit map. */
269 TX_MOD32_BIT_SET(priority, priority_bit)
270 _tx_thread_priority_maps[MAP_INDEX] = _tx_thread_priority_maps[MAP_INDEX] & (~(priority_bit));
271
272 #if TX_MAX_PRIORITIES > 32
273
274 /* Determine if there are any other bits set in this priority map. */
275 if (_tx_thread_priority_maps[MAP_INDEX] == ((ULONG) 0))
276 {
277
278 /* No, clear the active bit to signify this priority map has nothing set. */
279 TX_DIV32_BIT_SET(priority, priority_bit)
280 _tx_thread_priority_map_active = _tx_thread_priority_map_active & (~(priority_bit));
281 }
282 #endif
283
284 #ifndef TX_DISABLE_PREEMPTION_THRESHOLD
285
286 /* Check for a thread preempted that had preemption-threshold set. */
287 if (_tx_thread_preempted_maps[MAP_INDEX] != ((ULONG) 0))
288 {
289
290 /* Ensure that this thread's priority is clear in the preempt map. */
291 TX_MOD32_BIT_SET(priority, priority_bit)
292 _tx_thread_preempted_maps[MAP_INDEX] = _tx_thread_preempted_maps[MAP_INDEX] & (~(priority_bit));
293
294 #if TX_MAX_PRIORITIES > 32
295
296 /* Determine if there are any other bits set in this preempt map. */
297 if (_tx_thread_preempted_maps[MAP_INDEX] == ((ULONG) 0))
298 {
299
300 /* No, clear the active bit to signify this preempted map has nothing set. */
301 TX_DIV32_BIT_SET(priority, priority_bit)
302 _tx_thread_preempted_map_active = _tx_thread_preempted_map_active & (~(priority_bit));
303 }
304 #endif
305 }
306 #endif
307
308 #if TX_MAX_PRIORITIES > 32
309
310 /* Calculate the index to find the next highest priority thread ready for execution. */
311 priority_map = _tx_thread_priority_map_active;
312
313 /* Determine if there is anything. */
314 if (priority_map != ((ULONG) 0))
315 {
316
317 /* Calculate the lowest bit set in the priority map. */
318 TX_LOWEST_SET_BIT_CALCULATE(priority_map, map_index)
319 }
320
321 /* Calculate the base priority as well. */
322 base_priority = map_index * ((UINT) 32);
323 #else
324
325 /* Setup the base priority to zero. */
326 base_priority = ((UINT) 0);
327 #endif
328
329 /* Setup working variable for the priority map. */
330 priority_map = _tx_thread_priority_maps[MAP_INDEX];
331
332 /* Make a quick check for no other threads ready for execution. */
333 if (priority_map == ((ULONG) 0))
334 {
335
336 /* Nothing else is ready. Set highest priority and execute thread
337 accordingly. */
338 _tx_thread_highest_priority = ((UINT) TX_MAX_PRIORITIES);
339 _tx_thread_execute_ptr = TX_NULL;
340
341 #ifndef TX_MISRA_ENABLE
342
343 #ifdef TX_ENABLE_EVENT_TRACE
344
345 /* Check that the event time stamp is unchanged. A different
346 timestamp means that a later event wrote over the thread
347 suspend event. In that case, do nothing here. */
348 if (entry_ptr != TX_NULL)
349 {
350
351 /* Is the timestamp the same? */
352 if (time_stamp == entry_ptr -> tx_trace_buffer_entry_time_stamp)
353 {
354
355 /* Timestamp is the same, set the "next thread pointer" to the new value of the
356 next thread to execute. This can be used by the trace analysis tool to keep
357 track of next thread execution. */
358 entry_ptr -> tx_trace_buffer_entry_information_field_4 = 0;
359 }
360 }
361 #endif
362
363 /* Restore interrupts. */
364 TX_RESTORE
365
366 /* Determine if preemption should take place. This is only possible if the current thread pointer is
367 not the same as the execute thread pointer AND the system state and preempt disable flags are clear. */
368 TX_THREAD_SYSTEM_RETURN_CHECK(combined_flags)
369 if (combined_flags == ((ULONG) 0))
370 {
371
372 #ifdef TX_THREAD_ENABLE_PERFORMANCE_INFO
373
374 /* Yes, increment the return to idle return count. */
375 _tx_thread_performance_idle_return_count++;
376 #endif
377
378 /* Preemption is needed - return to the system! */
379 _tx_thread_system_return();
380 }
381
382 /* Return to caller. */
383 return;
384 #endif
385 }
386 else
387 {
388
389 /* Other threads at different priority levels are ready to run. */
390
391 /* Calculate the lowest bit set in the priority map. */
392 TX_LOWEST_SET_BIT_CALCULATE(priority_map, priority_bit)
393
394 /* Setup the next highest priority variable. */
395 _tx_thread_highest_priority = base_priority + ((UINT) priority_bit);
396 }
397 }
398
399 /* Determine if the suspending thread is the thread designated to execute. */
400 if (thread_ptr == _tx_thread_execute_ptr)
401 {
402
403 /* Pickup the highest priority thread to execute. */
404 _tx_thread_execute_ptr = _tx_thread_priority_list[_tx_thread_highest_priority];
405
406 #ifndef TX_DISABLE_PREEMPTION_THRESHOLD
407
408 /* Determine if a previous thread with preemption-threshold was preempted. */
409 #if TX_MAX_PRIORITIES > 32
410 if (_tx_thread_preempted_map_active != ((ULONG) 0))
411 #else
412 if (_tx_thread_preempted_maps[MAP_INDEX] != ((ULONG) 0))
413 #endif
414 {
415
416 /* Yes, there was a thread preempted when it was using preemption-threshold. */
417
418 /* Disable preemption. */
419 _tx_thread_preempt_disable++;
420
421 /* Restore interrupts. */
422 TX_RESTORE
423
424 /* Interrupts are enabled briefly here to keep the interrupt
425 lockout time deterministic. */
426
427 /* Disable interrupts again. */
428 TX_DISABLE
429
430 /* Decrement the preemption disable variable. */
431 _tx_thread_preempt_disable--;
432
433 /* Calculate the thread with preemption threshold set that
434 was interrupted by a thread above the preemption level. */
435
436 #if TX_MAX_PRIORITIES > 32
437
438 /* Calculate the index to find the next highest priority thread ready for execution. */
439 priority_map = _tx_thread_preempted_map_active;
440
441 /* Calculate the lowest bit set in the priority map. */
442 TX_LOWEST_SET_BIT_CALCULATE(priority_map, map_index)
443
444 /* Calculate the base priority as well. */
445 base_priority = map_index * ((UINT) 32);
446 #else
447
448 /* Setup the base priority to zero. */
449 base_priority = ((UINT) 0);
450 #endif
451
452 /* Setup temporary preempted map. */
453 priority_map = _tx_thread_preempted_maps[MAP_INDEX];
454
455 /* Calculate the lowest bit set in the priority map. */
456 TX_LOWEST_SET_BIT_CALCULATE(priority_map, priority_bit)
457
458 /* Setup the highest priority preempted thread. */
459 priority = base_priority + ((UINT) priority_bit);
460
461 /* Determine if the next highest priority thread is above the highest priority threshold value. */
462 if (_tx_thread_highest_priority >= (_tx_thread_priority_list[priority] -> tx_thread_preempt_threshold))
463 {
464
465 /* Thread not allowed to execute until earlier preempted thread finishes or lowers its
466 preemption-threshold. */
467 _tx_thread_execute_ptr = _tx_thread_priority_list[priority];
468
469 /* Clear the corresponding bit in the preempted map, since the preemption has been restored. */
470 TX_MOD32_BIT_SET(priority, priority_bit)
471 _tx_thread_preempted_maps[MAP_INDEX] = _tx_thread_preempted_maps[MAP_INDEX] & (~(priority_bit));
472
473 #if TX_MAX_PRIORITIES > 32
474
475 /* Determine if there are any other bits set in this preempt map. */
476 if (_tx_thread_preempted_maps[MAP_INDEX] == ((ULONG) 0))
477 {
478
479 /* No, clear the active bit to signify this preempt map has nothing set. */
480 TX_DIV32_BIT_SET(priority, priority_bit)
481 _tx_thread_preempted_map_active = _tx_thread_preempted_map_active & (~(priority_bit));
482 }
483 #endif
484 }
485 }
486 #endif
487
488 #ifndef TX_MISRA_ENABLE
489
490 #ifdef TX_THREAD_ENABLE_PERFORMANCE_INFO
491
492 /* Is the execute pointer different? */
493 if (_tx_thread_performance_execute_log[_tx_thread_performance__execute_log_index] != _tx_thread_execute_ptr)
494 {
495
496 /* Move to next entry. */
497 _tx_thread_performance__execute_log_index++;
498
499 /* Check for wrap condition. */
500 if (_tx_thread_performance__execute_log_index >= TX_THREAD_EXECUTE_LOG_SIZE)
501 {
502
503 /* Set the index to the beginning. */
504 _tx_thread_performance__execute_log_index = ((UINT) 0);
505 }
506
507 /* Log the new execute pointer. */
508 _tx_thread_performance_execute_log[_tx_thread_performance__execute_log_index] = _tx_thread_execute_ptr;
509 }
510 #endif
511
512 #ifdef TX_ENABLE_EVENT_TRACE
513
514 /* Check that the event time stamp is unchanged. A different
515 timestamp means that a later event wrote over the thread
516 suspend event. In that case, do nothing here. */
517 if (entry_ptr != TX_NULL)
518 {
519
520 /* Is the timestamp the same? */
521 if (time_stamp == entry_ptr -> tx_trace_buffer_entry_time_stamp)
522 {
523
524 /* Timestamp is the same, set the "next thread pointer" to the new value of the
525 next thread to execute. This can be used by the trace analysis tool to keep
526 track of next thread execution. */
527 entry_ptr -> tx_trace_buffer_entry_information_field_4 = TX_POINTER_TO_ULONG_CONVERT(_tx_thread_execute_ptr);
528 }
529 }
530 #endif
531
532 /* Restore interrupts. */
533 TX_RESTORE
534
535 /* Determine if preemption should take place. This is only possible if the current thread pointer is
536 not the same as the execute thread pointer AND the system state and preempt disable flags are clear. */
537 TX_THREAD_SYSTEM_RETURN_CHECK(combined_flags)
538 if (combined_flags == ((ULONG) 0))
539 {
540
541 #ifdef TX_THREAD_ENABLE_PERFORMANCE_INFO
542
543 /* No, there is another thread ready to run and will be scheduled upon return. */
544 _tx_thread_performance_non_idle_return_count++;
545 #endif
546
547 /* Preemption is needed - return to the system! */
548 _tx_thread_system_return();
549 }
550
551 /* Return to caller. */
552 return;
553 #endif
554 }
555
556 #ifdef TX_THREAD_ENABLE_PERFORMANCE_INFO
557
558 /* Is the execute pointer different? */
559 if (_tx_thread_performance_execute_log[_tx_thread_performance__execute_log_index] != _tx_thread_execute_ptr)
560 {
561
562 /* Move to next entry. */
563 _tx_thread_performance__execute_log_index++;
564
565 /* Check for wrap condition. */
566 if (_tx_thread_performance__execute_log_index >= TX_THREAD_EXECUTE_LOG_SIZE)
567 {
568
569 /* Set the index to the beginning. */
570 _tx_thread_performance__execute_log_index = ((UINT) 0);
571 }
572
573 /* Log the new execute pointer. */
574 _tx_thread_performance_execute_log[_tx_thread_performance__execute_log_index] = _tx_thread_execute_ptr;
575 }
576 #endif
577
578 #ifdef TX_ENABLE_EVENT_TRACE
579
580 /* Check that the event time stamp is unchanged. A different
581 timestamp means that a later event wrote over the thread
582 suspend event. In that case, do nothing here. */
583 if (entry_ptr != TX_NULL)
584 {
585
586 /* Is the timestamp the same? */
587 if (time_stamp == entry_ptr -> tx_trace_buffer_entry_time_stamp)
588 {
589
590 /* Timestamp is the same, set the "next thread pointer" to the new value of the
591 next thread to execute. This can be used by the trace analysis tool to keep
592 track of next thread execution. */
593 #ifdef TX_MISRA_ENABLE
594 entry_ptr -> tx_trace_buffer_entry_info_4 = TX_POINTER_TO_ULONG_CONVERT(_tx_thread_execute_ptr);
595 #else
596 entry_ptr -> tx_trace_buffer_entry_information_field_4 = TX_POINTER_TO_ULONG_CONVERT(_tx_thread_execute_ptr);
597 #endif
598 }
599 }
600 #endif
601 }
602
603 /* Restore interrupts. */
604 TX_RESTORE
605
606 /* Determine if a preemption condition is present. */
607 if (current_thread != _tx_thread_execute_ptr)
608 {
609
610 #ifdef TX_ENABLE_STACK_CHECKING
611
612 /* Pickup the next execute pointer. */
613 thread_ptr = _tx_thread_execute_ptr;
614
615 /* Check this thread's stack. */
616 TX_THREAD_STACK_CHECK(thread_ptr)
617 #endif
618
619 /* Determine if preemption should take place. This is only possible if the current thread pointer is
620 not the same as the execute thread pointer AND the system state and preempt disable flags are clear. */
621 TX_THREAD_SYSTEM_RETURN_CHECK(combined_flags)
622 if (combined_flags == ((ULONG) 0))
623 {
624
625 #ifdef TX_THREAD_ENABLE_PERFORMANCE_INFO
626
627 /* Determine if an idle system return is present. */
628 if (_tx_thread_execute_ptr == TX_NULL)
629 {
630
631 /* Yes, increment the return to idle return count. */
632 _tx_thread_performance_idle_return_count++;
633 }
634 else
635 {
636
637 /* No, there is another thread ready to run and will be scheduled upon return. */
638 _tx_thread_performance_non_idle_return_count++;
639 }
640 #endif
641
642 /* Preemption is needed - return to the system! */
643 _tx_thread_system_return();
644 }
645 }
646
647 /* Return to caller. */
648 return;
649 }
650 #else
651 /* Define the entry function for modules assuming the interruptable version of system suspend. */
652 {
653
654 TX_INTERRUPT_SAVE_AREA
655
656 ULONG wait_option;
657
658 /* Disable interrupts. */
659 TX_DISABLE
660
661 /* Determine if the thread is still suspending. */
662 if (thread_ptr -> tx_thread_suspending == TX_TRUE)
663 {
664
665 /* Yes, prepare to call the non-interruptable system suspend function. */
666
667 /* Clear the thread suspending flag. */
668 thread_ptr -> tx_thread_suspending = TX_FALSE;
669
670 /* Pickup the wait option. */
671 wait_option = thread_ptr -> tx_thread_timer.tx_timer_internal_remaining_ticks;
672
673 /* Decrement the preempt disable count. */
674 _tx_thread_preempt_disable--;
675
676 /* Call actual non-interruptable thread suspension routine. */
677 _tx_thread_system_ni_suspend(thread_ptr, wait_option);
678 }
679
680 /* Restore interrupts. */
681 TX_RESTORE
682
683 /* Check for preemption. */
684 _tx_thread_system_preempt_check();
685 }
686
687 /* Define the system suspend function that is not interruptable, i.e., it is assumed that
688 interrupts are disabled upon calling this function. */
689
690 VOID _tx_thread_system_ni_suspend(TX_THREAD *thread_ptr, ULONG wait_option)
691 {
692
693 UINT priority;
694 UINT base_priority;
695 ULONG priority_map;
696 ULONG priority_bit;
697 ULONG combined_flags;
698 TX_THREAD *ready_next;
699 TX_THREAD *ready_previous;
700 TX_THREAD *current_thread;
701
702 #if TX_MAX_PRIORITIES > 32
703 UINT map_index;
704 #endif
705
706 #ifdef TX_ENABLE_EVENT_TRACE
707 TX_TRACE_BUFFER_ENTRY *entry_ptr;
708 ULONG time_stamp = ((ULONG) 0);
709 #endif
710
711
712 /* Pickup thread pointer. */
713 TX_THREAD_GET_CURRENT(current_thread)
714
715 #ifndef TX_NO_TIMER
716
717
718 /* Determine if a timeout needs to be activated. */
719 if (thread_ptr == current_thread)
720 {
721
722 /* Is there a wait option? */
723 if (wait_option != TX_NO_WAIT)
724 {
725
726 /* Make sure it is not a wait-forever option. */
727 if (wait_option != TX_WAIT_FOREVER)
728 {
729
730 /* Setup the wait option. */
731 thread_ptr -> tx_thread_timer.tx_timer_internal_remaining_ticks = wait_option;
732
733 /* Activate the thread timer with the timeout value setup in the caller. */
734 _tx_timer_system_activate(&(thread_ptr -> tx_thread_timer));
735 }
736 }
737
738 /* Reset time slice for current thread. */
739 _tx_timer_time_slice = thread_ptr -> tx_thread_new_time_slice;
740 }
741 #endif
742
743 #ifdef TX_ENABLE_STACK_CHECKING
744
745 /* Check this thread's stack. */
746 TX_THREAD_STACK_CHECK(thread_ptr)
747 #endif
748
749 #ifdef TX_THREAD_ENABLE_PERFORMANCE_INFO
750
751 /* Increment the thread's suspend count. */
752 thread_ptr -> tx_thread_performance_suspend_count++;
753
754 /* Increment the total number of thread suspensions. */
755 _tx_thread_performance_suspend_count++;
756 #endif
757
758 /* Thread state change. */
759 TX_THREAD_STATE_CHANGE(thread_ptr, thread_ptr -> tx_thread_state)
760
761 /* Log the thread status change. */
762 TX_EL_THREAD_STATUS_CHANGE_INSERT(thread_ptr, thread_ptr -> tx_thread_state)
763
764 #ifdef TX_ENABLE_EVENT_TRACE
765
766 /* If trace is enabled, save the current event pointer. */
767 entry_ptr = _tx_trace_buffer_current_ptr;
768 #endif
769
770 /* Log the thread status change. */
771 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)
772
773 #ifdef TX_ENABLE_EVENT_TRACE
774
775 /* Save the time stamp for later comparison to verify that
776 the event hasn't been overwritten by the time we have
777 computed the next thread to execute. */
778 if (entry_ptr != TX_NULL)
779 {
780
781 /* Save time stamp. */
782 time_stamp = entry_ptr -> tx_trace_buffer_entry_time_stamp;
783 }
784 #endif
785
786 /* Pickup priority of thread. */
787 priority = thread_ptr -> tx_thread_priority;
788
789 /* Pickup the next ready thread pointer. */
790 ready_next = thread_ptr -> tx_thread_ready_next;
791
792 /* Determine if there are other threads at this priority that are
793 ready. */
794 if (ready_next != thread_ptr)
795 {
796
797 /* Yes, there are other threads at this priority ready. */
798
799 /* Pickup the previous ready thread pointer. */
800 ready_previous = thread_ptr -> tx_thread_ready_previous;
801
802 /* Just remove this thread from the priority list. */
803 ready_next -> tx_thread_ready_previous = ready_previous;
804 ready_previous -> tx_thread_ready_next = ready_next;
805
806 /* Determine if this is the head of the priority list. */
807 if (_tx_thread_priority_list[priority] == thread_ptr)
808 {
809
810 /* Update the head pointer of this priority list. */
811 _tx_thread_priority_list[priority] = ready_next;
812
813 #ifndef TX_DISABLE_PREEMPTION_THRESHOLD
814
815 #if TX_MAX_PRIORITIES > 32
816
817 /* Calculate the index into the bit map array. */
818 map_index = priority/((UINT) 32);
819 #endif
820
821 /* Check for a thread preempted that had preemption threshold set. */
822 if (_tx_thread_preempted_maps[MAP_INDEX] != ((ULONG) 0))
823 {
824
825 /* Ensure that this thread's priority is clear in the preempt map. */
826 TX_MOD32_BIT_SET(priority, priority_bit)
827 _tx_thread_preempted_maps[MAP_INDEX] = _tx_thread_preempted_maps[MAP_INDEX] & (~(priority_bit));
828
829 #if TX_MAX_PRIORITIES > 32
830
831 /* Determine if there are any other bits set in this preempt map. */
832 if (_tx_thread_preempted_maps[MAP_INDEX] == ((ULONG) 0))
833 {
834
835 /* No, clear the active bit to signify this preempt map has nothing set. */
836 TX_DIV32_BIT_SET(priority, priority_bit)
837 _tx_thread_preempted_map_active = _tx_thread_preempted_map_active & (~(priority_bit));
838 }
839 #endif
840 }
841 #endif
842 }
843 }
844 else
845 {
846
847 /* This is the only thread at this priority ready to run. Set the head
848 pointer to NULL. */
849 _tx_thread_priority_list[priority] = TX_NULL;
850
851 #if TX_MAX_PRIORITIES > 32
852
853 /* Calculate the index into the bit map array. */
854 map_index = priority/((UINT) 32);
855 #endif
856
857 /* Clear this priority bit in the ready priority bit map. */
858 TX_MOD32_BIT_SET(priority, priority_bit)
859 _tx_thread_priority_maps[MAP_INDEX] = _tx_thread_priority_maps[MAP_INDEX] & (~(priority_bit));
860
861 #if TX_MAX_PRIORITIES > 32
862
863 /* Determine if there are any other bits set in this priority map. */
864 if (_tx_thread_priority_maps[MAP_INDEX] == ((ULONG) 0))
865 {
866
867 /* No, clear the active bit to signify this priority map has nothing set. */
868 TX_DIV32_BIT_SET(priority, priority_bit)
869 _tx_thread_priority_map_active = _tx_thread_priority_map_active & (~(priority_bit));
870 }
871 #endif
872
873 #ifndef TX_DISABLE_PREEMPTION_THRESHOLD
874
875 /* Check for a thread preempted that had preemption-threshold set. */
876 if (_tx_thread_preempted_maps[MAP_INDEX] != ((ULONG) 0))
877 {
878
879 /* Ensure that this thread's priority is clear in the preempt map. */
880 TX_MOD32_BIT_SET(priority, priority_bit)
881 _tx_thread_preempted_maps[MAP_INDEX] = _tx_thread_preempted_maps[MAP_INDEX] & (~(priority_bit));
882
883 #if TX_MAX_PRIORITIES > 32
884
885 /* Determine if there are any other bits set in this preempt map. */
886 if (_tx_thread_preempted_maps[MAP_INDEX] == ((ULONG) 0))
887 {
888
889 /* No, clear the active bit to signify this preempted map has nothing set. */
890 TX_DIV32_BIT_SET(priority, priority_bit)
891 _tx_thread_preempted_map_active = _tx_thread_preempted_map_active & (~(priority_bit));
892 }
893 #endif
894 }
895 #endif
896
897 #if TX_MAX_PRIORITIES > 32
898
899 /* Calculate the index to find the next highest priority thread ready for execution. */
900 priority_map = _tx_thread_priority_map_active;
901
902 /* Determine if there is anything. */
903 if (priority_map != ((ULONG) 0))
904 {
905
906 /* Calculate the lowest bit set in the priority map. */
907 TX_LOWEST_SET_BIT_CALCULATE(priority_map, map_index)
908 }
909
910 /* Calculate the base priority as well. */
911 base_priority = map_index * ((UINT) 32);
912 #else
913
914 /* Setup the base priority to zero. */
915 base_priority = ((UINT) 0);
916 #endif
917
918 /* Setup working variable for the priority map. */
919 priority_map = _tx_thread_priority_maps[MAP_INDEX];
920
921 /* Make a quick check for no other threads ready for execution. */
922 if (priority_map == ((ULONG) 0))
923 {
924
925 /* Nothing else is ready. Set highest priority and execute thread
926 accordingly. */
927 _tx_thread_highest_priority = ((UINT) TX_MAX_PRIORITIES);
928 _tx_thread_execute_ptr = TX_NULL;
929
930 #ifndef TX_MISRA_ENABLE
931
932 #ifdef TX_ENABLE_EVENT_TRACE
933
934 /* Check that the event time stamp is unchanged. A different
935 timestamp means that a later event wrote over the thread
936 suspend event. In that case, do nothing here. */
937 if (entry_ptr != TX_NULL)
938 {
939
940 /* Is the timestamp the same? */
941 if (time_stamp == entry_ptr -> tx_trace_buffer_entry_time_stamp)
942 {
943
944 /* Timestamp is the same, set the "next thread pointer" to the new value of the
945 next thread to execute. This can be used by the trace analysis tool to keep
946 track of next thread execution. */
947 entry_ptr -> tx_trace_buffer_entry_information_field_4 = 0;
948 }
949 }
950 #endif
951
952 /* Determine if preemption should take place. This is only possible if the current thread pointer is
953 not the same as the execute thread pointer AND the system state and preempt disable flags are clear. */
954 TX_THREAD_SYSTEM_RETURN_CHECK(combined_flags)
955 if (combined_flags == ((ULONG) 0))
956 {
957
958 #ifdef TX_THREAD_ENABLE_PERFORMANCE_INFO
959
960 /* Yes, increment the return to idle return count. */
961 _tx_thread_performance_idle_return_count++;
962 #endif
963
964 /* Preemption is needed - return to the system! */
965 _tx_thread_system_return();
966 }
967
968 /* Return to caller. */
969 return;
970 #endif
971 }
972 else
973 {
974
975 /* Calculate the lowest bit set in the priority map. */
976 TX_LOWEST_SET_BIT_CALCULATE(priority_map, priority_bit)
977
978 /* Setup the next highest priority variable. */
979 _tx_thread_highest_priority = base_priority + ((UINT) priority_bit);
980 }
981 }
982
983 /* Determine if the suspending thread is the thread designated to execute. */
984 if (thread_ptr == _tx_thread_execute_ptr)
985 {
986
987 /* Pickup the highest priority thread to execute. */
988 _tx_thread_execute_ptr = _tx_thread_priority_list[_tx_thread_highest_priority];
989
990 #ifndef TX_DISABLE_PREEMPTION_THRESHOLD
991
992 /* Determine if a previous thread with preemption-threshold was preempted. */
993 #if TX_MAX_PRIORITIES > 32
994 if (_tx_thread_preempted_map_active != ((ULONG) 0))
995 #else
996 if (_tx_thread_preempted_maps[MAP_INDEX] != ((ULONG) 0))
997 #endif
998 {
999
1000 /* Yes, there was a thread preempted when it was using preemption-threshold. */
1001
1002 /* Disable preemption. */
1003 _tx_thread_preempt_disable++;
1004
1005 /* Decrement the preemption disable variable. */
1006 _tx_thread_preempt_disable--;
1007
1008 /* Calculate the thread with preemption threshold set that
1009 was interrupted by a thread above the preemption level. */
1010
1011 #if TX_MAX_PRIORITIES > 32
1012
1013 /* Calculate the index to find the next highest priority thread ready for execution. */
1014 priority_map = _tx_thread_preempted_map_active;
1015
1016 /* Calculate the lowest bit set in the priority map. */
1017 TX_LOWEST_SET_BIT_CALCULATE(priority_map, map_index)
1018
1019 /* Calculate the base priority as well. */
1020 base_priority = map_index * ((UINT) 32);
1021 #else
1022
1023 /* Setup the base priority to zero. */
1024 base_priority = ((UINT) 0);
1025 #endif
1026
1027 /* Setup temporary preempted map. */
1028 priority_map = _tx_thread_preempted_maps[MAP_INDEX];
1029
1030 /* Calculate the lowest bit set in the priority map. */
1031 TX_LOWEST_SET_BIT_CALCULATE(priority_map, priority_bit)
1032
1033 /* Setup the highest priority preempted thread. */
1034 priority = base_priority + ((UINT) priority_bit);
1035
1036 /* Determine if the next highest priority thread is above the highest priority threshold value. */
1037 if (_tx_thread_highest_priority >= (_tx_thread_priority_list[priority] -> tx_thread_preempt_threshold))
1038 {
1039
1040 /* Thread not allowed to execute until earlier preempted thread finishes or lowers its
1041 preemption-threshold. */
1042 _tx_thread_execute_ptr = _tx_thread_priority_list[priority];
1043
1044 /* Clear the corresponding bit in the preempted map, since the preemption has been restored. */
1045 TX_MOD32_BIT_SET(priority, priority_bit)
1046 _tx_thread_preempted_maps[MAP_INDEX] = _tx_thread_preempted_maps[MAP_INDEX] & (~(priority_bit));
1047
1048 #if TX_MAX_PRIORITIES > 32
1049
1050 /* Determine if there are any other bits set in this preempt map. */
1051 if (_tx_thread_preempted_maps[MAP_INDEX] == ((ULONG) 0))
1052 {
1053
1054 /* No, clear the active bit to signify this preempt map has nothing set. */
1055 TX_DIV32_BIT_SET(priority, priority_bit)
1056 _tx_thread_preempted_map_active = _tx_thread_preempted_map_active & (~(priority_bit));
1057 }
1058 #endif
1059 }
1060 }
1061 #endif
1062
1063 #ifndef TX_MISRA_ENABLE
1064
1065 #ifdef TX_THREAD_ENABLE_PERFORMANCE_INFO
1066
1067 /* Is the execute pointer different? */
1068 if (_tx_thread_performance_execute_log[_tx_thread_performance__execute_log_index] != _tx_thread_execute_ptr)
1069 {
1070
1071 /* Move to next entry. */
1072 _tx_thread_performance__execute_log_index++;
1073
1074 /* Check for wrap condition. */
1075 if (_tx_thread_performance__execute_log_index >= TX_THREAD_EXECUTE_LOG_SIZE)
1076 {
1077
1078 /* Set the index to the beginning. */
1079 _tx_thread_performance__execute_log_index = ((UINT) 0);
1080 }
1081
1082 /* Log the new execute pointer. */
1083 _tx_thread_performance_execute_log[_tx_thread_performance__execute_log_index] = _tx_thread_execute_ptr;
1084 }
1085 #endif
1086
1087 #ifdef TX_ENABLE_EVENT_TRACE
1088
1089 /* Check that the event time stamp is unchanged. A different
1090 timestamp means that a later event wrote over the thread
1091 suspend event. In that case, do nothing here. */
1092 if (entry_ptr != TX_NULL)
1093 {
1094
1095 /* Is the timestamp the same? */
1096 if (time_stamp == entry_ptr -> tx_trace_buffer_entry_time_stamp)
1097 {
1098
1099 /* Timestamp is the same, set the "next thread pointer" to the new value of the
1100 next thread to execute. This can be used by the trace analysis tool to keep
1101 track of next thread execution. */
1102 entry_ptr -> tx_trace_buffer_entry_information_field_4 = TX_POINTER_TO_ULONG_CONVERT(_tx_thread_execute_ptr);
1103 }
1104 }
1105 #endif
1106
1107 /* Determine if preemption should take place. This is only possible if the current thread pointer is
1108 not the same as the execute thread pointer AND the system state and preempt disable flags are clear. */
1109 TX_THREAD_SYSTEM_RETURN_CHECK(combined_flags)
1110 if (combined_flags == ((ULONG) 0))
1111 {
1112
1113 #ifdef TX_THREAD_ENABLE_PERFORMANCE_INFO
1114
1115 /* No, there is another thread ready to run and will be scheduled upon return. */
1116 _tx_thread_performance_non_idle_return_count++;
1117 #endif
1118
1119 /* Preemption is needed - return to the system! */
1120 _tx_thread_system_return();
1121 }
1122
1123 /* Return to caller. */
1124 return;
1125 #endif
1126 }
1127
1128 #ifdef TX_THREAD_ENABLE_PERFORMANCE_INFO
1129
1130 /* Is the execute pointer different? */
1131 if (_tx_thread_performance_execute_log[_tx_thread_performance__execute_log_index] != _tx_thread_execute_ptr)
1132 {
1133
1134 /* Move to next entry. */
1135 _tx_thread_performance__execute_log_index++;
1136
1137 /* Check for wrap condition. */
1138 if (_tx_thread_performance__execute_log_index >= TX_THREAD_EXECUTE_LOG_SIZE)
1139 {
1140
1141 /* Set the index to the beginning. */
1142 _tx_thread_performance__execute_log_index = ((UINT) 0);
1143 }
1144
1145 /* Log the new execute pointer. */
1146 _tx_thread_performance_execute_log[_tx_thread_performance__execute_log_index] = _tx_thread_execute_ptr;
1147 }
1148 #endif
1149
1150 #ifdef TX_ENABLE_EVENT_TRACE
1151
1152 /* Check that the event time stamp is unchanged. A different
1153 timestamp means that a later event wrote over the thread
1154 suspend event. In that case, do nothing here. */
1155 if (entry_ptr != TX_NULL)
1156 {
1157
1158 /* Is the timestamp the same? */
1159 if (time_stamp == entry_ptr -> tx_trace_buffer_entry_time_stamp)
1160 {
1161
1162 /* Timestamp is the same, set the "next thread pointer" to the new value of the
1163 next thread to execute. This can be used by the trace analysis tool to keep
1164 track of next thread execution. */
1165 #ifdef TX_MISRA_ENABLE
1166 entry_ptr -> tx_trace_buffer_entry_info_4 = TX_POINTER_TO_ULONG_CONVERT(_tx_thread_execute_ptr);
1167 #else
1168 entry_ptr -> tx_trace_buffer_entry_information_field_4 = TX_POINTER_TO_ULONG_CONVERT(_tx_thread_execute_ptr);
1169 #endif
1170 }
1171 }
1172 #endif
1173
1174 /* Determine if a preemption condition is present. */
1175 if (current_thread != _tx_thread_execute_ptr)
1176 {
1177
1178 #ifdef TX_ENABLE_STACK_CHECKING
1179
1180 /* Pickup the next execute pointer. */
1181 thread_ptr = _tx_thread_execute_ptr;
1182
1183 /* Check this thread's stack. */
1184 TX_THREAD_STACK_CHECK(thread_ptr)
1185 #endif
1186
1187 /* Determine if preemption should take place. This is only possible if the current thread pointer is
1188 not the same as the execute thread pointer AND the system state and preempt disable flags are clear. */
1189 TX_THREAD_SYSTEM_RETURN_CHECK(combined_flags)
1190 if (combined_flags == ((ULONG) 0))
1191 {
1192
1193 #ifdef TX_THREAD_ENABLE_PERFORMANCE_INFO
1194
1195 /* Determine if an idle system return is present. */
1196 if (_tx_thread_execute_ptr == TX_NULL)
1197 {
1198
1199 /* Yes, increment the return to idle return count. */
1200 _tx_thread_performance_idle_return_count++;
1201 }
1202 else
1203 {
1204
1205 /* No, there is another thread ready to run and will be scheduled upon return. */
1206 _tx_thread_performance_non_idle_return_count++;
1207 }
1208 #endif
1209
1210 /* Preemption is needed - return to the system! */
1211 _tx_thread_system_return();
1212 }
1213 }
1214
1215 /* Return to caller. */
1216 return;
1217 }
1218 #endif
1219
1220