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