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_priority_change PORTABLE C */
38 /* 6.1 */
39 /* AUTHOR */
40 /* */
41 /* William E. Lamie, Microsoft Corporation */
42 /* */
43 /* DESCRIPTION */
44 /* */
45 /* This function changes the priority of the specified thread. It */
46 /* also returns the old priority and handles preemption if the calling */
47 /* thread is currently executing and the priority change results in a */
48 /* higher priority thread ready for execution. */
49 /* */
50 /* Note: the preemption threshold is automatically changed to the new */
51 /* priority. */
52 /* */
53 /* INPUT */
54 /* */
55 /* thread_ptr Pointer to thread to suspend */
56 /* new_priority New thread priority */
57 /* old_priority Old thread priority */
58 /* */
59 /* OUTPUT */
60 /* */
61 /* status Completion status */
62 /* */
63 /* CALLS */
64 /* */
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 /* _tx_thread_system_preempt_check Check for preemption */
70 /* */
71 /* CALLED BY */
72 /* */
73 /* Application Code */
74 /* */
75 /* RELEASE HISTORY */
76 /* */
77 /* DATE NAME DESCRIPTION */
78 /* */
79 /* 05-19-2020 William E. Lamie Initial Version 6.0 */
80 /* 09-30-2020 William E. Lamie Modified comment(s), and */
81 /* change thread state from */
82 /* TX_SUSPENDED to */
83 /* TX_PRIORITY_CHANGE before */
84 /* calling */
85 /* _tx_thread_system_suspend, */
86 /* resulting in version 6.1 */
87 /* */
88 /**************************************************************************/
_tx_thread_priority_change(TX_THREAD * thread_ptr,UINT new_priority,UINT * old_priority)89 UINT _tx_thread_priority_change(TX_THREAD *thread_ptr, UINT new_priority, UINT *old_priority)
90 {
91
92 TX_INTERRUPT_SAVE_AREA
93
94 TX_THREAD *execute_ptr;
95 TX_THREAD *next_execute_ptr;
96 UINT original_priority;
97
98
99 /* Lockout interrupts while the thread is being suspended. */
100 TX_DISABLE
101
102 /* Save the previous priority. */
103 *old_priority = thread_ptr -> tx_thread_user_priority;
104
105 /* If trace is enabled, insert this event into the trace buffer. */
106 TX_TRACE_IN_LINE_INSERT(TX_TRACE_THREAD_PRIORITY_CHANGE, thread_ptr, new_priority, thread_ptr -> tx_thread_priority, thread_ptr -> tx_thread_state, TX_TRACE_THREAD_EVENTS)
107
108 /* Log this kernel call. */
109 TX_EL_THREAD_PRIORITY_CHANGE_INSERT
110
111 /* Determine if this thread is currently ready. */
112 if (thread_ptr -> tx_thread_state != TX_READY)
113 {
114
115 /* Setup the user priority and threshold in the thread's control
116 block. */
117 thread_ptr -> tx_thread_user_priority = new_priority;
118 thread_ptr -> tx_thread_user_preempt_threshold = new_priority;
119
120 /* Determine if the actual thread priority should be setup, which is the
121 case if the new priority is higher than the priority inheritance. */
122 if (new_priority < thread_ptr -> tx_thread_inherit_priority)
123 {
124
125 /* Change thread priority to the new user's priority. */
126 thread_ptr -> tx_thread_priority = new_priority;
127 thread_ptr -> tx_thread_preempt_threshold = new_priority;
128 }
129 else
130 {
131
132 /* Change thread priority to the priority inheritance. */
133 thread_ptr -> tx_thread_priority = thread_ptr -> tx_thread_inherit_priority;
134 thread_ptr -> tx_thread_preempt_threshold = thread_ptr -> tx_thread_inherit_priority;
135 }
136
137 /* Restore interrupts. */
138 TX_RESTORE
139 }
140 else
141 {
142
143 /* Set the state to priority change. */
144 thread_ptr -> tx_thread_state = TX_PRIORITY_CHANGE;
145
146 /* Pickup the next thread to execute. */
147 execute_ptr = _tx_thread_execute_ptr;
148
149 /* Save the original priority. */
150 original_priority = thread_ptr -> tx_thread_priority;
151
152 #ifdef TX_NOT_INTERRUPTABLE
153
154 /* Increment the preempt disable flag. */
155 _tx_thread_preempt_disable++;
156
157 /* Call actual non-interruptable thread suspension routine. */
158 _tx_thread_system_ni_suspend(thread_ptr, ((ULONG) 0));
159
160 /* At this point, the preempt disable flag is still set, so we still have
161 protection against all preemption. */
162
163 /* Setup the new priority for this thread. */
164 thread_ptr -> tx_thread_user_priority = new_priority;
165 thread_ptr -> tx_thread_user_preempt_threshold = new_priority;
166
167 /* Determine if the actual thread priority should be setup, which is the
168 case if the new priority is higher than the priority inheritance. */
169 if (new_priority < thread_ptr -> tx_thread_inherit_priority)
170 {
171
172 /* Change thread priority to the new user's priority. */
173 thread_ptr -> tx_thread_priority = new_priority;
174 thread_ptr -> tx_thread_preempt_threshold = new_priority;
175 }
176 else
177 {
178
179 /* Change thread priority to the priority inheritance. */
180 thread_ptr -> tx_thread_priority = thread_ptr -> tx_thread_inherit_priority;
181 thread_ptr -> tx_thread_preempt_threshold = thread_ptr -> tx_thread_inherit_priority;
182 }
183
184 /* Resume the thread with the new priority. */
185 _tx_thread_system_ni_resume(thread_ptr);
186
187 #else
188
189 /* Increment the preempt disable flag by 2 to prevent system suspend from
190 returning to the system. */
191 _tx_thread_preempt_disable = _tx_thread_preempt_disable + ((UINT) 3);
192
193 /* Set the suspending flag. */
194 thread_ptr -> tx_thread_suspending = TX_TRUE;
195
196 /* Setup the timeout period. */
197 thread_ptr -> tx_thread_timer.tx_timer_internal_remaining_ticks = ((ULONG) 0);
198
199 /* Restore interrupts. */
200 TX_RESTORE
201
202 /* The thread is ready and must first be removed from the list. Call the
203 system suspend function to accomplish this. */
204 _tx_thread_system_suspend(thread_ptr);
205
206 /* At this point, the preempt disable flag is still set, so we still have
207 protection against all preemption. */
208
209 /* Setup the new priority for this thread. */
210 thread_ptr -> tx_thread_user_priority = new_priority;
211 thread_ptr -> tx_thread_user_preempt_threshold = new_priority;
212
213 /* Determine if the actual thread priority should be setup, which is the
214 case if the new priority is higher than the priority inheritance. */
215 if (new_priority < thread_ptr -> tx_thread_inherit_priority)
216 {
217
218 /* Change thread priority to the new user's priority. */
219 thread_ptr -> tx_thread_priority = new_priority;
220 thread_ptr -> tx_thread_preempt_threshold = new_priority;
221 }
222 else
223 {
224
225 /* Change thread priority to the priority inheritance. */
226 thread_ptr -> tx_thread_priority = thread_ptr -> tx_thread_inherit_priority;
227 thread_ptr -> tx_thread_preempt_threshold = thread_ptr -> tx_thread_inherit_priority;
228 }
229
230 /* Resume the thread with the new priority. */
231 _tx_thread_system_resume(thread_ptr);
232
233 /* Disable interrupts. */
234 TX_DISABLE
235 #endif
236
237 /* Decrement the preempt disable flag. */
238 _tx_thread_preempt_disable--;
239
240 /* Pickup the next thread to execute. */
241 next_execute_ptr = _tx_thread_execute_ptr;
242
243 /* Determine if this thread is not the next thread to execute. */
244 if (thread_ptr != next_execute_ptr)
245 {
246
247 /* Make sure the thread is still ready. */
248 if (thread_ptr -> tx_thread_state == TX_READY)
249 {
250
251 /* Now check and see if this thread has an equal or higher priority. */
252 if (thread_ptr -> tx_thread_priority <= next_execute_ptr -> tx_thread_priority)
253 {
254
255 /* Now determine if this thread was the previously executing thread. */
256 if (thread_ptr == execute_ptr)
257 {
258
259 /* Yes, this thread was previously executing before we temporarily suspended and resumed
260 it in order to change the priority. A lower or same priority thread cannot be the next thread
261 to execute in this case since this thread really didn't suspend. Simply reset the execute
262 pointer to this thread. */
263 _tx_thread_execute_ptr = thread_ptr;
264
265 /* Determine if we moved to a lower priority. If so, move the thread to the front of its priority list. */
266 if (original_priority < new_priority)
267 {
268
269 /* Ensure that this thread is placed at the front of the priority list. */
270 _tx_thread_priority_list[thread_ptr -> tx_thread_priority] = thread_ptr;
271 }
272 }
273 }
274 }
275 }
276
277 /* Restore interrupts. */
278 TX_RESTORE
279
280 /* Check for preemption. */
281 _tx_thread_system_preempt_check();
282 }
283
284 /* Return success if we get here! */
285 return(TX_SUCCESS);
286 }
287
288