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_trace.h"
30 #include "tx_thread.h"
31 #include "tx_mutex.h"
32
33
34 /**************************************************************************/
35 /* */
36 /* FUNCTION RELEASE */
37 /* */
38 /* _tx_mutex_prioritize PORTABLE C */
39 /* 6.1 */
40 /* AUTHOR */
41 /* */
42 /* William E. Lamie, Microsoft Corporation */
43 /* */
44 /* DESCRIPTION */
45 /* */
46 /* This function places the highest priority suspended thread at the */
47 /* front of the suspension list. All other threads remain in the same */
48 /* FIFO suspension order. */
49 /* */
50 /* INPUT */
51 /* */
52 /* mutex_ptr Pointer to mutex control block */
53 /* */
54 /* OUTPUT */
55 /* */
56 /* status Completion status */
57 /* */
58 /* CALLS */
59 /* */
60 /* _tx_thread_system_preempt_check Check for preemption */
61 /* */
62 /* CALLED BY */
63 /* */
64 /* Application Code */
65 /* */
66 /* RELEASE HISTORY */
67 /* */
68 /* DATE NAME DESCRIPTION */
69 /* */
70 /* 05-19-2020 William E. Lamie Initial Version 6.0 */
71 /* 09-30-2020 Yuxin Zhou Modified comment(s), */
72 /* resulting in version 6.1 */
73 /* */
74 /**************************************************************************/
_tx_mutex_prioritize(TX_MUTEX * mutex_ptr)75 UINT _tx_mutex_prioritize(TX_MUTEX *mutex_ptr)
76 {
77
78 TX_INTERRUPT_SAVE_AREA
79
80 TX_THREAD *thread_ptr;
81 TX_THREAD *priority_thread_ptr;
82 TX_THREAD *head_ptr;
83 UINT suspended_count;
84 TX_THREAD *next_thread;
85 TX_THREAD *previous_thread;
86 UINT list_changed;
87 #ifdef TX_MISRA_ENABLE
88 UINT status;
89 #endif
90
91
92 /* Disable interrupts. */
93 TX_DISABLE
94
95 /* If trace is enabled, insert this event into the trace buffer. */
96 TX_TRACE_IN_LINE_INSERT(TX_TRACE_MUTEX_PRIORITIZE, mutex_ptr, mutex_ptr -> tx_mutex_suspended_count, TX_POINTER_TO_ULONG_CONVERT(&suspended_count), 0, TX_TRACE_MUTEX_EVENTS)
97
98 /* Log this kernel call. */
99 TX_EL_MUTEX_PRIORITIZE_INSERT
100
101 /* Pickup the suspended count. */
102 suspended_count = mutex_ptr -> tx_mutex_suspended_count;
103
104 /* Determine if there are fewer than 2 suspended threads. */
105 if (suspended_count < ((UINT) 2))
106 {
107
108 /* Restore interrupts. */
109 TX_RESTORE
110 }
111
112 /* Determine if there how many threads are suspended on this mutex. */
113 else if (suspended_count == ((UINT) 2))
114 {
115
116 /* Pickup the head pointer and the next pointer. */
117 head_ptr = mutex_ptr -> tx_mutex_suspension_list;
118 next_thread = head_ptr -> tx_thread_suspended_next;
119
120 /* Determine if the next suspended thread has a higher priority. */
121 if ((next_thread -> tx_thread_priority) < (head_ptr -> tx_thread_priority))
122 {
123
124 /* Yes, move the list head to the next thread. */
125 mutex_ptr -> tx_mutex_suspension_list = next_thread;
126 }
127
128 /* Restore interrupts. */
129 TX_RESTORE
130 }
131 else
132 {
133
134 /* Remember the suspension count and head pointer. */
135 head_ptr = mutex_ptr -> tx_mutex_suspension_list;
136
137 /* Default the highest priority thread to the thread at the front of the list. */
138 priority_thread_ptr = head_ptr;
139
140 /* Setup search pointer. */
141 thread_ptr = priority_thread_ptr -> tx_thread_suspended_next;
142
143 /* Disable preemption. */
144 _tx_thread_preempt_disable++;
145
146 /* Set the list changed flag to false. */
147 list_changed = TX_FALSE;
148
149 /* Search through the list to find the highest priority thread. */
150 do
151 {
152
153 /* Is the current thread higher priority? */
154 if (thread_ptr -> tx_thread_priority < priority_thread_ptr -> tx_thread_priority)
155 {
156
157 /* Yes, remember that this thread is the highest priority. */
158 priority_thread_ptr = thread_ptr;
159 }
160
161 /* Restore interrupts temporarily. */
162 TX_RESTORE
163
164 /* Disable interrupts again. */
165 TX_DISABLE
166
167 /* Determine if any changes to the list have occurred while
168 interrupts were enabled. */
169
170 /* Is the list head the same? */
171 if (head_ptr != mutex_ptr -> tx_mutex_suspension_list)
172 {
173
174 /* The list head has changed, set the list changed flag. */
175 list_changed = TX_TRUE;
176 }
177 else
178 {
179
180 /* Is the suspended count the same? */
181 if (suspended_count != mutex_ptr -> tx_mutex_suspended_count)
182 {
183
184 /* The list head has changed, set the list changed flag. */
185 list_changed = TX_TRUE;
186 }
187 }
188
189 /* Determine if the list has changed. */
190 if (list_changed == TX_FALSE)
191 {
192
193 /* Move the thread pointer to the next thread. */
194 thread_ptr = thread_ptr -> tx_thread_suspended_next;
195 }
196 else
197 {
198
199 /* Remember the suspension count and head pointer. */
200 head_ptr = mutex_ptr -> tx_mutex_suspension_list;
201 suspended_count = mutex_ptr -> tx_mutex_suspended_count;
202
203 /* Default the highest priority thread to the thread at the front of the list. */
204 priority_thread_ptr = head_ptr;
205
206 /* Setup search pointer. */
207 thread_ptr = priority_thread_ptr -> tx_thread_suspended_next;
208
209 /* Reset the list changed flag. */
210 list_changed = TX_FALSE;
211 }
212
213 } while (thread_ptr != head_ptr);
214
215 /* Release preemption. */
216 _tx_thread_preempt_disable--;
217
218 /* Now determine if the highest priority thread is at the front
219 of the list. */
220 if (priority_thread_ptr != head_ptr)
221 {
222
223 /* No, we need to move the highest priority suspended thread to the
224 front of the list. */
225
226 /* First, remove the highest priority thread by updating the
227 adjacent suspended threads. */
228 next_thread = priority_thread_ptr -> tx_thread_suspended_next;
229 previous_thread = priority_thread_ptr -> tx_thread_suspended_previous;
230 next_thread -> tx_thread_suspended_previous = previous_thread;
231 previous_thread -> tx_thread_suspended_next = next_thread;
232
233 /* Now, link the highest priority thread at the front of the list. */
234 previous_thread = head_ptr -> tx_thread_suspended_previous;
235 priority_thread_ptr -> tx_thread_suspended_next = head_ptr;
236 priority_thread_ptr -> tx_thread_suspended_previous = previous_thread;
237 previous_thread -> tx_thread_suspended_next = priority_thread_ptr;
238 head_ptr -> tx_thread_suspended_previous = priority_thread_ptr;
239
240 /* Move the list head pointer to the highest priority suspended thread. */
241 mutex_ptr -> tx_mutex_suspension_list = priority_thread_ptr;
242 }
243
244 /* Restore interrupts. */
245 TX_RESTORE
246
247 /* Check for preemption. */
248 _tx_thread_system_preempt_check();
249 }
250
251 #ifdef TX_MISRA_ENABLE
252
253 /* Initialize status to success. */
254 status = TX_SUCCESS;
255
256 /* Define extended processing option. */
257 status = TX_MUTEX_PRIORITIZE_MISRA_EXTENSION(status);
258
259 /* Return completion status. */
260 return(status);
261 #else
262
263 /* Return successful completion. */
264 return(TX_SUCCESS);
265 #endif
266 }
267
268