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