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 #define TX_THREAD_SMP_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_smp_protect                            SMP/Linux/GCC     */
39 /*                                                           6.1          */
40 /*  AUTHOR                                                                */
41 /*                                                                        */
42 /*    William E. Lamie, Microsoft Corporation                             */
43 /*                                                                        */
44 /*  DESCRIPTION                                                           */
45 /*                                                                        */
46 /*    This function gets protection for running inside the ThreadX        */
47 /*    source. This is acomplished by a combination of a test-and-set      */
48 /*    flag and periodically disabling interrupts.                         */
49 /*                                                                        */
50 /*  INPUT                                                                 */
51 /*                                                                        */
52 /*    None                                                                */
53 /*                                                                        */
54 /*  OUTPUT                                                                */
55 /*                                                                        */
56 /*    Previous Status Register                                            */
57 /*                                                                        */
58 /*  CALLS                                                                 */
59 /*                                                                        */
60 /*    pthread_self                          Get Linux thread ID           */
61 /*    GetThreadPriority                     Get current thread priority   */
62 /*    _tx_thread_smp_core_get               Get the current core ID       */
63 /*                                                                        */
64 /*  CALLED BY                                                             */
65 /*                                                                        */
66 /*    ThreadX Source                                                      */
67 /*                                                                        */
68 /*  RELEASE HISTORY                                                       */
69 /*                                                                        */
70 /*    DATE              NAME                      DESCRIPTION             */
71 /*                                                                        */
72 /*  09-30-2020     William E. Lamie         Initial Version 6.1           */
73 /*                                                                        */
74 /**************************************************************************/
_tx_thread_smp_protect(void)75 UINT  _tx_thread_smp_protect(void)
76 {
77 
78 pthread_t   current_thread_id;
79 int         exit_code = 0;
80 struct sched_param sp;
81 UINT        core;
82 UINT        interrupt_posture;
83 TX_THREAD   *current_thread;
84 UINT        current_state;
85 
86     /* Loop to attempt to get the protection.  */
87     do
88     {
89 
90         /* First, get the critical section.  */
91         do
92         {
93 
94 
95             /* Lock Linux mutex.  */
96             _tx_linux_mutex_obtain(&_tx_linux_mutex);
97 
98             /* Pickup the current thread ID.  */
99             current_thread_id = pthread_self();
100 
101             /* Pickup the current core.   */
102             core =  _tx_thread_smp_core_get();
103 
104             /* Pickup the current thread pointer.  */
105             current_thread = _tx_thread_current_ptr[core];
106 
107             /* Determine if this is a thread (THREAD_PRIORITY_LOWEST) and it does not
108                match the current thread pointer.  */
109             if ((_tx_linux_threadx_thread) &&
110                 ((!current_thread) || (current_thread -> tx_thread_linux_thread_id != current_thread_id)))
111             {
112 
113                 /* This indicates the Linux thread was actually terminated by ThreadX is only
114                    being allowed to run in order to cleanup its resources.  */
115                 _tx_linux_mutex_release_all(&_tx_linux_mutex);
116 
117                 /* Exit this thread.  */
118                 pthread_exit((void *)&exit_code);
119             }
120 
121             /* Determine if this is not actually a thread.  */
122             if (!_tx_linux_threadx_thread)
123                 break;
124 
125             /* Now check for terminated or completed state... and preempt disable is not set!   */
126             if ((current_thread) && (_tx_thread_preempt_disable == 0))
127             {
128 
129                 /* Pickup current state.  */
130                 current_state =  current_thread -> tx_thread_state;
131 
132                 /* Now check for terminated or completed state.  */
133                 if ((current_state == TX_TERMINATED) || (current_state == TX_COMPLETED))
134                 {
135 
136                     /* Clear the preemption flag.  */
137                     current_thread -> tx_thread_linux_deferred_preempt =  TX_FALSE;
138 
139                     /* Indicate that this thread was suspended asynchronously.  */
140                     current_thread -> tx_thread_linux_suspension_type =  1;
141 
142                     /* Save the remaining time-slice and disable it.  */
143                     if (_tx_timer_time_slice[core])
144                     {
145 
146                         current_thread -> tx_thread_time_slice =  _tx_timer_time_slice[core];
147                         _tx_timer_time_slice[core] =  0;
148                     }
149 
150                     /* Clear the current thread pointer.  */
151                     _tx_thread_current_ptr[core] =  TX_NULL;
152 
153                     /* Clear this mapping entry.  */
154                     _tx_linux_virtual_cores[core].tx_thread_smp_core_mapping_thread =               TX_NULL;
155                     _tx_linux_virtual_cores[core].tx_thread_smp_core_mapping_linux_thread_id =      0;
156 
157                     /* Indicate that this thread is now ready for scheduling again by another core.  */
158                     current_thread -> tx_thread_smp_core_control =  1;
159 
160                     /* Debug entry.  */
161                     _tx_linux_debug_entry_insert("SCHEDULE-thread_terminate_preempt_complete", __FILE__, __LINE__);
162 
163                     /* Release the scheduler's semaphore to immediately try again.  */
164                     tx_linux_sem_post(&_tx_linux_scheduler_semaphore);
165 
166                     /* This indicates the Linux thread was actually terminated by ThreadX is only
167                        being allowed to run in order to cleanup its resources.  */
168                     _tx_linux_mutex_release_all(&_tx_linux_mutex);
169 
170                     /* Exit this thread.  */
171                     pthread_exit((void *)&exit_code);
172                 }
173             }
174 
175             /* Determine if the deferred preempt flag is set.  */
176             if ((current_thread) && (current_thread -> tx_thread_linux_deferred_preempt))
177             {
178 
179                 /* Release the scheduler's semaphore to immediately try again.  */
180                 tx_linux_sem_post(&_tx_linux_scheduler_semaphore);
181 
182                 /* Release the protection that is nested.  */
183                 _tx_linux_mutex_release_all(&_tx_linux_mutex);
184 
185                 /* Sleep just to let other threads run.  */
186                 _tx_linux_thread_sleep(1000000);
187             }
188             else
189             {
190 
191                 /* Get out of the protection loop.  */
192                 break;
193             }
194         } while (1);
195 
196         /* Setup the returned interrupt posture.  */
197         interrupt_posture =  _tx_linux_global_int_disabled_flag;
198 
199         /* Determine if the protection is already active for this core.  */
200         if (_tx_thread_smp_protection.tx_thread_smp_protect_core == core)
201         {
202 
203             /* Yes, we have the protection already.  */
204 
205             /* Increment the protection count.  */
206             _tx_thread_smp_protection.tx_thread_smp_protect_count++;
207 
208             /* Set the global interrupt disable value.  */
209             _tx_linux_global_int_disabled_flag =  TX_TRUE;
210 
211             /* Debug entry.  */
212             _tx_linux_debug_entry_insert("PROTECT-obtained-nested", __FILE__, __LINE__);
213 
214             /* Get out of the retry loop.  */
215             break;
216         }
217         /* Determine if the protection is available.  */
218         else if (_tx_thread_smp_protection.tx_thread_smp_protect_core == 0xFFFFFFFF)
219         {
220 
221             /* At this point we have the protection.  Setup the protection structure.   */
222             _tx_thread_smp_protection.tx_thread_smp_protect_in_force =         TX_TRUE;
223             _tx_thread_smp_protection.tx_thread_smp_protect_thread =           current_thread;
224             _tx_thread_smp_protection.tx_thread_smp_protect_core =             core;
225             _tx_thread_smp_protection.tx_thread_smp_protect_count =            1;
226             _tx_thread_smp_protection.tx_thread_smp_protect_linux_thread_id =  current_thread_id;
227 
228             /* Set the global interrupt disable value.  */
229             _tx_linux_global_int_disabled_flag =  TX_TRUE;
230 
231             /* Debug entry.  */
232             _tx_linux_debug_entry_insert("PROTECT-obtained", __FILE__, __LINE__);
233 
234             /* Get out of the retry loop.  */
235             break;
236         }
237         else
238         {
239 
240             /* Protection is owned by another core.  */
241 
242             /* Release the protection and start over.  */
243             _tx_linux_mutex_release(&_tx_linux_mutex);
244         }
245     } while (1);
246 
247     /* Set the global interrupt disable value.  */
248     _tx_linux_global_int_disabled_flag =  TX_TRUE;
249 
250     /* Return the interrupt posture.  */
251     return(interrupt_posture);
252 }
253 
254 
255