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 /** Event Flags */
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_event_flags.h"
30
31
32 /**************************************************************************/
33 /* */
34 /* FUNCTION RELEASE */
35 /* */
36 /* _tx_event_flags_cleanup PORTABLE C */
37 /* 6.1 */
38 /* AUTHOR */
39 /* */
40 /* William E. Lamie, Microsoft Corporation */
41 /* */
42 /* DESCRIPTION */
43 /* */
44 /* This function processes event flags timeout and thread terminate */
45 /* actions that require the event flags 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_event_flags_cleanup(TX_THREAD * thread_ptr,ULONG suspension_sequence)77 VOID _tx_event_flags_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_EVENT_FLAGS_GROUP *group_ptr;
85 UINT suspended_count;
86 TX_THREAD *suspension_head;
87 TX_THREAD *next_thread;
88 TX_THREAD *previous_thread;
89
90
91 #ifndef TX_NOT_INTERRUPTABLE
92
93 /* Disable interrupts to remove the suspended thread from the event flags group. */
94 TX_DISABLE
95
96 /* Determine if the cleanup is still required. */
97 if (thread_ptr -> tx_thread_suspend_cleanup == &(_tx_event_flags_cleanup))
98 {
99
100 /* Check for valid suspension sequence. */
101 if (suspension_sequence == thread_ptr -> tx_thread_suspension_sequence)
102 {
103
104 /* Setup pointer to event flags control block. */
105 group_ptr = TX_VOID_TO_EVENT_FLAGS_POINTER_CONVERT(thread_ptr -> tx_thread_suspend_control_block);
106
107 /* Check for a NULL event flags control block pointer. */
108 if (group_ptr != TX_NULL)
109 {
110
111 /* Is the group pointer ID valid? */
112 if (group_ptr -> tx_event_flags_group_id == TX_EVENT_FLAGS_ID)
113 {
114
115 /* Determine if there are any thread suspensions. */
116 if (group_ptr -> tx_event_flags_group_suspended_count != TX_NO_SUSPENSIONS)
117 {
118 #else
119
120 /* Setup pointer to event flags control block. */
121 group_ptr = TX_VOID_TO_EVENT_FLAGS_POINTER_CONVERT(thread_ptr -> tx_thread_suspend_control_block);
122 #endif
123
124 /* Yes, we still have thread suspension! */
125
126 /* Clear the suspension cleanup flag. */
127 thread_ptr -> tx_thread_suspend_cleanup = TX_NULL;
128
129 /* Pickup the suspended count. */
130 suspended_count = group_ptr -> tx_event_flags_group_suspended_count;
131
132 /* Pickup the suspension head. */
133 suspension_head = group_ptr -> tx_event_flags_group_suspension_list;
134
135 /* Determine if the cleanup is being done while a set operation was interrupted. If the
136 suspended count is non-zero and the suspension head is NULL, the list is being processed
137 and cannot be touched from here. The suspension list removal will instead take place
138 inside the event flag set code. */
139 if (suspension_head != TX_NULL)
140 {
141
142 /* Remove the suspended thread from the list. */
143
144 /* Decrement the local suspension count. */
145 suspended_count--;
146
147 /* Store the updated suspended count. */
148 group_ptr -> tx_event_flags_group_suspended_count = suspended_count;
149
150 /* See if this is the only suspended thread on the list. */
151 if (suspended_count == TX_NO_SUSPENSIONS)
152 {
153
154 /* Yes, the only suspended thread. */
155
156 /* Update the head pointer. */
157 group_ptr -> tx_event_flags_group_suspension_list = TX_NULL;
158 }
159 else
160 {
161
162 /* At least one more thread is on the same suspension list. */
163
164 /* Update the links of the adjacent threads. */
165 next_thread = thread_ptr -> tx_thread_suspended_next;
166 previous_thread = thread_ptr -> tx_thread_suspended_previous;
167 next_thread -> tx_thread_suspended_previous = previous_thread;
168 previous_thread -> tx_thread_suspended_next = next_thread;
169
170 /* Determine if we need to update the head pointer. */
171 if (suspension_head == thread_ptr)
172 {
173
174 /* Update the list head pointer. */
175 group_ptr -> tx_event_flags_group_suspension_list = next_thread;
176 }
177 }
178 }
179 else
180 {
181
182 /* In this case, the search pointer in an interrupted event flag set must be reset. */
183 group_ptr -> tx_event_flags_group_reset_search = TX_TRUE;
184 }
185
186 /* Now we need to determine if this cleanup is from a terminate, timeout,
187 or from a wait abort. */
188 if (thread_ptr -> tx_thread_state == TX_EVENT_FLAG)
189 {
190
191 /* Timeout condition and the thread still suspended on the event flags group.
192 Setup return error status and resume the thread. */
193
194 #ifdef TX_EVENT_FLAGS_ENABLE_PERFORMANCE_INFO
195
196 /* Increment the total timeouts counter. */
197 _tx_event_flags_performance_timeout_count++;
198
199 /* Increment the number of timeouts on this event flags group. */
200 group_ptr -> tx_event_flags_group____performance_timeout_count++;
201 #endif
202
203 /* Setup return status. */
204 thread_ptr -> tx_thread_suspend_status = TX_NO_EVENTS;
205
206 #ifdef TX_NOT_INTERRUPTABLE
207
208 /* Resume the thread! */
209 _tx_thread_system_ni_resume(thread_ptr);
210 #else
211
212 /* Temporarily disable preemption. */
213 _tx_thread_preempt_disable++;
214
215 /* Restore interrupts. */
216 TX_RESTORE
217
218 /* Resume the thread! Check for preemption even though we are executing
219 from the system timer thread right now which normally executes at the
220 highest priority. */
221 _tx_thread_system_resume(thread_ptr);
222
223 /* Disable interrupts. */
224 TX_DISABLE
225 #endif
226 }
227 #ifndef TX_NOT_INTERRUPTABLE
228 }
229 }
230 }
231 }
232 }
233
234 /* Restore interrupts. */
235 TX_RESTORE
236 #endif
237 }
238
239