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