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_trace.h"
31 #include "tx_initialize.h"
32 #include "tx_thread.h"
33
34
35 /**************************************************************************/
36 /* */
37 /* FUNCTION RELEASE */
38 /* */
39 /* _tx_thread_preemption_change PORTABLE SMP */
40 /* 6.1 */
41 /* AUTHOR */
42 /* */
43 /* William E. Lamie, Microsoft Corporation */
44 /* */
45 /* DESCRIPTION */
46 /* */
47 /* This function processes preemption-threshold change requests. The */
48 /* previous preemption is returned to the caller. If the new request */
49 /* allows a higher priority thread to execute, preemption takes place */
50 /* inside of this function. */
51 /* */
52 /* INPUT */
53 /* */
54 /* thread_ptr Pointer to thread */
55 /* new_threshold New preemption-threshold */
56 /* old_threshold Old preemption-threshold */
57 /* */
58 /* OUTPUT */
59 /* */
60 /* status Service return status */
61 /* */
62 /* CALLS */
63 /* */
64 /* _tx_thread_smp_rebalance_execute_list Rebalance the execution list */
65 /* _tx_thread_system_preempt_check Check for preemption */
66 /* */
67 /* CALLED BY */
68 /* */
69 /* Application Code */
70 /* */
71 /* RELEASE HISTORY */
72 /* */
73 /* DATE NAME DESCRIPTION */
74 /* */
75 /* 09-30-2020 William E. Lamie Initial Version 6.1 */
76 /* */
77 /**************************************************************************/
_tx_thread_preemption_change(TX_THREAD * thread_ptr,UINT new_threshold,UINT * old_threshold)78 UINT _tx_thread_preemption_change(TX_THREAD *thread_ptr, UINT new_threshold, UINT *old_threshold)
79 {
80
81 TX_INTERRUPT_SAVE_AREA
82
83 UINT core_index;
84
85 #ifndef TX_DISABLE_PREEMPTION_THRESHOLD
86 ULONG priority_bit;
87 UINT base_priority;
88 UINT priority_bit_set;
89 ULONG priority_map;
90 UINT next_preempted;
91 TX_THREAD *preempted_thread;
92 #if TX_MAX_PRIORITIES > 32
93 UINT map_index;
94 #endif
95 #endif
96 UINT status;
97
98
99 #ifdef TX_DISABLE_PREEMPTION_THRESHOLD
100
101 /* Only allow 0 (disable all preemption) and returning preemption-threshold to the
102 current thread priority if preemption-threshold is disabled. All other threshold
103 values are converted to 0. */
104 if (new_threshold < thread_ptr -> tx_thread_user_priority)
105 {
106
107 /* Is the new threshold zero? */
108 if (new_threshold != ((UINT) 0))
109 {
110
111 /* Convert the new threshold to disable all preemption, since preemption-threshold is
112 not supported. */
113 new_threshold = ((UINT) 0);
114 }
115 }
116 #endif
117
118 /* Default status to success. */
119 status = TX_SUCCESS;
120
121 /* Lockout interrupts while the thread is being resumed. */
122 TX_DISABLE
123
124 /* If trace is enabled, insert this event into the trace buffer. */
125 TX_TRACE_IN_LINE_INSERT(TX_TRACE_THREAD_PREEMPTION_CHANGE, thread_ptr, new_threshold, thread_ptr -> tx_thread_preempt_threshold, thread_ptr -> tx_thread_state, TX_TRACE_THREAD_EVENTS)
126
127 /* Log this kernel call. */
128 TX_EL_THREAD_PREEMPTION_CHANGE_INSERT
129
130 /* Determine if the new threshold is greater than the current user priority. */
131 if (new_threshold > thread_ptr -> tx_thread_user_priority)
132 {
133
134 /* Restore interrupts. */
135 TX_RESTORE
136
137 /* Return error. */
138 status = TX_THRESH_ERROR;
139 }
140 else
141 {
142
143 /* Return the user's preemption-threshold. */
144 *old_threshold = thread_ptr -> tx_thread_user_preempt_threshold;
145
146 /* Setup the new threshold. */
147 thread_ptr -> tx_thread_user_preempt_threshold = new_threshold;
148
149 /* Determine if the new threshold represents a higher priority than the priority inheritance threshold. */
150 if (new_threshold < thread_ptr -> tx_thread_inherit_priority)
151 {
152
153 /* Update the actual preemption-threshold with the new threshold. */
154 thread_ptr -> tx_thread_preempt_threshold = new_threshold;
155 }
156 else
157 {
158
159 /* Update the actual preemption-threshold with the priority inheritance. */
160 thread_ptr -> tx_thread_preempt_threshold = thread_ptr -> tx_thread_inherit_priority;
161 }
162
163 /* Determine if the thread is ready and scheduled. */
164 if (thread_ptr -> tx_thread_state == TX_READY)
165 {
166
167 #ifndef TX_DISABLE_PREEMPTION_THRESHOLD
168
169 /* Determine if the new threshold is the same as the priority. */
170 if (thread_ptr -> tx_thread_user_priority == new_threshold)
171 {
172
173 /* Yes, preemption-threshold is being disabled. */
174
175 /* Determine if this thread was scheduled with preemption-threshold in force. */
176 if (_tx_thread_preemption_threshold_list[thread_ptr -> tx_thread_priority] == thread_ptr)
177 {
178
179 /* Clear the entry in the preempted list. */
180 _tx_thread_preemption_threshold_list[thread_ptr -> tx_thread_priority] = TX_NULL;
181
182 #if TX_MAX_PRIORITIES > 32
183
184 /* Calculate the index into the bit map array. */
185 map_index = (thread_ptr -> tx_thread_priority)/((UINT) 32);
186 #endif
187
188 /* Yes, this thread is at the front of the list. Make sure
189 the preempted bit is cleared for this thread. */
190 TX_MOD32_BIT_SET(thread_ptr -> tx_thread_priority, priority_bit)
191 _tx_thread_preempted_maps[MAP_INDEX] = _tx_thread_preempted_maps[MAP_INDEX] & (~(priority_bit));
192
193 #if TX_MAX_PRIORITIES > 32
194
195 /* Determine if there are any other bits set in this preempt map. */
196 if (_tx_thread_preempted_maps[MAP_INDEX] == ((ULONG) 0))
197 {
198
199 /* No, clear the active bit to signify this preempt map has nothing set. */
200 TX_DIV32_BIT_SET(thread_ptr -> tx_thread_priority, priority_bit)
201 _tx_thread_preempted_map_active = _tx_thread_preempted_map_active & (~(priority_bit));
202 }
203 #endif
204 }
205 }
206 #endif
207
208 /* Determine if this thread has global preemption disabled. */
209 if (thread_ptr == _tx_thread_preemption__threshold_scheduled)
210 {
211
212 /* Clear the global preemption disable flag. */
213 _tx_thread_preemption__threshold_scheduled = TX_NULL;
214
215 #ifndef TX_DISABLE_PREEMPTION_THRESHOLD
216
217 /* Calculate the first thread with preemption-threshold active. */
218 #if TX_MAX_PRIORITIES > 32
219 if (_tx_thread_preempted_map_active != ((ULONG) 0))
220 #else
221 if (_tx_thread_preempted_maps[0] != ((ULONG) 0))
222 #endif
223 {
224 #if TX_MAX_PRIORITIES > 32
225
226 /* Calculate the index to find the next highest priority thread ready for execution. */
227 priority_map = _tx_thread_preempted_map_active;
228
229 /* Calculate the lowest bit set in the priority map. */
230 TX_LOWEST_SET_BIT_CALCULATE(priority_map, map_index)
231
232 /* Calculate the base priority as well. */
233 base_priority = map_index * ((UINT) 32);
234 #else
235
236 /* Setup the base priority to zero. */
237 base_priority = ((UINT) 0);
238 #endif
239
240 /* Setup temporary preempted map. */
241 priority_map = _tx_thread_preempted_maps[MAP_INDEX];
242
243 /* Calculate the lowest bit set in the priority map. */
244 TX_LOWEST_SET_BIT_CALCULATE(priority_map, priority_bit_set)
245
246 /* Move priority bit set into priority bit. */
247 priority_bit = (ULONG) priority_bit_set;
248
249 /* Setup the highest priority preempted thread. */
250 next_preempted = base_priority + priority_bit;
251
252 /* Pickup the previously preempted thread. */
253 preempted_thread = _tx_thread_preemption_threshold_list[next_preempted];
254
255 /* Pickup the preempted thread. */
256 _tx_thread_preemption__threshold_scheduled = preempted_thread;
257 }
258 #endif
259 }
260
261 /* See if preemption needs to take place. */
262
263 #ifdef TX_THREAD_SMP_DEBUG_ENABLE
264
265 /* Debug entry. */
266 _tx_thread_smp_debug_entry_insert(12, 0, thread_ptr);
267 #endif
268
269 /* Pickup the index. */
270 core_index = TX_SMP_CORE_ID;
271
272 /* Call the rebalance routine. This routine maps cores and ready threads. */
273 _tx_thread_smp_rebalance_execute_list(core_index);
274
275 #ifdef TX_THREAD_SMP_DEBUG_ENABLE
276
277 /* Debug entry. */
278 _tx_thread_smp_debug_entry_insert(13, 0, thread_ptr);
279 #endif
280
281 /* Restore interrupts. */
282 TX_RESTORE
283
284 /* Check for preemption. */
285 _tx_thread_system_preempt_check();
286 }
287 else
288 {
289
290 /* Restore interrupts. */
291 TX_RESTORE
292 }
293 }
294
295 /* Return completion status. */
296 return(status);
297 }
298
299