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 #ifndef TX_NO_TIMER
25
26 /* Include necessary system files. */
27
28 #include "tx_api.h"
29 #include "tx_timer.h"
30 #include "tx_thread.h"
31 #include "tx_trace.h"
32
33
34 /**************************************************************************/
35 /* */
36 /* FUNCTION RELEASE */
37 /* */
38 /* _tx_thread_time_slice PORTABLE C */
39 /* 6.1 */
40 /* AUTHOR */
41 /* */
42 /* William E. Lamie, Microsoft Corporation */
43 /* */
44 /* DESCRIPTION */
45 /* */
46 /* This function moves the currently executing thread to the end of */
47 /* the threads ready at the same priority level as a result of a */
48 /* time-slice interrupt. If no other thread of the same priority is */
49 /* ready, this function simply returns. */
50 /* */
51 /* INPUT */
52 /* */
53 /* None */
54 /* */
55 /* OUTPUT */
56 /* */
57 /* None */
58 /* */
59 /* CALLS */
60 /* */
61 /* None */
62 /* */
63 /* CALLED BY */
64 /* */
65 /* _tx_timer_interrupt Timer interrupt handling */
66 /* */
67 /* RELEASE HISTORY */
68 /* */
69 /* DATE NAME DESCRIPTION */
70 /* */
71 /* 05-19-2020 William E. Lamie Initial Version 6.0 */
72 /* 09-30-2020 Scott Larson Modified comment(s), and */
73 /* opt out of function when */
74 /* TX_NO_TIMER is defined, */
75 /* resulting in version 6.1 */
76 /* */
77 /**************************************************************************/
_tx_thread_time_slice(VOID)78 VOID _tx_thread_time_slice(VOID)
79 {
80
81 TX_INTERRUPT_SAVE_AREA
82
83 TX_THREAD *thread_ptr;
84 #ifdef TX_ENABLE_STACK_CHECKING
85 TX_THREAD *next_thread_ptr;
86 #endif
87 #ifdef TX_ENABLE_EVENT_TRACE
88 ULONG system_state;
89 UINT preempt_disable;
90 #endif
91
92 /* Pickup thread pointer. */
93 TX_THREAD_GET_CURRENT(thread_ptr)
94
95 #ifdef TX_ENABLE_STACK_CHECKING
96
97 /* Check this thread's stack. */
98 TX_THREAD_STACK_CHECK(thread_ptr)
99
100 /* Set the next thread pointer to NULL. */
101 next_thread_ptr = TX_NULL;
102 #endif
103
104 /* Lockout interrupts while the time-slice is evaluated. */
105 TX_DISABLE
106
107 /* Clear the expired time-slice flag. */
108 _tx_timer_expired_time_slice = TX_FALSE;
109
110 /* Make sure the thread pointer is valid. */
111 if (thread_ptr != TX_NULL)
112 {
113
114 /* Make sure the thread is still active, i.e. not suspended. */
115 if (thread_ptr -> tx_thread_state == TX_READY)
116 {
117
118 /* Setup a fresh time-slice for the thread. */
119 thread_ptr -> tx_thread_time_slice = thread_ptr -> tx_thread_new_time_slice;
120
121 /* Reset the actual time-slice variable. */
122 _tx_timer_time_slice = thread_ptr -> tx_thread_time_slice;
123
124 /* Determine if there is another thread at the same priority and preemption-threshold
125 is not set. Preemption-threshold overrides time-slicing. */
126 if (thread_ptr -> tx_thread_ready_next != thread_ptr)
127 {
128
129 /* Check to see if preemption-threshold is not being used. */
130 if (thread_ptr -> tx_thread_priority == thread_ptr -> tx_thread_preempt_threshold)
131 {
132
133 /* Preemption-threshold is not being used by this thread. */
134
135 /* There is another thread at this priority, make it the highest at
136 this priority level. */
137 _tx_thread_priority_list[thread_ptr -> tx_thread_priority] = thread_ptr -> tx_thread_ready_next;
138
139 /* Designate the highest priority thread as the one to execute. Don't use this
140 thread's priority as an index just in case a higher priority thread is now
141 ready! */
142 _tx_thread_execute_ptr = _tx_thread_priority_list[_tx_thread_highest_priority];
143
144 #ifdef TX_THREAD_ENABLE_PERFORMANCE_INFO
145
146 /* Increment the thread's time-slice counter. */
147 thread_ptr -> tx_thread_performance_time_slice_count++;
148
149 /* Increment the total number of thread time-slice operations. */
150 _tx_thread_performance_time_slice_count++;
151 #endif
152
153
154 #ifdef TX_ENABLE_STACK_CHECKING
155
156 /* Pickup the next execute pointer. */
157 next_thread_ptr = _tx_thread_execute_ptr;
158 #endif
159 }
160 }
161 }
162 }
163
164 #ifdef TX_ENABLE_EVENT_TRACE
165
166 /* Pickup the volatile information. */
167 system_state = TX_THREAD_GET_SYSTEM_STATE();
168 preempt_disable = _tx_thread_preempt_disable;
169
170 /* Insert this event into the trace buffer. */
171 TX_TRACE_IN_LINE_INSERT(TX_TRACE_TIME_SLICE, _tx_thread_execute_ptr, system_state, preempt_disable, TX_POINTER_TO_ULONG_CONVERT(&thread_ptr), TX_TRACE_INTERNAL_EVENTS)
172 #endif
173
174 /* Restore previous interrupt posture. */
175 TX_RESTORE
176
177 #ifdef TX_ENABLE_STACK_CHECKING
178
179 /* Determine if there is a next thread pointer to perform stack checking on. */
180 if (next_thread_ptr != TX_NULL)
181 {
182
183 /* Yes, check this thread's stack. */
184 TX_THREAD_STACK_CHECK(next_thread_ptr)
185 }
186 #endif
187 }
188
189 #endif
190