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
25
26 /* Include necessary system files. */
27
28 #include "tx_api.h"
29 #include "tx_trace.h"
30 #include "tx_thread.h"
31
32
33 /**************************************************************************/
34 /* */
35 /* FUNCTION RELEASE */
36 /* */
37 /* _tx_thread_preemption_change PORTABLE C */
38 /* 6.1 */
39 /* AUTHOR */
40 /* */
41 /* William E. Lamie, Microsoft Corporation */
42 /* */
43 /* DESCRIPTION */
44 /* */
45 /* This function processes preemption-threshold change requests. The */
46 /* previous preemption is returned to the caller. If the new request */
47 /* allows a higher priority thread to execute, preemption takes place */
48 /* inside of this function. */
49 /* */
50 /* INPUT */
51 /* */
52 /* thread_ptr Pointer to thread */
53 /* new_threshold New preemption threshold */
54 /* old_threshold Old preemption threshold */
55 /* */
56 /* OUTPUT */
57 /* */
58 /* status Service return status */
59 /* */
60 /* CALLS */
61 /* */
62 /* _tx_thread_system_preempt_check Check for preemption */
63 /* */
64 /* CALLED BY */
65 /* */
66 /* Application Code */
67 /* */
68 /* RELEASE HISTORY */
69 /* */
70 /* DATE NAME DESCRIPTION */
71 /* */
72 /* 05-19-2020 William E. Lamie Initial Version 6.0 */
73 /* 09-30-2020 Yuxin Zhou Modified comment(s), */
74 /* resulting in version 6.1 */
75 /* */
76 /**************************************************************************/
_tx_thread_preemption_change(TX_THREAD * thread_ptr,UINT new_threshold,UINT * old_threshold)77 UINT _tx_thread_preemption_change(TX_THREAD *thread_ptr, UINT new_threshold, UINT *old_threshold)
78 {
79
80 TX_INTERRUPT_SAVE_AREA
81
82 #ifndef TX_DISABLE_PREEMPTION_THRESHOLD
83 ULONG priority_bit;
84 #if TX_MAX_PRIORITIES > 32
85 UINT map_index;
86 #endif
87 #endif
88 UINT status;
89
90
91 /* Default status to success. */
92 status = TX_SUCCESS;
93
94 #ifdef TX_DISABLE_PREEMPTION_THRESHOLD
95
96 /* Only allow 0 (disable all preemption) and returning preemption-threshold to the
97 current thread priority if preemption-threshold is disabled. All other threshold
98 values are converted to 0. */
99 if (thread_ptr -> tx_thread_user_priority != new_threshold)
100 {
101
102 /* Is the new threshold zero? */
103 if (new_threshold != ((UINT) 0))
104 {
105
106 /* Convert the new threshold to disable all preemption, since preemption-threshold is
107 not supported. */
108 new_threshold = ((UINT) 0);
109 }
110 }
111 #endif
112
113 /* Lockout interrupts while the thread is being resumed. */
114 TX_DISABLE
115
116 /* If trace is enabled, insert this event into the trace buffer. */
117 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)
118
119 /* Log this kernel call. */
120 TX_EL_THREAD_PREEMPTION_CHANGE_INSERT
121
122 /* Determine if the new threshold is greater than the current user priority. */
123 if (new_threshold > thread_ptr -> tx_thread_user_priority)
124 {
125
126 /* Return error. */
127 status = TX_THRESH_ERROR;
128 }
129 else
130 {
131
132 #ifndef TX_DISABLE_PREEMPTION_THRESHOLD
133
134 /* Determine if the new threshold is the same as the priority. */
135 if (thread_ptr -> tx_thread_user_priority == new_threshold)
136 {
137
138 /* Determine if this thread is at the head of the list. */
139 if (_tx_thread_priority_list[thread_ptr -> tx_thread_priority] == thread_ptr)
140 {
141
142 #if TX_MAX_PRIORITIES > 32
143
144 /* Calculate the index into the bit map array. */
145 map_index = (thread_ptr -> tx_thread_priority)/((UINT) 32);
146 #endif
147
148 /* Yes, this thread is at the front of the list. Make sure
149 the preempted bit is cleared for this thread. */
150 TX_MOD32_BIT_SET(thread_ptr -> tx_thread_priority, priority_bit)
151 _tx_thread_preempted_maps[MAP_INDEX] = _tx_thread_preempted_maps[MAP_INDEX] & (~(priority_bit));
152
153 #if TX_MAX_PRIORITIES > 32
154
155 /* Determine if there are any other bits set in this preempt map. */
156 if (_tx_thread_preempted_maps[MAP_INDEX] == ((ULONG) 0))
157 {
158
159 /* No, clear the active bit to signify this preempt map has nothing set. */
160 TX_DIV32_BIT_SET(thread_ptr -> tx_thread_priority, priority_bit)
161 _tx_thread_preempted_map_active = _tx_thread_preempted_map_active & (~(priority_bit));
162 }
163 #endif
164 }
165 }
166 #endif
167
168 /* Return the user's preemption-threshold. */
169 *old_threshold = thread_ptr -> tx_thread_user_preempt_threshold;
170
171 /* Setup the new threshold. */
172 thread_ptr -> tx_thread_user_preempt_threshold = new_threshold;
173
174 /* Determine if the new threshold represents a higher priority than the priority inheritance threshold. */
175 if (new_threshold < thread_ptr -> tx_thread_inherit_priority)
176 {
177
178 /* Update the actual preemption-threshold with the new threshold. */
179 thread_ptr -> tx_thread_preempt_threshold = new_threshold;
180 }
181 else
182 {
183
184 /* Update the actual preemption-threshold with the priority inheritance. */
185 thread_ptr -> tx_thread_preempt_threshold = thread_ptr -> tx_thread_inherit_priority;
186 }
187
188 /* Is the thread priority less than the current highest priority? If not, no preemption is required. */
189 if (_tx_thread_highest_priority < thread_ptr -> tx_thread_priority)
190 {
191
192 /* Is the new thread preemption-threshold less than the current highest priority? If not, no preemption is required. */
193 if (_tx_thread_highest_priority < new_threshold)
194 {
195
196 /* If the current execute pointer is the same at this thread, preemption needs to take place. */
197 if (_tx_thread_execute_ptr == thread_ptr)
198 {
199
200 /* Preemption needs to take place. */
201
202 #ifndef TX_DISABLE_PREEMPTION_THRESHOLD
203
204 /* Determine if this thread has preemption threshold set. */
205 if (thread_ptr -> tx_thread_preempt_threshold != thread_ptr -> tx_thread_priority)
206 {
207
208 #if TX_MAX_PRIORITIES > 32
209
210 /* Calculate the index into the bit map array. */
211 map_index = (thread_ptr -> tx_thread_priority)/((UINT) 32);
212
213 /* Set the active bit to remember that the preempt map has something set. */
214 TX_DIV32_BIT_SET(thread_ptr -> tx_thread_priority, priority_bit)
215 _tx_thread_preempted_map_active = _tx_thread_preempted_map_active | priority_bit;
216 #endif
217
218 /* Remember that this thread was preempted by a thread above the thread's threshold. */
219 TX_MOD32_BIT_SET(thread_ptr -> tx_thread_priority, priority_bit)
220 _tx_thread_preempted_maps[MAP_INDEX] = _tx_thread_preempted_maps[MAP_INDEX] | priority_bit;
221 }
222 #endif
223
224 #ifdef TX_THREAD_ENABLE_PERFORMANCE_INFO
225
226 /* Determine if the caller is an interrupt or from a thread. */
227 if (TX_THREAD_GET_SYSTEM_STATE() == ((ULONG) 0))
228 {
229
230 /* Caller is a thread, so this is a solicited preemption. */
231 _tx_thread_performance_solicited_preemption_count++;
232
233 /* Increment the thread's solicited preemption counter. */
234 thread_ptr -> tx_thread_performance_solicited_preemption_count++;
235 }
236
237 /* Remember the thread that preempted this thread. */
238 thread_ptr -> tx_thread_performance_last_preempting_thread = _tx_thread_priority_list[_tx_thread_highest_priority];
239
240 /* Is the execute pointer different? */
241 if (_tx_thread_performance_execute_log[_tx_thread_performance__execute_log_index] != _tx_thread_execute_ptr)
242 {
243
244 /* Move to next entry. */
245 _tx_thread_performance__execute_log_index++;
246
247 /* Check for wrap condition. */
248 if (_tx_thread_performance__execute_log_index >= TX_THREAD_EXECUTE_LOG_SIZE)
249 {
250
251 /* Set the index to the beginning. */
252 _tx_thread_performance__execute_log_index = ((UINT) 0);
253 }
254
255 /* Log the new execute pointer. */
256 _tx_thread_performance_execute_log[_tx_thread_performance__execute_log_index] = _tx_thread_execute_ptr;
257 }
258 #endif
259
260 /* Setup the highest priority thread to execute. */
261 _tx_thread_execute_ptr = _tx_thread_priority_list[_tx_thread_highest_priority];
262
263 /* Restore interrupts. */
264 TX_RESTORE
265
266 /* Check for preemption. */
267 _tx_thread_system_preempt_check();
268
269 /* Disable interrupts. */
270 TX_DISABLE
271 }
272 }
273 }
274 }
275
276 /* Restore interrupts. */
277 TX_RESTORE
278
279 /* Return completion status. */
280 return(status);
281 }
282
283