1 /**************************************************************************/
2 /* */
3 /* Copyright (c) Microsoft Corporation. All rights reserved. */
4 /* */
5 /* This software is licensed under the Microsoft Software License */
6 /* Terms for Microsoft Azure RTOS. Full text of the license can be */
7 /* found in the LICENSE file at https://aka.ms/AzureRTOS_EULA */
8 /* and in the root directory of this software. */
9 /* */
10 /**************************************************************************/
11
12
13 /**************************************************************************/
14 /**************************************************************************/
15 /** */
16 /** ThreadX Component */
17 /** */
18 /** Thread */
19 /** */
20 /**************************************************************************/
21 /**************************************************************************/
22
23 #define TX_SOURCE_CODE
24 #define TX_THREAD_SMP_SOURCE_CODE
25
26
27 /* Include necessary system files. */
28
29 #include "tx_api.h"
30 #include "tx_timer.h"
31 #include "tx_thread.h"
32 #include "tx_trace.h"
33
34
35 /**************************************************************************/
36 /* */
37 /* FUNCTION RELEASE */
38 /* */
39 /* _tx_thread_time_slice PORTABLE SMP */
40 /* 6.1 */
41 /* AUTHOR */
42 /* */
43 /* William E. Lamie, Microsoft Corporation */
44 /* */
45 /* DESCRIPTION */
46 /* */
47 /* This function moves the currently executing thread to the end of */
48 /* the threads ready at the same priority level as a result of a */
49 /* time-slice interrupt. If no other thread of the same priority is */
50 /* ready, this function simply returns. */
51 /* */
52 /* INPUT */
53 /* */
54 /* None */
55 /* */
56 /* OUTPUT */
57 /* */
58 /* None */
59 /* */
60 /* CALLS */
61 /* */
62 /* _tx_thread_smp_rebalance_execute_list Rebalance the execution list */
63 /* */
64 /* CALLED BY */
65 /* */
66 /* _tx_timer_interrupt Timer interrupt handling */
67 /* */
68 /* RELEASE HISTORY */
69 /* */
70 /* DATE NAME DESCRIPTION */
71 /* */
72 /* 09-30-2020 William E. Lamie Initial Version 6.1 */
73 /* */
74 /**************************************************************************/
_tx_thread_time_slice(VOID)75 VOID _tx_thread_time_slice(VOID)
76 {
77
78 ULONG core_index, current_core;
79 UINT priority;
80 TX_THREAD *thread_ptr;
81 TX_THREAD *next_thread;
82 TX_THREAD *previous_thread;
83 TX_THREAD *head_ptr;
84 TX_THREAD *tail_ptr;
85 UINT loop_finished;
86 UINT rebalance;
87 ULONG excluded;
88 #ifdef TX_ENABLE_EVENT_TRACE
89 ULONG system_state;
90 UINT preempt_disable;
91 #endif
92
93
94 /* Quick check for expiration. */
95 #if TX_THREAD_SMP_MAX_CORES == 1
96 if (_tx_timer_time_slice[0] != 0)
97 {
98 #endif
99 #if TX_THREAD_SMP_MAX_CORES == 2
100 if ((_tx_timer_time_slice[0] != ((ULONG) 0)) || (_tx_timer_time_slice[1] != ((ULONG) 0)))
101 {
102 #endif
103 #if TX_THREAD_SMP_MAX_CORES == 3
104 if ((_tx_timer_time_slice[0] != ((ULONG) 0)) || (_tx_timer_time_slice[1] != ((ULONG) 0)) || (_tx_timer_time_slice[2] != ((ULONG) 0)))
105 {
106 #endif
107 #if TX_THREAD_SMP_MAX_CORES == 4
108 if ((_tx_timer_time_slice[0] != ((ULONG) 0)) || (_tx_timer_time_slice[1] != ((ULONG) 0)) || (_tx_timer_time_slice[2] != ((ULONG) 0)) || (_tx_timer_time_slice[3] != ((ULONG) 0)))
109 {
110 #endif
111
112 /* Initialize the rebalance flag to false. */
113 rebalance = TX_FALSE;
114
115 /* Get the core index. */
116 current_core = TX_SMP_CORE_ID;
117
118 /* Loop to process all time-slices. */
119
120 #ifndef TX_THREAD_SMP_DYNAMIC_CORE_MAX
121
122 for (core_index = ((ULONG) 0); core_index < ((ULONG) TX_THREAD_SMP_MAX_CORES); core_index++)
123 #else
124
125 for (core_index = ((ULONG) 0); core_index < _tx_thread_smp_max_cores; core_index++)
126 #endif
127 {
128
129 /* Determine if there is a time-slice active on this core. */
130 if (_tx_timer_time_slice[core_index] != ((ULONG) 0))
131 {
132
133 /* Time-slice is active, decrement it for this core. */
134 _tx_timer_time_slice[core_index]--;
135
136 /* Has the time-slice expired? */
137 if (_tx_timer_time_slice[core_index] == ((ULONG) 0))
138 {
139
140 /* Yes, time-slice on this core has expired. */
141
142 /* Pickup the current thread pointer. */
143 thread_ptr = _tx_thread_current_ptr[core_index];
144
145 /* Make sure the thread is still active, i.e. not suspended. */
146 if ((thread_ptr != TX_NULL) && (thread_ptr -> tx_thread_state == TX_READY) && (thread_ptr -> tx_thread_time_slice != ((ULONG) 0)))
147 {
148
149 /* Yes, thread is still active and time-slice has expired. */
150
151 /* Setup a fresh time-slice for the thread. */
152 thread_ptr -> tx_thread_time_slice = thread_ptr -> tx_thread_new_time_slice;
153
154 /* Reset the actual time-slice variable. */
155 _tx_timer_time_slice[core_index] = thread_ptr -> tx_thread_time_slice;
156
157 #ifdef TX_THREAD_SMP_DEBUG_ENABLE
158
159 /* Debug entry. */
160 _tx_thread_smp_debug_entry_insert(10, 0, thread_ptr);
161 #endif
162
163 #ifdef TX_ENABLE_STACK_CHECKING
164
165 /* Check this thread's stack. */
166 TX_THREAD_STACK_CHECK(thread_ptr)
167 #endif
168
169 #ifdef TX_THREAD_ENABLE_PERFORMANCE_INFO
170
171 /* Increment the thread's time-slice counter. */
172 thread_ptr -> tx_thread_performance_time_slice_count++;
173
174 /* Increment the total number of thread time-slice operations. */
175 _tx_thread_performance_time_slice_count++;
176 #endif
177
178 /* Setup the priority. */
179 priority = thread_ptr -> tx_thread_priority;
180
181 /* Determine if preemption-threshold is set. If so, don't time-slice. */
182 if (priority == thread_ptr -> tx_thread_preempt_threshold)
183 {
184
185 /* Preemption-threshold is not set. */
186
187 /* Pickup the next thread. */
188 next_thread = thread_ptr -> tx_thread_ready_next;
189
190 /* Pickup the head of the list. */
191 head_ptr = _tx_thread_priority_list[priority];
192
193 /* Pickup the list tail. */
194 tail_ptr = head_ptr -> tx_thread_ready_previous;
195
196 /* Determine if this thread is not the tail pointer. */
197 if (thread_ptr != tail_ptr)
198 {
199
200 /* Not the tail pointer, this thread must be moved to the end of the ready list. */
201
202 /* Determine if this thread is at the head of the list. */
203 if (head_ptr == thread_ptr)
204 {
205
206 /* Simply move the head pointer to put this thread at the end of the ready list at this priority. */
207 _tx_thread_priority_list[priority] = next_thread;
208 }
209 else
210 {
211
212 /* Now we need to remove this thread from its current position and place it at the end of the list. */
213
214 /* Pickup the previous thread pointer. */
215 previous_thread = thread_ptr -> tx_thread_ready_previous;
216
217 /* Remove the thread from the ready list. */
218 next_thread -> tx_thread_ready_previous = previous_thread;
219 previous_thread -> tx_thread_ready_next = next_thread;
220
221 /* Insert the thread at the end of the list. */
222 tail_ptr -> tx_thread_ready_next = thread_ptr;
223 head_ptr -> tx_thread_ready_previous = thread_ptr;
224 thread_ptr -> tx_thread_ready_previous = tail_ptr;
225 thread_ptr -> tx_thread_ready_next = head_ptr;
226 }
227
228 /* Make sure the current core execute pointer is still this thread. If not, a higher priority thread has already
229 preempted it either from another ISR or from the timer processing. */
230 if (_tx_thread_execute_ptr[core_index] != thread_ptr)
231 {
232
233 /* Set the rebalance flag. */
234 rebalance = TX_TRUE;
235 }
236
237 /* Determine if the rebalance flag has been set already. If so, don't bother trying to update the
238 execute list from this routine. */
239 if (rebalance == TX_FALSE)
240 {
241
242 /* Set the loop finished flag to false. */
243 loop_finished = TX_FALSE;
244
245 /* Determine if there is a thread at the same priority that isn't currently executing. */
246 do
247 {
248
249 /* Isolate the exclusion for this core. */
250 excluded = (next_thread -> tx_thread_smp_cores_excluded >> core_index) & ((ULONG) 1);
251
252 /* Determine if the next thread has preemption-threshold set. */
253 if (next_thread -> tx_thread_preempt_threshold < next_thread -> tx_thread_priority)
254 {
255
256 /* Set the rebalance flag. */
257 rebalance = TX_TRUE;
258
259 /* Get out of the loop. */
260 loop_finished = TX_TRUE;
261 }
262
263 /* Determine if the next thread is excluded from running on this core. */
264 else if (excluded == ((ULONG) 1))
265 {
266
267 /* Set the rebalance flag. */
268 rebalance = TX_TRUE;
269
270 /* Get out of the loop. */
271 loop_finished = TX_TRUE;
272 }
273 else
274 {
275
276 /* Is the next thread not scheduled */
277 if (next_thread != _tx_thread_execute_ptr[next_thread -> tx_thread_smp_core_mapped])
278 {
279
280 /* Remember this index in the thread control block. */
281 next_thread -> tx_thread_smp_core_mapped = core_index;
282
283 /* Setup the entry in the execution list. */
284 _tx_thread_execute_ptr[core_index] = next_thread;
285
286 #ifdef TX_THREAD_SMP_INTER_CORE_INTERRUPT
287
288 /* Determine if we need to preempt the core. */
289 if (core_index != current_core)
290 {
291
292 /* Preempt the mapped thread. */
293 _tx_thread_smp_core_preempt(core_index);
294 }
295 #endif
296 /* Get out of the loop. */
297 loop_finished = TX_TRUE;
298 }
299 }
300
301 /* Is the loop fininshed? */
302 if (loop_finished == TX_TRUE)
303 {
304
305 /* Yes, break out of the loop. */
306 break;
307 }
308
309 /* Move to the next thread at this priority. */
310 next_thread = next_thread -> tx_thread_ready_next;
311
312 } while (next_thread != thread_ptr);
313 }
314 }
315
316 #ifdef TX_THREAD_SMP_DEBUG_ENABLE
317
318 /* Debug entry. */
319 _tx_thread_smp_debug_entry_insert(11, 0, thread_ptr);
320 #endif
321 }
322 }
323 }
324 }
325 }
326
327 /* Determine if rebalance was set. */
328 if (rebalance == TX_TRUE)
329 {
330
331 /* Call the rebalance routine. This routine maps cores and ready threads. */
332 _tx_thread_smp_rebalance_execute_list(current_core);
333 }
334
335 #ifdef TX_ENABLE_EVENT_TRACE
336
337 /* Pickup the volatile information. */
338 system_state = TX_THREAD_GET_SYSTEM_STATE();
339 preempt_disable = _tx_thread_preempt_disable;
340
341 /* Insert this event into the trace buffer. */
342 TX_TRACE_IN_LINE_INSERT(TX_TRACE_TIME_SLICE, _tx_thread_execute_ptr[0], system_state, preempt_disable, TX_POINTER_TO_ULONG_CONVERT(&thread_ptr), TX_TRACE_INTERNAL_EVENTS)
343 #endif
344
345 #if TX_THREAD_SMP_MAX_CORES == 1
346 }
347 #endif
348 #if TX_THREAD_SMP_MAX_CORES == 2
349 }
350 #endif
351 #if TX_THREAD_SMP_MAX_CORES == 3
352 }
353 #endif
354 #if TX_THREAD_SMP_MAX_CORES == 4
355 }
356 #endif
357 }
358
359