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 /** Event Flags */
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_event_flags.h"
32
33
34 /**************************************************************************/
35 /* */
36 /* FUNCTION RELEASE */
37 /* */
38 /* _tx_event_flags_get PORTABLE C */
39 /* 6.2.0 */
40 /* AUTHOR */
41 /* */
42 /* William E. Lamie, Microsoft Corporation */
43 /* */
44 /* DESCRIPTION */
45 /* */
46 /* This function gets the specified event flags from the group, */
47 /* according to the get option. The get option also specifies whether */
48 /* or not the retrieved flags are cleared. */
49 /* */
50 /* INPUT */
51 /* */
52 /* group_ptr Pointer to group control block */
53 /* requested_event_flags Event flags requested */
54 /* get_option Specifies and/or and clear options*/
55 /* actual_flags_ptr Pointer to place the actual flags */
56 /* the service retrieved */
57 /* wait_option Suspension option */
58 /* */
59 /* OUTPUT */
60 /* */
61 /* status Completion status */
62 /* */
63 /* CALLS */
64 /* */
65 /* _tx_thread_system_suspend Suspend thread service */
66 /* _tx_thread_system_ni_suspend Non-interruptable suspend thread */
67 /* */
68 /* CALLED BY */
69 /* */
70 /* Application Code */
71 /* */
72 /* RELEASE HISTORY */
73 /* */
74 /* DATE NAME DESCRIPTION */
75 /* */
76 /* 05-19-2020 William E. Lamie Initial Version 6.0 */
77 /* 09-30-2020 Yuxin Zhou Modified comment(s), */
78 /* resulting in version 6.1 */
79 /* 04-25-2022 Scott Larson Modified comment(s), */
80 /* handle 0 flags case, */
81 /* resulting in version 6.1.11 */
82 /* 10-31-2022 Scott Larson Modified comment(s), always */
83 /* return actual flags, */
84 /* resulting in version 6.2.0 */
85 /* */
86 /**************************************************************************/
_tx_event_flags_get(TX_EVENT_FLAGS_GROUP * group_ptr,ULONG requested_flags,UINT get_option,ULONG * actual_flags_ptr,ULONG wait_option)87 UINT _tx_event_flags_get(TX_EVENT_FLAGS_GROUP *group_ptr, ULONG requested_flags,
88 UINT get_option, ULONG *actual_flags_ptr, ULONG wait_option)
89 {
90
91 TX_INTERRUPT_SAVE_AREA
92
93 UINT status;
94 UINT and_request;
95 UINT clear_request;
96 ULONG current_flags;
97 ULONG flags_satisfied;
98 #ifndef TX_NOT_INTERRUPTABLE
99 ULONG delayed_clear_flags;
100 #endif
101 UINT suspended_count;
102 TX_THREAD *thread_ptr;
103 TX_THREAD *next_thread;
104 TX_THREAD *previous_thread;
105 #ifndef TX_NOT_INTERRUPTABLE
106 UINT interrupted_set_request;
107 #endif
108
109
110 /* Disable interrupts to examine the event flags group. */
111 TX_DISABLE
112
113 #ifdef TX_EVENT_FLAGS_ENABLE_PERFORMANCE_INFO
114
115 /* Increment the total event flags get counter. */
116 _tx_event_flags_performance_get_count++;
117
118 /* Increment the number of event flags gets on this semaphore. */
119 group_ptr -> tx_event_flags_group__performance_get_count++;
120 #endif
121
122 /* If trace is enabled, insert this event into the trace buffer. */
123 TX_TRACE_IN_LINE_INSERT(TX_TRACE_EVENT_FLAGS_GET, group_ptr, requested_flags, group_ptr -> tx_event_flags_group_current, get_option, TX_TRACE_EVENT_FLAGS_EVENTS)
124
125 /* Log this kernel call. */
126 TX_EL_EVENT_FLAGS_GET_INSERT
127
128 /* Pickup current flags. */
129 current_flags = group_ptr -> tx_event_flags_group_current;
130
131 /* Return the actual event flags and apply delayed clearing. */
132 *actual_flags_ptr = current_flags & ~group_ptr -> tx_event_flags_group_delayed_clear;
133
134 /* Apply the event flag option mask. */
135 and_request = (get_option & TX_AND);
136
137 #ifdef TX_NOT_INTERRUPTABLE
138
139 /* Check for AND condition. All flags must be present to satisfy request. */
140 if (and_request == TX_AND)
141 {
142
143 /* AND request is present. */
144
145 /* Calculate the flags present. */
146 flags_satisfied = (current_flags & requested_flags);
147
148 /* Determine if they satisfy the AND request. */
149 if (flags_satisfied != requested_flags)
150 {
151
152 /* No, not all the requested flags are present. Clear the flags present variable. */
153 flags_satisfied = ((ULONG) 0);
154 }
155 }
156 else
157 {
158
159 /* OR request is present. Simply or the requested flags and the current flags. */
160 flags_satisfied = (current_flags & requested_flags);
161 }
162
163 /* Determine if the request is satisfied. */
164 if (flags_satisfied != ((ULONG) 0))
165 {
166
167 /* Pickup the clear bit. */
168 clear_request = (get_option & TX_EVENT_FLAGS_CLEAR_MASK);
169
170 /* Determine whether or not clearing needs to take place. */
171 if (clear_request == TX_TRUE)
172 {
173
174 /* Yes, clear the flags that satisfied this request. */
175 group_ptr -> tx_event_flags_group_current =
176 group_ptr -> tx_event_flags_group_current & (~requested_flags);
177 }
178
179 /* Return success. */
180 status = TX_SUCCESS;
181 }
182
183 #else
184
185 /* Pickup delayed clear flags. */
186 delayed_clear_flags = group_ptr -> tx_event_flags_group_delayed_clear;
187
188 /* Determine if there are any delayed clear operations pending. */
189 if (delayed_clear_flags != ((ULONG) 0))
190 {
191
192 /* Yes, apply them to the current flags. */
193 current_flags = current_flags & (~delayed_clear_flags);
194 }
195
196 /* Check for AND condition. All flags must be present to satisfy request. */
197 if (and_request == TX_AND)
198 {
199
200 /* AND request is present. */
201
202 /* Calculate the flags present. */
203 flags_satisfied = (current_flags & requested_flags);
204
205 /* Determine if they satisfy the AND request. */
206 if (flags_satisfied != requested_flags)
207 {
208
209 /* No, not all the requested flags are present. Clear the flags present variable. */
210 flags_satisfied = ((ULONG) 0);
211 }
212 }
213 else
214 {
215
216 /* OR request is present. Simply AND together the requested flags and the current flags
217 to see if any are present. */
218 flags_satisfied = (current_flags & requested_flags);
219 }
220
221 /* Determine if the request is satisfied. */
222 if (flags_satisfied != ((ULONG) 0))
223 {
224
225 /* Yes, this request can be handled immediately. */
226
227 /* Pickup the clear bit. */
228 clear_request = (get_option & TX_EVENT_FLAGS_CLEAR_MASK);
229
230 /* Determine whether or not clearing needs to take place. */
231 if (clear_request == TX_TRUE)
232 {
233
234 /* Set interrupted set request flag to false. */
235 interrupted_set_request = TX_FALSE;
236
237 /* Determine if the suspension list is being processed by an interrupted
238 set request. */
239 if (group_ptr -> tx_event_flags_group_suspended_count != TX_NO_SUSPENSIONS)
240 {
241
242 if (group_ptr -> tx_event_flags_group_suspension_list == TX_NULL)
243 {
244
245 /* Set the interrupted set request flag. */
246 interrupted_set_request = TX_TRUE;
247 }
248 }
249
250 /* Was a set request interrupted? */
251 if (interrupted_set_request == TX_TRUE)
252 {
253
254 /* A previous set operation is was interrupted, we need to defer the
255 event clearing until the set operation is complete. */
256
257 /* Remember the events to clear. */
258 group_ptr -> tx_event_flags_group_delayed_clear =
259 group_ptr -> tx_event_flags_group_delayed_clear | requested_flags;
260 }
261 else
262 {
263
264 /* Yes, clear the flags that satisfied this request. */
265 group_ptr -> tx_event_flags_group_current =
266 group_ptr -> tx_event_flags_group_current & ~requested_flags;
267 }
268 }
269
270 /* Set status to success. */
271 status = TX_SUCCESS;
272 }
273
274 #endif
275 else
276 {
277 /* flags_satisfied is 0. */
278 /* Determine if the request specifies suspension. */
279 if (wait_option != TX_NO_WAIT)
280 {
281
282 /* Determine if the preempt disable flag is non-zero OR the requested events is 0. */
283 if ((_tx_thread_preempt_disable != ((UINT) 0)) || (requested_flags == (UINT) 0))
284 {
285
286 /* Suspension is not allowed if the preempt disable flag is non-zero at this point,
287 or if requested_flags is 0, return error completion. */
288 status = TX_NO_EVENTS;
289 }
290 else
291 {
292
293 /* Prepare for suspension of this thread. */
294
295 #ifdef TX_EVENT_FLAGS_ENABLE_PERFORMANCE_INFO
296
297 /* Increment the total event flags suspensions counter. */
298 _tx_event_flags_performance_suspension_count++;
299
300 /* Increment the number of event flags suspensions on this semaphore. */
301 group_ptr -> tx_event_flags_group___performance_suspension_count++;
302 #endif
303
304 /* Pickup thread pointer. */
305 TX_THREAD_GET_CURRENT(thread_ptr)
306
307 /* Setup cleanup routine pointer. */
308 thread_ptr -> tx_thread_suspend_cleanup = &(_tx_event_flags_cleanup);
309
310 /* Remember which event flags we are looking for. */
311 thread_ptr -> tx_thread_suspend_info = requested_flags;
312
313 /* Save the get option as well. */
314 thread_ptr -> tx_thread_suspend_option = get_option;
315
316 /* Save the destination for the current events. */
317 thread_ptr -> tx_thread_additional_suspend_info = (VOID *) actual_flags_ptr;
318
319 /* Setup cleanup information, i.e. this event flags group control
320 block. */
321 thread_ptr -> tx_thread_suspend_control_block = (VOID *) group_ptr;
322
323 #ifndef TX_NOT_INTERRUPTABLE
324
325 /* Increment the suspension sequence number, which is used to identify
326 this suspension event. */
327 thread_ptr -> tx_thread_suspension_sequence++;
328 #endif
329
330 /* Pickup the suspended count. */
331 suspended_count = group_ptr -> tx_event_flags_group_suspended_count;
332
333 /* Setup suspension list. */
334 if (suspended_count == TX_NO_SUSPENSIONS)
335 {
336
337 /* No other threads are suspended. Setup the head pointer and
338 just setup this threads pointers to itself. */
339 group_ptr -> tx_event_flags_group_suspension_list = thread_ptr;
340 thread_ptr -> tx_thread_suspended_next = thread_ptr;
341 thread_ptr -> tx_thread_suspended_previous = thread_ptr;
342 }
343 else
344 {
345
346 /* This list is not NULL, add current thread to the end. */
347 next_thread = group_ptr -> tx_event_flags_group_suspension_list;
348 thread_ptr -> tx_thread_suspended_next = next_thread;
349 previous_thread = next_thread -> tx_thread_suspended_previous;
350 thread_ptr -> tx_thread_suspended_previous = previous_thread;
351 previous_thread -> tx_thread_suspended_next = thread_ptr;
352 next_thread -> tx_thread_suspended_previous = thread_ptr;
353 }
354
355 /* Increment the number of threads suspended. */
356 group_ptr -> tx_event_flags_group_suspended_count++;
357
358 /* Set the state to suspended. */
359 thread_ptr -> tx_thread_state = TX_EVENT_FLAG;
360
361 #ifdef TX_NOT_INTERRUPTABLE
362
363 /* Call actual non-interruptable thread suspension routine. */
364 _tx_thread_system_ni_suspend(thread_ptr, wait_option);
365
366 /* Return the completion status. */
367 status = thread_ptr -> tx_thread_suspend_status;
368 #else
369
370 /* Set the suspending flag. */
371 thread_ptr -> tx_thread_suspending = TX_TRUE;
372
373 /* Setup the timeout period. */
374 thread_ptr -> tx_thread_timer.tx_timer_internal_remaining_ticks = wait_option;
375
376 /* Temporarily disable preemption. */
377 _tx_thread_preempt_disable++;
378
379 /* Restore interrupts. */
380 TX_RESTORE
381
382 /* Call actual thread suspension routine. */
383 _tx_thread_system_suspend(thread_ptr);
384
385 /* Disable interrupts. */
386 TX_DISABLE
387
388 /* Return the completion status. */
389 status = thread_ptr -> tx_thread_suspend_status;
390 #endif
391 }
392 }
393 else
394 {
395
396 /* Immediate return, return error completion. */
397 status = TX_NO_EVENTS;
398 }
399 }
400
401 /* Restore interrupts. */
402 TX_RESTORE
403
404 /* Return completion status. */
405 return(status);
406 }
407
408