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_thread.h"
29 #include "tx_mutex.h"
30
31
32 /**************************************************************************/
33 /* */
34 /* FUNCTION RELEASE */
35 /* */
36 /* _tx_mutex_cleanup PORTABLE C */
37 /* 6.1 */
38 /* AUTHOR */
39 /* */
40 /* William E. Lamie, Microsoft Corporation */
41 /* */
42 /* DESCRIPTION */
43 /* */
44 /* This function processes mutex timeout and thread terminate */
45 /* actions that require the mutex data structures to be cleaned */
46 /* up. */
47 /* */
48 /* INPUT */
49 /* */
50 /* thread_ptr Pointer to suspended thread's */
51 /* control block */
52 /* */
53 /* OUTPUT */
54 /* */
55 /* None */
56 /* */
57 /* CALLS */
58 /* */
59 /* _tx_thread_system_resume Resume thread service */
60 /* _tx_thread_system_ni_resume Non-interruptable resume thread */
61 /* */
62 /* CALLED BY */
63 /* */
64 /* _tx_thread_timeout Thread timeout processing */
65 /* _tx_thread_terminate Thread terminate processing */
66 /* _tx_thread_wait_abort Thread wait abort processing */
67 /* */
68 /* RELEASE HISTORY */
69 /* */
70 /* DATE NAME DESCRIPTION */
71 /* */
72 /* 05-19-2020 William E. Lamie Initial Version 6.0 */
73 /* 09-30-2020 Yuxin Zhou Modified comment(s), */
74 /* resulting in version 6.1 */
75 /* */
76 /**************************************************************************/
_tx_mutex_cleanup(TX_THREAD * thread_ptr,ULONG suspension_sequence)77 VOID _tx_mutex_cleanup(TX_THREAD *thread_ptr, ULONG suspension_sequence)
78 {
79
80 #ifndef TX_NOT_INTERRUPTABLE
81 TX_INTERRUPT_SAVE_AREA
82 #endif
83
84 TX_MUTEX *mutex_ptr;
85 UINT suspended_count;
86 TX_THREAD *next_thread;
87 TX_THREAD *previous_thread;
88
89
90 #ifndef TX_NOT_INTERRUPTABLE
91
92 /* Disable interrupts to remove the suspended thread from the mutex. */
93 TX_DISABLE
94
95 /* Determine if the cleanup is still required. */
96 if (thread_ptr -> tx_thread_suspend_cleanup == &(_tx_mutex_cleanup))
97 {
98
99 /* Check for valid suspension sequence. */
100 if (suspension_sequence == thread_ptr -> tx_thread_suspension_sequence)
101 {
102
103 /* Setup pointer to mutex control block. */
104 mutex_ptr = TX_VOID_TO_MUTEX_POINTER_CONVERT(thread_ptr -> tx_thread_suspend_control_block);
105
106 /* Check for NULL mutex pointer. */
107 if (mutex_ptr != TX_NULL)
108 {
109
110 /* Determine if the mutex ID is valid. */
111 if (mutex_ptr -> tx_mutex_id == TX_MUTEX_ID)
112 {
113
114 /* Determine if there are any thread suspensions. */
115 if (mutex_ptr -> tx_mutex_suspended_count != TX_NO_SUSPENSIONS)
116 {
117 #else
118
119 /* Setup pointer to mutex control block. */
120 mutex_ptr = TX_VOID_TO_MUTEX_POINTER_CONVERT(thread_ptr -> tx_thread_suspend_control_block);
121 #endif
122
123 /* Yes, we still have thread suspension! */
124
125 /* Clear the suspension cleanup flag. */
126 thread_ptr -> tx_thread_suspend_cleanup = TX_NULL;
127
128 /* Decrement the suspension count. */
129 mutex_ptr -> tx_mutex_suspended_count--;
130
131 /* Pickup the suspended count. */
132 suspended_count = mutex_ptr -> tx_mutex_suspended_count;
133
134 /* Remove the suspended thread from the list. */
135
136 /* See if this is the only suspended thread on the list. */
137 if (suspended_count == TX_NO_SUSPENSIONS)
138 {
139
140 /* Yes, the only suspended thread. */
141
142 /* Update the head pointer. */
143 mutex_ptr -> tx_mutex_suspension_list = TX_NULL;
144 }
145 else
146 {
147
148 /* At least one more thread is on the same suspension list. */
149
150 /* Update the links of the adjacent threads. */
151 next_thread = thread_ptr -> tx_thread_suspended_next;
152 previous_thread = thread_ptr -> tx_thread_suspended_previous;
153 next_thread -> tx_thread_suspended_previous = previous_thread;
154 previous_thread -> tx_thread_suspended_next = next_thread;
155
156 /* Determine if we need to update the head pointer. */
157 if (mutex_ptr -> tx_mutex_suspension_list == thread_ptr)
158 {
159
160 /* Update the list head pointer. */
161 mutex_ptr -> tx_mutex_suspension_list = next_thread;
162 }
163 }
164
165 /* Now we need to determine if this cleanup is from a terminate, timeout,
166 or from a wait abort. */
167 if (thread_ptr -> tx_thread_state == TX_MUTEX_SUSP)
168 {
169
170 /* Timeout condition and the thread still suspended on the mutex.
171 Setup return error status and resume the thread. */
172
173 #ifdef TX_MUTEX_ENABLE_PERFORMANCE_INFO
174
175 /* Increment the total timeouts counter. */
176 _tx_mutex_performance_timeout_count++;
177
178 /* Increment the number of timeouts on this semaphore. */
179 mutex_ptr -> tx_mutex_performance_timeout_count++;
180 #endif
181
182 /* Setup return status. */
183 thread_ptr -> tx_thread_suspend_status = TX_NOT_AVAILABLE;
184
185 #ifdef TX_NOT_INTERRUPTABLE
186
187 /* Resume the thread! */
188 _tx_thread_system_ni_resume(thread_ptr);
189 #else
190
191 /* Temporarily disable preemption. */
192 _tx_thread_preempt_disable++;
193
194 /* Restore interrupts. */
195 TX_RESTORE
196
197 /* Resume the thread! */
198 _tx_thread_system_resume(thread_ptr);
199
200 /* Disable interrupts. */
201 TX_DISABLE
202 #endif
203 }
204 #ifndef TX_NOT_INTERRUPTABLE
205 }
206 }
207 }
208 }
209 }
210
211 /* Restore interrupts. */
212 TX_RESTORE
213 #endif
214 }
215
216
217 /**************************************************************************/
218 /* */
219 /* FUNCTION RELEASE */
220 /* */
221 /* _tx_mutex_thread_release PORTABLE C */
222 /* 6.1 */
223 /* AUTHOR */
224 /* */
225 /* William E. Lamie, Microsoft Corporation */
226 /* */
227 /* DESCRIPTION */
228 /* */
229 /* This function releases all mutexes owned by the thread. This */
230 /* function is called when the thread completes or is terminated. */
231 /* */
232 /* INPUT */
233 /* */
234 /* thread_ptr Pointer to thread's control block */
235 /* */
236 /* OUTPUT */
237 /* */
238 /* None */
239 /* */
240 /* CALLS */
241 /* */
242 /* _tx_mutex_put Release the mutex */
243 /* */
244 /* CALLED BY */
245 /* */
246 /* _tx_thread_shell_entry Thread completion processing */
247 /* _tx_thread_terminate Thread terminate processing */
248 /* */
249 /* RELEASE HISTORY */
250 /* */
251 /* DATE NAME DESCRIPTION */
252 /* */
253 /* 05-19-2020 William E. Lamie Initial Version 6.0 */
254 /* 09-30-2020 Yuxin Zhou Modified comment(s), */
255 /* resulting in version 6.1 */
256 /* */
257 /**************************************************************************/
_tx_mutex_thread_release(TX_THREAD * thread_ptr)258 VOID _tx_mutex_thread_release(TX_THREAD *thread_ptr)
259 {
260
261 TX_INTERRUPT_SAVE_AREA
262
263 TX_MUTEX *mutex_ptr;
264 #ifdef TX_MISRA_ENABLE
265 UINT status;
266 #endif
267
268
269 /* Disable interrupts. */
270 TX_DISABLE
271
272 /* Temporarily disable preemption. */
273 _tx_thread_preempt_disable++;
274
275 /* Loop to look at all the mutexes. */
276 do
277 {
278
279 /* Pickup the mutex head pointer. */
280 mutex_ptr = thread_ptr -> tx_thread_owned_mutex_list;
281
282 /* Determine if there is a mutex. */
283 if (mutex_ptr != TX_NULL)
284 {
285
286 /* Yes, set the ownership count to 1. */
287 mutex_ptr -> tx_mutex_ownership_count = ((UINT) 1);
288
289 /* Restore interrupts. */
290 TX_RESTORE
291
292 #ifdef TX_MISRA_ENABLE
293 /* Release the mutex. */
294 do
295 {
296 status = _tx_mutex_put(mutex_ptr);
297 } while (status != TX_SUCCESS);
298 #else
299 _tx_mutex_put(mutex_ptr);
300 #endif
301
302 /* Disable interrupts. */
303 TX_DISABLE
304
305 /* Move to the next mutex. */
306 mutex_ptr = thread_ptr -> tx_thread_owned_mutex_list;
307 }
308 } while (mutex_ptr != TX_NULL);
309
310 /* Restore preemption. */
311 _tx_thread_preempt_disable--;
312
313 /* Restore interrupts. */
314 TX_RESTORE
315 }
316
317