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 #define TX_THREAD_SMP_SOURCE_CODE
25
26
27 /* Include necessary system files. */
28
29 #include "tx_api.h"
30 #include "tx_thread.h"
31 #include "tx_mutex.h"
32
33
34 /**************************************************************************/
35 /* */
36 /* FUNCTION RELEASE */
37 /* */
38 /* _tx_mutex_priority_change PORTABLE SMP */
39 /* 6.1 */
40 /* AUTHOR */
41 /* */
42 /* William E. Lamie, Microsoft Corporation */
43 /* */
44 /* DESCRIPTION */
45 /* */
46 /* This function changes the priority of the specified thread for the */
47 /* priority inheritance option of the mutex service. */
48 /* */
49 /* INPUT */
50 /* */
51 /* thread_ptr Pointer to thread to suspend */
52 /* new_priority New thread priority */
53 /* new_threshold New preemption-threshold */
54 /* */
55 /* OUTPUT */
56 /* */
57 /* None */
58 /* */
59 /* CALLS */
60 /* */
61 /* _tx_thread_smp_rebalance_execute_list */
62 /* Rebalance the execution list */
63 /* _tx_thread_smp_simple_priority_change */
64 /* Change priority */
65 /* _tx_thread_system_resume Resume thread */
66 /* _tx_thread_system_ni_resume Non-interruptable resume thread */
67 /* _tx_thread_system_suspend Suspend thread */
68 /* _tx_thread_system_ni_suspend Non-interruptable suspend thread */
69 /* */
70 /* CALLED BY */
71 /* */
72 /* _tx_mutex_get Inherit priority */
73 /* _tx_mutex_put Restore previous priority */
74 /* */
75 /* RELEASE HISTORY */
76 /* */
77 /* DATE NAME DESCRIPTION */
78 /* */
79 /* 09-30-2020 William E. Lamie Initial Version 6.1 */
80 /* */
81 /**************************************************************************/
_tx_mutex_priority_change(TX_THREAD * thread_ptr,UINT new_priority)82 VOID _tx_mutex_priority_change(TX_THREAD *thread_ptr, UINT new_priority)
83 {
84
85 #ifndef TX_NOT_INTERRUPTABLE
86
87 TX_INTERRUPT_SAVE_AREA
88 #endif
89
90 TX_THREAD *execute_ptr;
91 UINT core_index;
92 UINT original_priority;
93 UINT lowest_priority;
94 TX_THREAD *original_pt_thread;
95 #ifndef TX_DISABLE_PREEMPTION_THRESHOLD
96 TX_THREAD *new_pt_thread;
97 UINT priority;
98 ULONG priority_bit;
99 #if TX_MAX_PRIORITIES > 32
100 UINT map_index;
101 #endif
102 #endif
103 UINT finished;
104
105
106 /* Default finished to false. */
107 finished = TX_FALSE;
108
109 #ifndef TX_NOT_INTERRUPTABLE
110
111 /* Lockout interrupts while the thread is being suspended. */
112 TX_DISABLE
113 #endif
114
115 /* Determine if there is anything to do. */
116 if (thread_ptr -> tx_thread_priority == new_priority)
117 {
118
119 if (thread_ptr -> tx_thread_preempt_threshold == new_priority)
120 {
121
122 /* Set the finished flag to true. */
123 finished = TX_TRUE;
124 }
125 }
126
127 /* Determine if there is still more to do. */
128 if (finished == TX_FALSE)
129 {
130
131 /* Default the execute pointer to NULL. */
132 execute_ptr = TX_NULL;
133
134 /* Determine if this thread is currently ready. */
135 if (thread_ptr -> tx_thread_state != TX_READY)
136 {
137
138 /* Change thread priority to the new mutex priority-inheritance priority. */
139 thread_ptr -> tx_thread_priority = new_priority;
140
141 /* Determine how to setup the thread's preemption-threshold. */
142 if (thread_ptr -> tx_thread_user_preempt_threshold < new_priority)
143 {
144
145 /* Change thread preemption-threshold to the user's preemption-threshold. */
146 thread_ptr -> tx_thread_preempt_threshold = thread_ptr -> tx_thread_user_preempt_threshold;
147 }
148 else
149 {
150
151 /* Change the thread preemption-threshold to the new threshold. */
152 thread_ptr -> tx_thread_preempt_threshold = new_priority;
153 }
154
155 }
156 else
157 {
158
159 /* Pickup the core index. */
160 core_index = thread_ptr -> tx_thread_smp_core_mapped;
161
162 /* Save the original priority. */
163 original_priority = thread_ptr -> tx_thread_priority;
164
165 /* Determine if this thread is the currently executing thread. */
166 if (thread_ptr == _tx_thread_execute_ptr[core_index])
167 {
168
169 /* Yes, this thread is scheduled. */
170
171 /* Remember this thread as the currently executing thread. */
172 execute_ptr = thread_ptr;
173
174 /* Determine if the thread is being set to a higher-priority and it does't have
175 preemption-threshold set. */
176 if (new_priority < thread_ptr -> tx_thread_priority)
177 {
178
179 /* Check for preemption-threshold. */
180 if (thread_ptr -> tx_thread_user_priority == thread_ptr -> tx_thread_user_preempt_threshold)
181 {
182
183 /* Simple case, remove the thread from the current priority list and place in
184 the higher priority list. */
185 _tx_thread_smp_simple_priority_change(thread_ptr, new_priority);
186
187 /* Set the finished flag to true. */
188 finished = TX_TRUE;
189 }
190 }
191 }
192 else
193 {
194
195 /* Thread is not currently executing, so it can just be moved to the lower priority in the list. */
196
197 /* Determine if the thread is being set to a lower-priority and it does't have
198 preemption-threshold set. */
199 if (new_priority > thread_ptr -> tx_thread_priority)
200 {
201
202 /* Check for preemption-threshold. */
203 if (thread_ptr -> tx_thread_user_priority == thread_ptr -> tx_thread_user_preempt_threshold)
204 {
205
206 /* Simple case, remove the thread from the current priority list and place in
207 the lower priority list. */
208 if (new_priority < thread_ptr -> tx_thread_user_priority)
209 {
210
211 /* Use the new priority. */
212 _tx_thread_smp_simple_priority_change(thread_ptr, new_priority);
213 }
214 else
215 {
216
217 /* Use the user priority. */
218 _tx_thread_smp_simple_priority_change(thread_ptr, thread_ptr -> tx_thread_user_priority);
219 }
220
221 /* Set the finished flag to true. */
222 finished = TX_TRUE;
223 }
224 }
225 }
226
227 /* Now determine if we are finished. */
228 if (finished == TX_FALSE)
229 {
230
231 /* Save the original preemption-threshold thread. */
232 original_pt_thread = _tx_thread_preemption__threshold_scheduled;
233
234 #ifdef TX_NOT_INTERRUPTABLE
235
236 /* Increment the preempt disable flag. */
237 _tx_thread_preempt_disable++;
238
239 /* Set the state to priority change. */
240 thread_ptr -> tx_thread_state = TX_PRIORITY_CHANGE;
241
242 /* Call actual non-interruptable thread suspension routine. */
243 _tx_thread_system_ni_suspend(thread_ptr, ((ULONG) 0));
244
245 /* At this point, the preempt disable flag is still set, so we still have
246 protection against all preemption. */
247
248 /* Determine how to setup the thread's priority. */
249 if (thread_ptr -> tx_thread_user_priority < new_priority)
250 {
251
252 /* Change thread priority to the user's priority. */
253 thread_ptr -> tx_thread_priority = thread_ptr -> tx_thread_user_priority;
254 }
255 else
256 {
257
258 /* Change thread priority to the new mutex priority-inheritance priority. */
259 thread_ptr -> tx_thread_priority = new_priority;
260 }
261
262 /* Determine how to setup the thread's preemption-threshold. */
263 if (thread_ptr -> tx_thread_user_preempt_threshold < new_priority)
264 {
265
266 /* Change thread preemption-threshold to the user's preemption-threshold. */
267 thread_ptr -> tx_thread_preempt_threshold = thread_ptr -> tx_thread_user_preempt_threshold;
268 }
269 else
270 {
271
272 /* Change the thread preemption-threshold to the new threshold. */
273 thread_ptr -> tx_thread_preempt_threshold = new_priority;
274 }
275
276 /* Resume the thread with the new priority. */
277 _tx_thread_system_ni_resume(thread_ptr);
278
279 /* Decrement the preempt disable flag. */
280 _tx_thread_preempt_disable--;
281 #else
282
283 /* Increment the preempt disable flag. */
284 _tx_thread_preempt_disable = _tx_thread_preempt_disable + ((UINT) 2);
285
286 /* Set the state to priority change. */
287 thread_ptr -> tx_thread_state = TX_PRIORITY_CHANGE;
288
289 /* Set the suspending flag. */
290 thread_ptr -> tx_thread_suspending = TX_TRUE;
291
292 /* Setup the timeout period. */
293 thread_ptr -> tx_thread_timer.tx_timer_internal_remaining_ticks = ((UINT) 0);
294
295 /* Restore interrupts. */
296 TX_RESTORE
297
298 /* The thread is ready and must first be removed from the list. Call the
299 system suspend function to accomplish this. */
300 _tx_thread_system_suspend(thread_ptr);
301
302 /* Lockout interrupts again. */
303 TX_DISABLE
304
305 /* At this point, the preempt disable flag is still set, so we still have
306 protection against all preemption. */
307
308 /* Determine how to setup the thread's priority. */
309 if (thread_ptr -> tx_thread_user_priority < new_priority)
310 {
311
312 /* Change thread priority to the user's priority. */
313 thread_ptr -> tx_thread_priority = thread_ptr -> tx_thread_user_priority;
314 }
315 else
316 {
317
318 /* Change thread priority to the new mutex priority-inheritance priority. */
319 thread_ptr -> tx_thread_priority = new_priority;
320 }
321
322 /* Determine how to setup the thread's preemption-threshold. */
323 if (thread_ptr -> tx_thread_user_preempt_threshold < new_priority)
324 {
325
326 /* Change thread preemption-threshold to the user's preemption-threshold. */
327 thread_ptr -> tx_thread_preempt_threshold = thread_ptr -> tx_thread_user_preempt_threshold;
328 }
329 else
330 {
331
332 /* Change the thread preemption-threshold to the new threshold. */
333 thread_ptr -> tx_thread_preempt_threshold = new_priority;
334 }
335
336 /* Restore interrupts. */
337 TX_RESTORE
338
339 /* Resume the thread with the new priority. */
340 _tx_thread_system_resume(thread_ptr);
341 #endif
342
343 /* Optional processing extension. */
344 TX_MUTEX_PRIORITY_CHANGE_EXTENSION
345
346 #ifndef TX_NOT_INTERRUPTABLE
347
348 /* Disable interrupts. */
349 TX_DISABLE
350 #endif
351
352 /* Determine if the thread was previously executing. */
353 if (thread_ptr == execute_ptr)
354 {
355
356 /* Make sure the thread is still ready. */
357 if (thread_ptr -> tx_thread_state == TX_READY)
358 {
359
360 #ifndef TX_DISABLE_PREEMPTION_THRESHOLD
361 /* Determine if preemption-threshold is in force at the new priority level. */
362 if (_tx_thread_preemption_threshold_list[thread_ptr -> tx_thread_priority] == TX_NULL)
363 {
364
365 /* Ensure that this thread is placed at the front of the priority list. */
366 _tx_thread_priority_list[thread_ptr -> tx_thread_priority] = thread_ptr;
367 }
368 #else
369
370 /* Ensure that this thread is placed at the front of the priority list. */
371 _tx_thread_priority_list[thread_ptr -> tx_thread_priority] = thread_ptr;
372 #endif
373 }
374 }
375
376 /* Pickup the core index. */
377 core_index = thread_ptr -> tx_thread_smp_core_mapped;
378
379 #ifndef TX_THREAD_SMP_DYNAMIC_CORE_MAX
380
381 /* Pickup the next thread to execute. */
382 if (core_index < ((UINT) TX_THREAD_SMP_MAX_CORES))
383 #else
384
385 /* Pickup the next thread to execute. */
386 if (core_index < _tx_thread_smp_max_cores)
387 #endif
388 {
389
390 /* Determine if this thread is not the next thread to execute. */
391 if (thread_ptr != _tx_thread_execute_ptr[core_index])
392 {
393
394 /* Now determine if this thread was previously executing thread. */
395 if (thread_ptr == execute_ptr)
396 {
397
398 /* Determine if we moved to a lower priority. If so, move the thread to the front of the priority list. */
399 if (original_priority < new_priority)
400 {
401
402 /* Make sure the thread is still ready. */
403 if (thread_ptr -> tx_thread_state == TX_READY)
404 {
405
406 /* Determine the lowest priority scheduled thread. */
407 lowest_priority = _tx_thread_smp_lowest_priority_get();
408
409 /* Determine if this thread has a higher or same priority as the lowest priority
410 in the list. */
411 if (thread_ptr -> tx_thread_priority <= lowest_priority)
412 {
413
414 /* Yes, we need to rebalance to make it possible for this thread to execute. */
415
416 /* Determine if the thread with preemption-threshold thread has changed... and is
417 not the scheduled thread. */
418 if ((original_pt_thread != _tx_thread_preemption__threshold_scheduled) &&
419 (original_pt_thread != thread_ptr))
420 {
421
422 /* Yes, preemption-threshold has changed. Determine if it can or should
423 be reversed. */
424
425 #ifndef TX_DISABLE_PREEMPTION_THRESHOLD
426
427 /* Pickup the preemption-threshold thread. */
428 new_pt_thread = _tx_thread_preemption__threshold_scheduled;
429 #endif
430
431 /* Restore the original preemption-threshold thread. */
432 _tx_thread_preemption__threshold_scheduled = original_pt_thread;
433
434
435 #ifndef TX_DISABLE_PREEMPTION_THRESHOLD
436
437 /* Determine if there is a new preemption-threshold thread to reverse. */
438 if (new_pt_thread != TX_NULL)
439 {
440
441 /* Clear the information associated with the new preemption-threshold thread. */
442
443 /* Pickup the priority. */
444 priority = new_pt_thread -> tx_thread_priority;
445
446 /* Clear the preempted list entry. */
447 _tx_thread_preemption_threshold_list[priority] = TX_NULL;
448
449 #if TX_MAX_PRIORITIES > 32
450 /* Calculate the bit map array index. */
451 map_index = new_priority/((UINT) 32);
452 #endif
453 /* Ensure that this thread's priority is clear in the preempt map. */
454 TX_MOD32_BIT_SET(priority, priority_bit)
455 _tx_thread_preempted_maps[MAP_INDEX] = _tx_thread_preempted_maps[MAP_INDEX] & (~(priority_bit));
456 #if TX_MAX_PRIORITIES > 32
457
458 /* Determine if there are any other bits set in this preempt map. */
459 if (_tx_thread_preempted_maps[MAP_INDEX] == ((ULONG) 0))
460 {
461
462 /* No, clear the active bit to signify this preempted map has nothing set. */
463 TX_DIV32_BIT_SET(priority, priority_bit)
464 _tx_thread_preempted_map_active = _tx_thread_preempted_map_active & (~(priority_bit));
465 }
466 #endif
467 }
468 #endif
469 }
470
471 /* Pickup the index. */
472 core_index = TX_SMP_CORE_ID;
473
474 /* Call the rebalance routine. This routine maps cores and ready threads. */
475 _tx_thread_smp_rebalance_execute_list(core_index);
476 }
477 }
478 }
479 }
480 }
481 }
482 }
483 }
484 }
485
486 #ifndef TX_NOT_INTERRUPTABLE
487
488 /* Restore interrupts. */
489 TX_RESTORE
490 #endif
491 }
492
493