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 /**   Thread                                                              */
18 /**                                                                       */
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_timer.h"
31 
32 
33 /**************************************************************************/
34 /*                                                                        */
35 /*  FUNCTION                                               RELEASE        */
36 /*                                                                        */
37 /*    _tx_thread_schedule                               Win32/Visual      */
38 /*                                                           6.1          */
39 /*  AUTHOR                                                                */
40 /*                                                                        */
41 /*    William E. Lamie, Microsoft Corporation                             */
42 /*                                                                        */
43 /*  DESCRIPTION                                                           */
44 /*                                                                        */
45 /*    This function waits for a thread control block pointer to appear in */
46 /*    the _tx_thread_execute_ptr variable.  Once a thread pointer appears */
47 /*    in the variable, the corresponding thread is resumed.               */
48 /*                                                                        */
49 /*  INPUT                                                                 */
50 /*                                                                        */
51 /*    None                                                                */
52 /*                                                                        */
53 /*  OUTPUT                                                                */
54 /*                                                                        */
55 /*    None                                                                */
56 /*                                                                        */
57 /*  CALLS                                                                 */
58 /*                                                                        */
59 /*    ReleaseSemaphore                      Win32 release semaphore       */
60 /*    ResumeThread                          Win32 resume thread           */
61 /*    Sleep                                 Win32 thread sleep            */
62 /*    WaitForSingleObject                   Win32 wait on a semaphore     */
63 /*    _tx_win32_critical_section_obtain     Obtain critical section       */
64 /*    _tx_win32_critical_section_release    Release critical section      */
65 /*                                                                        */
66 /*  CALLED BY                                                             */
67 /*                                                                        */
68 /*    _tx_initialize_kernel_enter          ThreadX entry function         */
69 /*                                                                        */
70 /*  RELEASE HISTORY                                                       */
71 /*                                                                        */
72 /*    DATE              NAME                      DESCRIPTION             */
73 /*                                                                        */
74 /*  09-30-2020     William E. Lamie         Initial Version 6.1           */
75 /*                                                                        */
76 /**************************************************************************/
_tx_thread_schedule(VOID)77 VOID   _tx_thread_schedule(VOID)
78 {
79 
80 
81     /* Loop forever.  */
82     while(1)
83     {
84 
85         /* Wait for a thread to execute and all ISRs to complete.  */
86         while(1)
87         {
88 
89 
90             /* Enter Win32 critical section.  */
91             _tx_win32_critical_section_obtain(&_tx_win32_critical_section);
92 
93             /* Debug entry.  */
94             _tx_win32_debug_entry_insert("SCHEDULE-wake_up", __FILE__, __LINE__);
95 
96             /* Determine if there is a thread ready to execute AND all ISRs
97                are complete.  */
98             if ((_tx_thread_execute_ptr != TX_NULL) && (_tx_thread_system_state == 0))
99             {
100 
101                 /* Get out of this loop and schedule the thread!  */
102                 break;
103             }
104             else
105             {
106 
107                 /* Leave the critical section.  */
108                 _tx_win32_critical_section_release(&_tx_win32_critical_section);
109 
110                 /* Now sleep so we don't block forever.  */
111                 Sleep(2);
112             }
113         }
114 
115         /* Yes! We have a thread to execute. Note that the critical section is already
116            active from the scheduling loop above.  */
117 
118         /* Setup the current thread pointer.  */
119         _tx_thread_current_ptr =  _tx_thread_execute_ptr;
120 
121         /* Increment the run count for this thread.  */
122         _tx_thread_current_ptr -> tx_thread_run_count++;
123 
124         /* Setup time-slice, if present.  */
125         _tx_timer_time_slice =  _tx_thread_current_ptr -> tx_thread_time_slice;
126 
127         /* Determine how the thread was suspended.  */
128         if (_tx_thread_current_ptr -> tx_thread_win32_suspension_type)
129         {
130 
131             /* Debug entry.  */
132             _tx_win32_debug_entry_insert("SCHEDULE-resume_thread", __FILE__, __LINE__);
133 
134             /* Pseudo interrupt suspension.  The thread is not waiting on
135                its run semaphore.  */
136             ResumeThread(_tx_thread_current_ptr -> tx_thread_win32_thread_handle);
137         }
138         else
139         {
140 
141             /* Debug entry.  */
142             _tx_win32_debug_entry_insert("SCHEDULE-release_sem", __FILE__, __LINE__);
143 
144             /* Let the thread run again by releasing its run semaphore.  */
145             ReleaseSemaphore(_tx_thread_current_ptr -> tx_thread_win32_thread_run_semaphore, 1, NULL);
146         }
147 
148         /* Debug entry.  */
149         _tx_win32_debug_entry_insert("SCHEDULE-self_suspend_sem", __FILE__, __LINE__);
150 
151         /* Exit Win32 critical section.  */
152         _tx_win32_critical_section_release(&_tx_win32_critical_section);
153 
154         /* Now suspend the main thread so the application thread can run.  */
155         WaitForSingleObject(_tx_win32_scheduler_semaphore, INFINITE);
156     }
157 }
158 
159 
160 /* Define the ThreadX Win32 critical section get, release, and release all functions.  */
161 
_tx_win32_critical_section_obtain(TX_WIN32_CRITICAL_SECTION * critical_section)162 void    _tx_win32_critical_section_obtain(TX_WIN32_CRITICAL_SECTION *critical_section)
163 {
164 
165 TX_THREAD     *thread_ptr;
166 
167 
168     /* Is the protection owned?  */
169     if (critical_section -> tx_win32_critical_section_owner == GetCurrentThreadId())
170     {
171 
172         /* Simply increment the nested counter.  */
173         critical_section -> tx_win32_critical_section_nested_count++;
174     }
175     else
176     {
177 
178         /* Pickup the current thread pointer.  */
179         thread_ptr =  _tx_thread_current_ptr;
180 
181         /* Get the Win32 critical section.  */
182         while (WaitForSingleObject(critical_section -> tx_win32_critical_section_mutex_handle, 3) != WAIT_OBJECT_0)
183         {
184         }
185 
186         /* At this point we have the mutex.  */
187 
188         /* Increment the nesting counter.  */
189         critical_section -> tx_win32_critical_section_nested_count =  1;
190 
191         /* Remember the owner.  */
192         critical_section -> tx_win32_critical_section_owner =  GetCurrentThreadId();
193     }
194 }
195 
196 
_tx_win32_critical_section_release(TX_WIN32_CRITICAL_SECTION * critical_section)197 void    _tx_win32_critical_section_release(TX_WIN32_CRITICAL_SECTION *critical_section)
198 {
199 
200 
201     /* Ensure the caller is the mutex owner.  */
202     if (critical_section -> tx_win32_critical_section_owner == GetCurrentThreadId())
203     {
204 
205         /* Determine if there is protection.  */
206         if (critical_section -> tx_win32_critical_section_nested_count)
207         {
208 
209             /* Decrement the nesting counter.  */
210             critical_section -> tx_win32_critical_section_nested_count--;
211 
212             /* Determine if the critical section is now being released.  */
213             if (critical_section -> tx_win32_critical_section_nested_count == 0)
214             {
215 
216                 /* Yes, it is being released clear the owner.  */
217                 critical_section -> tx_win32_critical_section_owner =  0;
218 
219                 /* Finally, release the mutex.  */
220                 if (ReleaseMutex(critical_section -> tx_win32_critical_section_mutex_handle) != TX_TRUE)
221                 {
222 
223                     /* Increment the system error counter.  */
224                     _tx_win32_system_error++;
225                 }
226 
227                 /* Just in case, make sure there the mutex is not owned.  */
228                 while (ReleaseMutex(critical_section -> tx_win32_critical_section_mutex_handle) == TX_TRUE)
229                 {
230 
231                     /* Increment the system error counter.  */
232                     _tx_win32_system_error++;
233                 }
234 
235                 /* Sleep for 0, just to relinquish to other ready threads.  */
236                 Sleep(0);
237 			}
238         }
239     }
240     else
241     {
242 
243         /* Increment the system error counter.  */
244         _tx_win32_system_error++;
245     }
246 }
247 
248 
_tx_win32_critical_section_release_all(TX_WIN32_CRITICAL_SECTION * critical_section)249 void    _tx_win32_critical_section_release_all(TX_WIN32_CRITICAL_SECTION    *critical_section)
250 {
251 
252     /* Ensure the caller is the mutex owner.  */
253     if (critical_section -> tx_win32_critical_section_owner == GetCurrentThreadId())
254     {
255 
256         /* Determine if there is protection.  */
257         if (critical_section -> tx_win32_critical_section_nested_count)
258         {
259 
260             /* Clear the nesting counter.  */
261             critical_section -> tx_win32_critical_section_nested_count =  0;
262 
263             /* Yes, it is being release clear the owner.  */
264             critical_section -> tx_win32_critical_section_owner =  0;
265 
266             /* Finally, release the mutex.  */
267             if (ReleaseMutex(critical_section -> tx_win32_critical_section_mutex_handle) != TX_TRUE)
268             {
269 
270                 /* Increment the system error counter.  */
271                 _tx_win32_system_error++;
272             }
273 
274             /* Just in case, make sure there the mutex is not owned.  */
275             while (ReleaseMutex(critical_section -> tx_win32_critical_section_mutex_handle) == TX_TRUE)
276             {
277 
278                 /* Increment the system error counter.  */
279                 _tx_win32_system_error++;
280             }
281         }
282     }
283     else
284     {
285 
286         /* Increment the system error counter.  */
287         _tx_win32_system_error++;
288     }
289 }
290 
291