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