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