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 #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_trace.h"
31 #include "tx_initialize.h"
32 #include "tx_thread.h"
33 
34 
35 /**************************************************************************/
36 /*                                                                        */
37 /*  FUNCTION                                               RELEASE        */
38 /*                                                                        */
39 /*    _tx_thread_preemption_change                       PORTABLE SMP     */
40 /*                                                           6.1          */
41 /*  AUTHOR                                                                */
42 /*                                                                        */
43 /*    William E. Lamie, Microsoft Corporation                             */
44 /*                                                                        */
45 /*  DESCRIPTION                                                           */
46 /*                                                                        */
47 /*    This function processes preemption-threshold change requests.  The  */
48 /*    previous preemption is returned to the caller.  If the new request  */
49 /*    allows a higher priority thread to execute, preemption takes place  */
50 /*    inside of this function.                                            */
51 /*                                                                        */
52 /*  INPUT                                                                 */
53 /*                                                                        */
54 /*    thread_ptr                            Pointer to thread             */
55 /*    new_threshold                         New preemption-threshold      */
56 /*    old_threshold                         Old preemption-threshold      */
57 /*                                                                        */
58 /*  OUTPUT                                                                */
59 /*                                                                        */
60 /*    status                                Service return status         */
61 /*                                                                        */
62 /*  CALLS                                                                 */
63 /*                                                                        */
64 /*    _tx_thread_smp_rebalance_execute_list Rebalance the execution list  */
65 /*    _tx_thread_system_preempt_check       Check for preemption          */
66 /*                                                                        */
67 /*  CALLED BY                                                             */
68 /*                                                                        */
69 /*    Application Code                                                    */
70 /*                                                                        */
71 /*  RELEASE HISTORY                                                       */
72 /*                                                                        */
73 /*    DATE              NAME                      DESCRIPTION             */
74 /*                                                                        */
75 /*  09-30-2020     William E. Lamie         Initial Version 6.1           */
76 /*                                                                        */
77 /**************************************************************************/
_tx_thread_preemption_change(TX_THREAD * thread_ptr,UINT new_threshold,UINT * old_threshold)78 UINT  _tx_thread_preemption_change(TX_THREAD *thread_ptr, UINT new_threshold, UINT *old_threshold)
79 {
80 
81 TX_INTERRUPT_SAVE_AREA
82 
83 UINT        core_index;
84 
85 #ifndef TX_DISABLE_PREEMPTION_THRESHOLD
86 ULONG       priority_bit;
87 UINT        base_priority;
88 UINT        priority_bit_set;
89 ULONG       priority_map;
90 UINT        next_preempted;
91 TX_THREAD   *preempted_thread;
92 #if TX_MAX_PRIORITIES > 32
93 UINT        map_index;
94 #endif
95 #endif
96 UINT        status;
97 
98 
99 #ifdef TX_DISABLE_PREEMPTION_THRESHOLD
100 
101     /* Only allow 0 (disable all preemption) and returning preemption-threshold to the
102        current thread priority if preemption-threshold is disabled. All other threshold
103        values are converted to 0.  */
104     if (new_threshold < thread_ptr -> tx_thread_user_priority)
105     {
106 
107         /* Is the new threshold zero?  */
108         if (new_threshold != ((UINT) 0))
109         {
110 
111             /* Convert the new threshold to disable all preemption, since preemption-threshold is
112                not supported.  */
113             new_threshold =  ((UINT) 0);
114         }
115     }
116 #endif
117 
118     /* Default status to success.  */
119     status =  TX_SUCCESS;
120 
121     /* Lockout interrupts while the thread is being resumed.  */
122     TX_DISABLE
123 
124     /* If trace is enabled, insert this event into the trace buffer.  */
125     TX_TRACE_IN_LINE_INSERT(TX_TRACE_THREAD_PREEMPTION_CHANGE, thread_ptr, new_threshold, thread_ptr -> tx_thread_preempt_threshold, thread_ptr -> tx_thread_state, TX_TRACE_THREAD_EVENTS)
126 
127     /* Log this kernel call.  */
128     TX_EL_THREAD_PREEMPTION_CHANGE_INSERT
129 
130     /* Determine if the new threshold is greater than the current user priority.  */
131     if (new_threshold > thread_ptr -> tx_thread_user_priority)
132     {
133 
134         /* Restore interrupts.  */
135         TX_RESTORE
136 
137         /* Return error.  */
138         status =  TX_THRESH_ERROR;
139     }
140     else
141     {
142 
143         /* Return the user's preemption-threshold.   */
144         *old_threshold =  thread_ptr -> tx_thread_user_preempt_threshold;
145 
146         /* Setup the new threshold.  */
147         thread_ptr -> tx_thread_user_preempt_threshold =  new_threshold;
148 
149         /* Determine if the new threshold represents a higher priority than the priority inheritance threshold.  */
150         if (new_threshold < thread_ptr -> tx_thread_inherit_priority)
151         {
152 
153             /* Update the actual preemption-threshold with the new threshold.  */
154             thread_ptr -> tx_thread_preempt_threshold =  new_threshold;
155         }
156         else
157         {
158 
159             /* Update the actual preemption-threshold with the priority inheritance.  */
160             thread_ptr -> tx_thread_preempt_threshold =  thread_ptr -> tx_thread_inherit_priority;
161         }
162 
163         /* Determine if the thread is ready and scheduled.  */
164         if (thread_ptr -> tx_thread_state == TX_READY)
165         {
166 
167 #ifndef TX_DISABLE_PREEMPTION_THRESHOLD
168 
169             /* Determine if the new threshold is the same as the priority.  */
170             if (thread_ptr -> tx_thread_user_priority == new_threshold)
171             {
172 
173                 /* Yes, preemption-threshold is being disabled.  */
174 
175                 /* Determine if this thread was scheduled with preemption-threshold in force.  */
176                 if (_tx_thread_preemption_threshold_list[thread_ptr -> tx_thread_priority] == thread_ptr)
177                 {
178 
179                     /* Clear the entry in the preempted list.  */
180                     _tx_thread_preemption_threshold_list[thread_ptr -> tx_thread_priority] =  TX_NULL;
181 
182 #if TX_MAX_PRIORITIES > 32
183 
184                     /* Calculate the index into the bit map array.  */
185                     map_index =  (thread_ptr -> tx_thread_priority)/((UINT) 32);
186 #endif
187 
188                     /* Yes, this thread is at the front of the list.  Make sure
189                        the preempted bit is cleared for this thread.  */
190                     TX_MOD32_BIT_SET(thread_ptr -> tx_thread_priority, priority_bit)
191                     _tx_thread_preempted_maps[MAP_INDEX] =  _tx_thread_preempted_maps[MAP_INDEX] & (~(priority_bit));
192 
193 #if TX_MAX_PRIORITIES > 32
194 
195                     /* Determine if there are any other bits set in this preempt map.  */
196                     if (_tx_thread_preempted_maps[MAP_INDEX] == ((ULONG) 0))
197                     {
198 
199                         /* No, clear the active bit to signify this preempt map has nothing set.  */
200                         TX_DIV32_BIT_SET(thread_ptr -> tx_thread_priority, priority_bit)
201                         _tx_thread_preempted_map_active =  _tx_thread_preempted_map_active & (~(priority_bit));
202                     }
203 #endif
204                 }
205             }
206 #endif
207 
208             /* Determine if this thread has global preemption disabled.  */
209             if (thread_ptr == _tx_thread_preemption__threshold_scheduled)
210             {
211 
212                 /* Clear the global preemption disable flag.  */
213                 _tx_thread_preemption__threshold_scheduled =  TX_NULL;
214 
215 #ifndef TX_DISABLE_PREEMPTION_THRESHOLD
216 
217                 /* Calculate the first thread with preemption-threshold active.  */
218 #if TX_MAX_PRIORITIES > 32
219                 if (_tx_thread_preempted_map_active != ((ULONG) 0))
220 #else
221                 if (_tx_thread_preempted_maps[0] != ((ULONG) 0))
222 #endif
223                 {
224 #if TX_MAX_PRIORITIES > 32
225 
226                     /* Calculate the index to find the next highest priority thread ready for execution.  */
227                     priority_map =    _tx_thread_preempted_map_active;
228 
229                     /* Calculate the lowest bit set in the priority map. */
230                     TX_LOWEST_SET_BIT_CALCULATE(priority_map, map_index)
231 
232                     /* Calculate the base priority as well.  */
233                     base_priority =  map_index * ((UINT) 32);
234 #else
235 
236                     /* Setup the base priority to zero.  */
237                     base_priority =   ((UINT) 0);
238 #endif
239 
240                     /* Setup temporary preempted map.  */
241                     priority_map =  _tx_thread_preempted_maps[MAP_INDEX];
242 
243                     /* Calculate the lowest bit set in the priority map. */
244                     TX_LOWEST_SET_BIT_CALCULATE(priority_map, priority_bit_set)
245 
246                     /* Move priority bit set into priority bit.  */
247                     priority_bit =  (ULONG) priority_bit_set;
248 
249                     /* Setup the highest priority preempted thread.  */
250                     next_preempted =  base_priority + priority_bit;
251 
252                     /* Pickup the previously preempted thread.  */
253                     preempted_thread =  _tx_thread_preemption_threshold_list[next_preempted];
254 
255                     /* Pickup the preempted thread.  */
256                     _tx_thread_preemption__threshold_scheduled =  preempted_thread;
257                 }
258 #endif
259             }
260 
261             /* See if preemption needs to take place.  */
262 
263 #ifdef TX_THREAD_SMP_DEBUG_ENABLE
264 
265             /* Debug entry.  */
266             _tx_thread_smp_debug_entry_insert(12, 0, thread_ptr);
267 #endif
268 
269             /* Pickup the index.  */
270             core_index =  TX_SMP_CORE_ID;
271 
272             /* Call the rebalance routine. This routine maps cores and ready threads.  */
273             _tx_thread_smp_rebalance_execute_list(core_index);
274 
275 #ifdef TX_THREAD_SMP_DEBUG_ENABLE
276 
277             /* Debug entry.  */
278             _tx_thread_smp_debug_entry_insert(13, 0, thread_ptr);
279 #endif
280 
281             /* Restore interrupts.  */
282             TX_RESTORE
283 
284             /* Check for preemption.  */
285             _tx_thread_system_preempt_check();
286         }
287         else
288         {
289 
290             /* Restore interrupts.  */
291             TX_RESTORE
292         }
293     }
294 
295     /* Return completion status.  */
296     return(status);
297 }
298 
299