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