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