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 #include <stdio.h>
33 #include <errno.h>
34
35 extern sem_t _tx_linux_timer_semaphore;
36 extern sem_t _tx_linux_isr_semaphore;
37 extern UINT _tx_linux_timer_waiting;
38 extern pthread_t _tx_linux_timer_id;
39 /**************************************************************************/
40 /* */
41 /* FUNCTION RELEASE */
42 /* */
43 /* _tx_thread_schedule Linux/GNU */
44 /* 6.1 */
45 /* AUTHOR */
46 /* */
47 /* William E. Lamie, Microsoft Corporation */
48 /* */
49 /* DESCRIPTION */
50 /* */
51 /* This function waits for a thread control block pointer to appear in */
52 /* the _tx_thread_execute_ptr variable. Once a thread pointer appears */
53 /* in the variable, the corresponding thread is resumed. */
54 /* */
55 /* INPUT */
56 /* */
57 /* None */
58 /* */
59 /* OUTPUT */
60 /* */
61 /* None */
62 /* */
63 /* CALLS */
64 /* */
65 /* tx_linux_mutex_lock */
66 /* tx_linux_mutex_unlock */
67 /* _tx_linux_debug_entry_insert */
68 /* _tx_linux_thread_resume */
69 /* tx_linux_sem_post */
70 /* sem_trywait */
71 /* tx_linux_sem_wait */
72 /* */
73 /* CALLED BY */
74 /* */
75 /* _tx_initialize_kernel_enter ThreadX entry function */
76 /* */
77 /* RELEASE HISTORY */
78 /* */
79 /* DATE NAME DESCRIPTION */
80 /* */
81 /* 09-30-2020 William E. Lamie Initial Version 6.1 */
82 /* */
83 /**************************************************************************/
_tx_thread_schedule(VOID)84 VOID _tx_thread_schedule(VOID)
85 {
86 struct timespec ts;
87
88 /* Set timer. */
89 ts.tv_sec = 0;
90 ts.tv_nsec = 200000;
91
92 /* Loop forever. */
93 while(1)
94 {
95
96 /* Wait for a thread to execute and all ISRs to complete. */
97 while(1)
98 {
99
100 /* Lock Linux mutex. */
101 tx_linux_mutex_lock(_tx_linux_mutex);
102
103 /* Determine if there is a thread ready to execute AND all ISRs
104 are complete. */
105 if ((_tx_thread_execute_ptr != TX_NULL) && (_tx_thread_system_state == 0))
106 {
107
108 /* Get out of this loop and schedule the thread! */
109 break;
110 }
111 else
112 {
113
114 /* Unlock linux mutex. */
115 tx_linux_mutex_unlock(_tx_linux_mutex);
116
117 /* Don't waste all the processor time here in the master thread... */
118 #ifdef TX_LINUX_NO_IDLE_ENABLE
119 while(!sem_trywait(&_tx_linux_timer_semaphore));
120 tx_linux_sem_post(&_tx_linux_timer_semaphore);
121 /*nanosleep(&ts, &ts);*/
122
123 clock_gettime(CLOCK_REALTIME, &ts);
124 ts.tv_nsec += 200000;
125 if (ts.tv_nsec > 1000000000)
126 {
127 ts.tv_nsec -= 1000000000;
128 ts.tv_sec++;
129 }
130 sem_timedwait(&_tx_linux_semaphore_no_idle, &ts);
131 #else
132 nanosleep(&ts, &ts);
133 #endif /* TX_LINUX_NO_IDLE_ENABLE */
134 }
135 }
136
137 /* Yes! We have a thread to execute. Note that the critical section is already
138 active from the scheduling loop above. */
139
140 /* Setup the current thread pointer. */
141 _tx_thread_current_ptr = _tx_thread_execute_ptr;
142
143 /* Increment the run count for this thread. */
144 _tx_thread_current_ptr -> tx_thread_run_count++;
145
146 /* Setup time-slice, if present. */
147 _tx_timer_time_slice = _tx_thread_current_ptr -> tx_thread_time_slice;
148
149 /* Determine how the thread was suspended. */
150 if (_tx_thread_current_ptr -> tx_thread_linux_suspension_type)
151 {
152
153 /* Debug entry. */
154 _tx_linux_debug_entry_insert("SCHEDULE-resume_thread", __FILE__, __LINE__);
155
156 /* Pseudo interrupt suspension. The thread is not waiting on
157 its run semaphore. */
158 _tx_linux_thread_resume(_tx_thread_current_ptr -> tx_thread_linux_thread_id);
159 }
160 else
161 {
162
163 /* Debug entry. */
164 _tx_linux_debug_entry_insert("SCHEDULE-release_sem", __FILE__, __LINE__);
165
166 /* Make sure semaphore is 0. */
167 while(!sem_trywait(&_tx_thread_current_ptr -> tx_thread_linux_thread_run_semaphore));
168
169 /* Let the thread run again by releasing its run semaphore. */
170 tx_linux_sem_post(&_tx_thread_current_ptr -> tx_thread_linux_thread_run_semaphore);
171
172 /* Block timer ISR. */
173 if(_tx_linux_timer_waiting)
174 {
175
176 /* It is woken up by timer ISR. */
177 /* Let ThreadX thread wake up first. */
178 tx_linux_sem_wait(&_tx_linux_semaphore);
179
180 /* Wake up timer ISR. */
181 tx_linux_sem_post_nolock(&_tx_linux_isr_semaphore);
182 }
183 else
184 {
185
186 /* It is woken up by TX_THREAD. */
187 /* Suspend timer thread and let ThreadX thread wake up first. */
188 _tx_linux_thread_suspend(_tx_linux_timer_id);
189 tx_linux_sem_wait(&_tx_linux_semaphore);
190 _tx_linux_thread_resume(_tx_linux_timer_id);
191
192 }
193 }
194
195 /* Unlock linux mutex. */
196 tx_linux_mutex_unlock(_tx_linux_mutex);
197
198 /* Debug entry. */
199 _tx_linux_debug_entry_insert("SCHEDULE-self_suspend_sem", __FILE__, __LINE__);
200
201 /* Now suspend the main thread so the application thread can run. */
202 tx_linux_sem_wait(&_tx_linux_semaphore);
203
204 /* Debug entry. */
205 _tx_linux_debug_entry_insert("SCHEDULE-wake_up", __FILE__, __LINE__);
206
207 }
208 }
209
_tx_thread_delete_port_completion(TX_THREAD * thread_ptr,UINT tx_saved_posture)210 void _tx_thread_delete_port_completion(TX_THREAD *thread_ptr, UINT tx_saved_posture)
211 {
212 INT linux_status;
213 sem_t *threadrunsemaphore;
214 pthread_t thread_id;
215 struct timespec ts;
216
217 thread_id = thread_ptr -> tx_thread_linux_thread_id;
218 threadrunsemaphore = &(thread_ptr -> tx_thread_linux_thread_run_semaphore);
219 ts.tv_sec = 0;
220 ts.tv_nsec = 1000000;
221 TX_RESTORE
222 do
223 {
224 linux_status = pthread_cancel(thread_id);
225 if(linux_status != EAGAIN)
226 {
227 break;
228 }
229 _tx_linux_thread_resume(thread_id);
230 tx_linux_sem_post(threadrunsemaphore);
231 nanosleep(&ts, &ts);
232 } while (1);
233 pthread_join(thread_id, NULL);
234 sem_destroy(threadrunsemaphore);
235 TX_DISABLE
236 }
237
_tx_thread_reset_port_completion(TX_THREAD * thread_ptr,UINT tx_saved_posture)238 void _tx_thread_reset_port_completion(TX_THREAD *thread_ptr, UINT tx_saved_posture)
239 {
240 INT linux_status;
241 sem_t *threadrunsemaphore;
242 pthread_t thread_id;
243 struct timespec ts;
244
245 thread_id = thread_ptr -> tx_thread_linux_thread_id;
246 threadrunsemaphore = &(thread_ptr -> tx_thread_linux_thread_run_semaphore);
247 ts.tv_sec = 0;
248 ts.tv_nsec = 1000000;
249 TX_RESTORE
250 do
251 {
252 linux_status = pthread_cancel(thread_id);
253 if(linux_status != EAGAIN)
254 {
255 break;
256 }
257 _tx_linux_thread_resume(thread_id);
258 tx_linux_sem_post(threadrunsemaphore);
259 nanosleep(&ts, &ts);
260 } while (1);
261 pthread_join(thread_id, NULL);
262 sem_destroy(threadrunsemaphore);
263 TX_DISABLE
264 }
265