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