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 - High Level SMP Support */
18 /** */
19 /**************************************************************************/
20 /**************************************************************************/
21
22 #define TX_SOURCE_CODE
23 #define TX_THREAD_SMP_SOURCE_CODE
24
25
26 /* Include necessary system files. */
27
28 #include "tx_api.h"
29 #include "tx_initialize.h"
30 #include "tx_timer.h"
31 #include "tx_thread.h"
32
33
34 /**************************************************************************/
35 /* */
36 /* FUNCTION RELEASE */
37 /* */
38 /* _tx_thread_smp_core_exclude PORTABLE SMP */
39 /* 6.1 */
40 /* AUTHOR */
41 /* */
42 /* William E. Lamie, Microsoft Corporation */
43 /* */
44 /* DESCRIPTION */
45 /* */
46 /* This function allows the application to exclude one or more cores */
47 /* from executing the specified thread. */
48 /* */
49 /* INPUT */
50 /* */
51 /* thread_ptr Pointer to the thread */
52 /* exclusion_map Bit map of exclusion list, */
53 /* where bit 0 set means that */
54 /* this thread cannot run on */
55 /* core0, etc. */
56 /* */
57 /* OUTPUT */
58 /* */
59 /* Status */
60 /* */
61 /* CALLS */
62 /* */
63 /* _tx_thread_smp_rebalance_execute_list Build execution list */
64 /* _tx_thread_system_return System return */
65 /* */
66 /* CALLED BY */
67 /* */
68 /* Application Code */
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_smp_core_exclude(TX_THREAD * thread_ptr,ULONG exclusion_map)77 UINT _tx_thread_smp_core_exclude(TX_THREAD *thread_ptr, ULONG exclusion_map)
78 {
79
80 TX_INTERRUPT_SAVE_AREA
81
82 UINT core_index;
83 UINT new_mapped_core;
84 ULONG mapped_core;
85 ULONG available_cores;
86 UINT restore_needed;
87 UINT status;
88
89
90 /* Default status to success. */
91 status = TX_SUCCESS;
92
93 /* First, make sure the thread pointer is valid. */
94 if (thread_ptr == TX_NULL)
95 {
96
97 /* Return pointer error. */
98 status = TX_THREAD_ERROR;
99 }
100
101 /* Check for valid ID. */
102 else if (thread_ptr -> tx_thread_id != TX_THREAD_ID)
103 {
104
105 /* Return pointer error. */
106 status = TX_THREAD_ERROR;
107 }
108 else
109 {
110
111 /* Disable interrupts. */
112 TX_DISABLE
113
114 /* Set the restore needed flag. */
115 restore_needed = TX_TRUE;
116
117 #ifdef TX_THREAD_SMP_DEBUG_ENABLE
118
119 /* Debug entry. */
120 _tx_thread_smp_debug_entry_insert(2, 0, thread_ptr);
121 #endif
122
123 /* Build the bitmap for the last mapped core. */
124 mapped_core = (((ULONG) 1) << thread_ptr -> tx_thread_smp_core_mapped);
125
126 /* Calculate the available cores map. */
127 available_cores = (~exclusion_map) & ((ULONG) TX_THREAD_SMP_CORE_MASK);
128
129 /* Save the excluded and available cores. */
130 thread_ptr -> tx_thread_smp_cores_excluded = exclusion_map;
131 thread_ptr -> tx_thread_smp_cores_allowed = available_cores;
132
133 /* Determine if this is within the now available cores. */
134 if ((mapped_core & available_cores) == ((ULONG) 0))
135 {
136
137 /* Determine if there are any cores available. */
138 if (available_cores == ((ULONG) 0))
139 {
140
141 /* No cores are available, simply set the last running core to 0. */
142 thread_ptr -> tx_thread_smp_core_mapped = ((UINT) 0);
143 }
144 else
145 {
146
147 /* No, we need set the last mapped core to a valid core. */
148 TX_LOWEST_SET_BIT_CALCULATE(available_cores, new_mapped_core)
149
150 /* Now setup the last core mapped. */
151 thread_ptr -> tx_thread_smp_core_mapped = new_mapped_core;
152 }
153 }
154
155 #ifdef TX_THREAD_SMP_DEBUG_ENABLE
156
157 /* Determine if the thread is in a ready state. */
158 if (thread_ptr -> tx_thread_state != TX_READY)
159 {
160
161
162 /* Debug entry. */
163 _tx_thread_smp_debug_entry_insert(3, 0, thread_ptr);
164
165 }
166 #endif
167
168 /* Determine if the thread is ready. */
169 if (thread_ptr -> tx_thread_state == TX_READY)
170 {
171
172 /* Pickup the index. */
173 core_index = TX_SMP_CORE_ID;
174
175 /* Call the rebalance routine. This routine maps cores and ready threads. */
176 _tx_thread_smp_rebalance_execute_list(core_index);
177
178 #ifdef TX_THREAD_SMP_DEBUG_ENABLE
179
180 /* Debug entry. */
181 _tx_thread_smp_debug_entry_insert(3, 0, thread_ptr);
182 #endif
183
184 /* Determine if this thread needs to return to the system. */
185
186 /* Is there a difference between the current and execute thread pointers? */
187 if (_tx_thread_execute_ptr[core_index] != _tx_thread_current_ptr[core_index])
188 {
189
190 /* Yes, check to see if we are at the thread level. */
191 if (_tx_thread_system_state[core_index] == ((ULONG) 0))
192 {
193
194 /* At the thread level, check for the preempt disable flag being set. */
195 if (_tx_thread_preempt_disable == ((UINT) 0))
196 {
197
198 #ifndef TX_NOT_INTERRUPTABLE
199
200 /* Increment the preempt disable flag in order to keep the protection. */
201 _tx_thread_preempt_disable++;
202
203 /* Restore interrupts. */
204 TX_RESTORE
205 #endif
206
207 /* Transfer control to the system so the scheduler can execute
208 the next thread. */
209 _tx_thread_system_return();
210
211 #ifdef TX_NOT_INTERRUPTABLE
212
213 /* Restore interrupts. */
214 TX_RESTORE
215 #endif
216
217 /* Clear the restore needed flag, since the interrupt poster/protection has been done. */
218 restore_needed = TX_FALSE;
219 }
220 }
221 }
222 }
223
224 /* Determine if the protection still needs to be restored. */
225 if (restore_needed == TX_TRUE)
226 {
227
228 /* Restore interrupts. */
229 TX_RESTORE
230 }
231 }
232
233 /* Return status. */
234 return(status);
235 }
236
237