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 /** Mutex */
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_thread.h"
30 #include "tx_mutex.h"
31
32
33 /**************************************************************************/
34 /* */
35 /* FUNCTION RELEASE */
36 /* */
37 /* _tx_mutex_priority_change PORTABLE C */
38 /* 6.1.6 */
39 /* AUTHOR */
40 /* */
41 /* William E. Lamie, Microsoft Corporation */
42 /* */
43 /* DESCRIPTION */
44 /* */
45 /* This function changes the priority of the specified thread for the */
46 /* priority inheritance option of the mutex service. */
47 /* */
48 /* INPUT */
49 /* */
50 /* thread_ptr Pointer to thread to suspend */
51 /* new_priority New thread priority */
52 /* */
53 /* OUTPUT */
54 /* */
55 /* None */
56 /* */
57 /* CALLS */
58 /* */
59 /* _tx_thread_system_resume Resume thread */
60 /* _tx_thread_system_ni_resume Non-interruptable resume thread */
61 /* _tx_thread_system_suspend Suspend thread */
62 /* _tx_thread_system_ni_suspend Non-interruptable suspend thread */
63 /* */
64 /* CALLED BY */
65 /* */
66 /* _tx_mutex_get Inherit priority */
67 /* _tx_mutex_put Restore previous priority */
68 /* */
69 /* RELEASE HISTORY */
70 /* */
71 /* DATE NAME DESCRIPTION */
72 /* */
73 /* 05-19-2020 William E. Lamie Initial Version 6.0 */
74 /* 09-30-2020 William E. Lamie Modified comment(s), and */
75 /* change thread state from */
76 /* TX_SUSPENDED to */
77 /* TX_PRIORITY_CHANGE before */
78 /* calling */
79 /* _tx_thread_system_suspend, */
80 /* resulting in version 6.1 */
81 /* 04-02-2021 Scott Larson Modified comments, fixed */
82 /* mapping current thread's */
83 /* priority rather than next, */
84 /* resulting in version 6.1.6 */
85 /* */
86 /**************************************************************************/
_tx_mutex_priority_change(TX_THREAD * thread_ptr,UINT new_priority)87 VOID _tx_mutex_priority_change(TX_THREAD *thread_ptr, UINT new_priority)
88 {
89
90 #ifndef TX_NOT_INTERRUPTABLE
91
92 TX_INTERRUPT_SAVE_AREA
93 #endif
94
95 TX_THREAD *execute_ptr;
96 TX_THREAD *next_execute_ptr;
97 UINT original_priority;
98 #ifndef TX_DISABLE_PREEMPTION_THRESHOLD
99 ULONG priority_bit;
100 #if TX_MAX_PRIORITIES > 32
101 UINT map_index;
102 #endif
103 #endif
104
105
106
107 #ifndef TX_NOT_INTERRUPTABLE
108
109 /* Lockout interrupts while the thread is being suspended. */
110 TX_DISABLE
111 #endif
112
113 /* Determine if this thread is currently ready. */
114 if (thread_ptr -> tx_thread_state != TX_READY)
115 {
116
117 /* Change thread priority to the new mutex priority-inheritance priority. */
118 thread_ptr -> tx_thread_priority = new_priority;
119
120 /* Determine how to setup the thread's preemption-threshold. */
121 if (thread_ptr -> tx_thread_user_preempt_threshold < new_priority)
122 {
123
124 /* Change thread preemption-threshold to the user's preemption-threshold. */
125 thread_ptr -> tx_thread_preempt_threshold = thread_ptr -> tx_thread_user_preempt_threshold;
126 }
127 else
128 {
129
130 /* Change the thread preemption-threshold to the new threshold. */
131 thread_ptr -> tx_thread_preempt_threshold = new_priority;
132 }
133
134 #ifndef TX_NOT_INTERRUPTABLE
135 /* Restore interrupts. */
136 TX_RESTORE
137 #endif
138 }
139 else
140 {
141
142 /* Pickup the next thread to execute. */
143 execute_ptr = _tx_thread_execute_ptr;
144
145 /* Save the original priority. */
146 original_priority = thread_ptr -> tx_thread_priority;
147
148 #ifdef TX_NOT_INTERRUPTABLE
149
150 /* Increment the preempt disable flag. */
151 _tx_thread_preempt_disable++;
152
153 /* Set the state to priority change. */
154 thread_ptr -> tx_thread_state = TX_PRIORITY_CHANGE;
155
156 /* Call actual non-interruptable thread suspension routine. */
157 _tx_thread_system_ni_suspend(thread_ptr, ((ULONG) 0));
158
159 /* At this point, the preempt disable flag is still set, so we still have
160 protection against all preemption. */
161
162 /* Change thread priority to the new mutex priority-inheritance priority. */
163 thread_ptr -> tx_thread_priority = new_priority;
164
165 /* Determine how to setup the thread's preemption-threshold. */
166 if (thread_ptr -> tx_thread_user_preempt_threshold < new_priority)
167 {
168
169 /* Change thread preemption-threshold to the user's preemption-threshold. */
170 thread_ptr -> tx_thread_preempt_threshold = thread_ptr -> tx_thread_user_preempt_threshold;
171 }
172 else
173 {
174
175 /* Change the thread preemption-threshold to the new threshold. */
176 thread_ptr -> tx_thread_preempt_threshold = new_priority;
177 }
178
179 /* Resume the thread with the new priority. */
180 _tx_thread_system_ni_resume(thread_ptr);
181
182 /* Decrement the preempt disable flag. */
183 _tx_thread_preempt_disable--;
184 #else
185
186 /* Increment the preempt disable flag. */
187 _tx_thread_preempt_disable = _tx_thread_preempt_disable + ((UINT) 2);
188
189 /* Set the state to priority change. */
190 thread_ptr -> tx_thread_state = TX_PRIORITY_CHANGE;
191
192 /* Set the suspending flag. */
193 thread_ptr -> tx_thread_suspending = TX_TRUE;
194
195 /* Setup the timeout period. */
196 thread_ptr -> tx_thread_timer.tx_timer_internal_remaining_ticks = ((ULONG) 0);
197
198 /* Restore interrupts. */
199 TX_RESTORE
200
201 /* The thread is ready and must first be removed from the list. Call the
202 system suspend function to accomplish this. */
203 _tx_thread_system_suspend(thread_ptr);
204
205 /* Disable interrupts. */
206 TX_DISABLE
207
208 /* At this point, the preempt disable flag is still set, so we still have
209 protection against all preemption. */
210
211 /* Change thread priority to the new mutex priority-inheritance priority. */
212 thread_ptr -> tx_thread_priority = new_priority;
213
214 /* Determine how to setup the thread's preemption-threshold. */
215 if (thread_ptr -> tx_thread_user_preempt_threshold < new_priority)
216 {
217
218 /* Change thread preemption-threshold to the user's preemption-threshold. */
219 thread_ptr -> tx_thread_preempt_threshold = thread_ptr -> tx_thread_user_preempt_threshold;
220 }
221 else
222 {
223
224 /* Change the thread preemption-threshold to the new threshold. */
225 thread_ptr -> tx_thread_preempt_threshold = new_priority;
226 }
227
228 /* Restore interrupts. */
229 TX_RESTORE
230
231 /* Resume the thread with the new priority. */
232 _tx_thread_system_resume(thread_ptr);
233 #endif
234
235 /* Optional processing extension. */
236 TX_MUTEX_PRIORITY_CHANGE_EXTENSION
237
238 #ifndef TX_NOT_INTERRUPTABLE
239
240 /* Disable interrupts. */
241 TX_DISABLE
242 #endif
243
244 /* Pickup the next thread to execute. */
245 next_execute_ptr = _tx_thread_execute_ptr;
246
247 /* Determine if this thread is not the next thread to execute. */
248 if (thread_ptr != next_execute_ptr)
249 {
250
251 /* Make sure the thread is still ready. */
252 if (thread_ptr -> tx_thread_state == TX_READY)
253 {
254
255 /* Now check and see if this thread has an equal or higher priority. */
256 if (thread_ptr -> tx_thread_priority <= next_execute_ptr -> tx_thread_priority)
257 {
258
259 /* Now determine if this thread was the previously executing thread. */
260 if (thread_ptr == execute_ptr)
261 {
262
263 /* Yes, this thread was previously executing before we temporarily suspended and resumed
264 it in order to change the priority. A lower or same priority thread cannot be the next thread
265 to execute in this case since this thread really didn't suspend. Simply reset the execute
266 pointer to this thread. */
267 _tx_thread_execute_ptr = thread_ptr;
268
269 /* Determine if we moved to a lower priority. If so, move the thread to the front of its priority list. */
270 if (original_priority < new_priority)
271 {
272
273 /* Ensure that this thread is placed at the front of the priority list. */
274 _tx_thread_priority_list[thread_ptr -> tx_thread_priority] = thread_ptr;
275 }
276 }
277 }
278 else
279 {
280
281 /* Now determine if this thread's preemption-threshold needs to be enforced. */
282 if (thread_ptr -> tx_thread_preempt_threshold < thread_ptr -> tx_thread_priority)
283 {
284
285 /* Yes, preemption-threshold is in force for this thread. */
286
287 /* Compare the next thread to execute thread's priority against the thread's preemption-threshold. */
288 if (thread_ptr -> tx_thread_preempt_threshold <= next_execute_ptr -> tx_thread_priority)
289 {
290
291 /* We must swap execute pointers to enforce the preemption-threshold of a thread coming out of
292 priority inheritance. */
293 _tx_thread_execute_ptr = thread_ptr;
294
295 /* Determine if we moved to a lower priority. If so, move the thread to the front of its priority list. */
296 if (original_priority < new_priority)
297 {
298
299 /* Ensure that this thread is placed at the front of the priority list. */
300 _tx_thread_priority_list[thread_ptr -> tx_thread_priority] = thread_ptr;
301 }
302 }
303
304 #ifndef TX_DISABLE_PREEMPTION_THRESHOLD
305
306 else
307 {
308
309 /* In this case, we need to mark the preempted map to indicate a thread executed above the
310 preemption-threshold. */
311
312 #if TX_MAX_PRIORITIES > 32
313
314 /* Calculate the index into the bit map array. */
315 map_index = (thread_ptr -> tx_thread_priority)/ ((UINT) 32);
316
317 /* Set the active bit to remember that the preempt map has something set. */
318 TX_DIV32_BIT_SET(thread_ptr -> tx_thread_priority, priority_bit)
319 _tx_thread_preempted_map_active = _tx_thread_preempted_map_active | priority_bit;
320 #endif
321
322 /* Remember that this thread was preempted by a thread above the thread's threshold. */
323 TX_MOD32_BIT_SET(thread_ptr -> tx_thread_priority, priority_bit)
324 _tx_thread_preempted_maps[MAP_INDEX] = _tx_thread_preempted_maps[MAP_INDEX] | priority_bit;
325 }
326 #endif
327 }
328 }
329 }
330 }
331
332 #ifndef TX_NOT_INTERRUPTABLE
333
334 /* Restore interrupts. */
335 TX_RESTORE
336 #endif
337 }
338 }
339
340