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 /** Semaphore */
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_semaphore.h"
32
33
34 /**************************************************************************/
35 /* */
36 /* FUNCTION RELEASE */
37 /* */
38 /* _tx_semaphore_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 /* semaphore_ptr Pointer to semaphore 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_semaphore_prioritize(TX_SEMAPHORE * semaphore_ptr)75 UINT _tx_semaphore_prioritize(TX_SEMAPHORE *semaphore_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
88
89 /* Disable interrupts. */
90 TX_DISABLE
91
92 /* If trace is enabled, insert this event into the trace buffer. */
93 TX_TRACE_IN_LINE_INSERT(TX_TRACE_SEMAPHORE_PRIORITIZE, semaphore_ptr, semaphore_ptr -> tx_semaphore_suspended_count, TX_POINTER_TO_ULONG_CONVERT(&suspended_count), 0, TX_TRACE_SEMAPHORE_EVENTS)
94
95 /* Log this kernel call. */
96 TX_EL_SEMAPHORE_PRIORITIZE_INSERT
97
98 /* Pickup the suspended count. */
99 suspended_count = semaphore_ptr -> tx_semaphore_suspended_count;
100
101 /* Determine if there are fewer than 2 suspended threads. */
102 if (suspended_count < ((UINT) 2))
103 {
104
105 /* Restore interrupts. */
106 TX_RESTORE
107 }
108
109 /* Determine if there how many threads are suspended on this semaphore. */
110 else if (suspended_count == ((UINT) 2))
111 {
112
113 /* Pickup the head pointer and the next pointer. */
114 head_ptr = semaphore_ptr -> tx_semaphore_suspension_list;
115 next_thread = head_ptr -> tx_thread_suspended_next;
116
117 /* Determine if the next suspended thread has a higher priority. */
118 if ((next_thread -> tx_thread_priority) < (head_ptr -> tx_thread_priority))
119 {
120
121 /* Yes, move the list head to the next thread. */
122 semaphore_ptr -> tx_semaphore_suspension_list = next_thread;
123 }
124
125 /* Restore interrupts. */
126 TX_RESTORE
127 }
128 else
129 {
130
131 /* Remember the suspension count and head pointer. */
132 head_ptr = semaphore_ptr -> tx_semaphore_suspension_list;
133
134 /* Default the highest priority thread to the thread at the front of the list. */
135 priority_thread_ptr = head_ptr;
136
137 /* Setup search pointer. */
138 thread_ptr = priority_thread_ptr -> tx_thread_suspended_next;
139
140 /* Disable preemption. */
141 _tx_thread_preempt_disable++;
142
143 /* Set the list changed flag to false. */
144 list_changed = TX_FALSE;
145
146 /* Search through the list to find the highest priority thread. */
147 do
148 {
149
150 /* Is the current thread higher priority? */
151 if (thread_ptr -> tx_thread_priority < priority_thread_ptr -> tx_thread_priority)
152 {
153
154 /* Yes, remember that this thread is the highest priority. */
155 priority_thread_ptr = thread_ptr;
156 }
157
158 /* Restore interrupts temporarily. */
159 TX_RESTORE
160
161 /* Disable interrupts again. */
162 TX_DISABLE
163
164 /* Determine if any changes to the list have occurred while
165 interrupts were enabled. */
166
167 /* Is the list head the same? */
168 if (head_ptr != semaphore_ptr -> tx_semaphore_suspension_list)
169 {
170
171 /* The list head has changed, set the list changed flag. */
172 list_changed = TX_TRUE;
173 }
174 else
175 {
176
177 /* Is the suspended count the same? */
178 if (suspended_count != semaphore_ptr -> tx_semaphore_suspended_count)
179 {
180
181 /* The list head has changed, set the list changed flag. */
182 list_changed = TX_TRUE;
183 }
184 }
185
186 /* Determine if the list has changed. */
187 if (list_changed == TX_FALSE)
188 {
189
190 /* Yes, everything is the same... move the thread pointer to the next thread. */
191 thread_ptr = thread_ptr -> tx_thread_suspended_next;
192 }
193 else
194 {
195
196 /* No, the list is been modified so we need to start the search over. */
197
198 /* Save the suspension count and head pointer. */
199 head_ptr = semaphore_ptr -> tx_semaphore_suspension_list;
200 suspended_count = semaphore_ptr -> tx_semaphore_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 semaphore_ptr -> tx_semaphore_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 /* Return completion status. */
251 return(TX_SUCCESS);
252 }
253
254