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 
25 
26 /* Include necessary system files.  */
27 
28 #include "tx_api.h"
29 #include "tx_trace.h"
30 #include "tx_thread.h"
31 
32 
33 /**************************************************************************/
34 /*                                                                        */
35 /*  FUNCTION                                               RELEASE        */
36 /*                                                                        */
37 /*    _tx_thread_preemption_change                        PORTABLE C      */
38 /*                                                           6.1          */
39 /*  AUTHOR                                                                */
40 /*                                                                        */
41 /*    William E. Lamie, Microsoft Corporation                             */
42 /*                                                                        */
43 /*  DESCRIPTION                                                           */
44 /*                                                                        */
45 /*    This function processes preemption-threshold change requests.  The  */
46 /*    previous preemption is returned to the caller.  If the new request  */
47 /*    allows a higher priority thread to execute, preemption takes place  */
48 /*    inside of this function.                                            */
49 /*                                                                        */
50 /*  INPUT                                                                 */
51 /*                                                                        */
52 /*    thread_ptr                            Pointer to thread             */
53 /*    new_threshold                         New preemption threshold      */
54 /*    old_threshold                         Old preemption threshold      */
55 /*                                                                        */
56 /*  OUTPUT                                                                */
57 /*                                                                        */
58 /*    status                                Service return status         */
59 /*                                                                        */
60 /*  CALLS                                                                 */
61 /*                                                                        */
62 /*    _tx_thread_system_preempt_check       Check for preemption          */
63 /*                                                                        */
64 /*  CALLED BY                                                             */
65 /*                                                                        */
66 /*    Application Code                                                    */
67 /*                                                                        */
68 /*  RELEASE HISTORY                                                       */
69 /*                                                                        */
70 /*    DATE              NAME                      DESCRIPTION             */
71 /*                                                                        */
72 /*  05-19-2020     William E. Lamie         Initial Version 6.0           */
73 /*  09-30-2020     Yuxin Zhou               Modified comment(s),          */
74 /*                                            resulting in version 6.1    */
75 /*                                                                        */
76 /**************************************************************************/
_tx_thread_preemption_change(TX_THREAD * thread_ptr,UINT new_threshold,UINT * old_threshold)77 UINT  _tx_thread_preemption_change(TX_THREAD *thread_ptr, UINT new_threshold, UINT *old_threshold)
78 {
79 
80 TX_INTERRUPT_SAVE_AREA
81 
82 #ifndef TX_DISABLE_PREEMPTION_THRESHOLD
83 ULONG       priority_bit;
84 #if TX_MAX_PRIORITIES > 32
85 UINT        map_index;
86 #endif
87 #endif
88 UINT        status;
89 
90 
91     /* Default status to success.  */
92     status =  TX_SUCCESS;
93 
94 #ifdef TX_DISABLE_PREEMPTION_THRESHOLD
95 
96     /* Only allow 0 (disable all preemption) and returning preemption-threshold to the
97        current thread priority if preemption-threshold is disabled. All other threshold
98        values are converted to 0.  */
99     if (thread_ptr -> tx_thread_user_priority != new_threshold)
100     {
101 
102         /* Is the new threshold zero?  */
103         if (new_threshold != ((UINT) 0))
104         {
105 
106             /* Convert the new threshold to disable all preemption, since preemption-threshold is
107                not supported.  */
108             new_threshold =  ((UINT) 0);
109         }
110     }
111 #endif
112 
113     /* Lockout interrupts while the thread is being resumed.  */
114     TX_DISABLE
115 
116     /* If trace is enabled, insert this event into the trace buffer.  */
117     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)
118 
119     /* Log this kernel call.  */
120     TX_EL_THREAD_PREEMPTION_CHANGE_INSERT
121 
122     /* Determine if the new threshold is greater than the current user priority.  */
123     if (new_threshold > thread_ptr -> tx_thread_user_priority)
124     {
125 
126         /* Return error.  */
127         status =  TX_THRESH_ERROR;
128     }
129     else
130     {
131 
132 #ifndef TX_DISABLE_PREEMPTION_THRESHOLD
133 
134         /* Determine if the new threshold is the same as the priority.  */
135         if (thread_ptr -> tx_thread_user_priority == new_threshold)
136         {
137 
138             /* Determine if this thread is at the head of the list.  */
139             if (_tx_thread_priority_list[thread_ptr -> tx_thread_priority] == thread_ptr)
140             {
141 
142 #if TX_MAX_PRIORITIES > 32
143 
144                 /* Calculate the index into the bit map array.  */
145                 map_index =  (thread_ptr -> tx_thread_priority)/((UINT) 32);
146 #endif
147 
148                 /* Yes, this thread is at the front of the list.  Make sure
149                    the preempted bit is cleared for this thread.  */
150                 TX_MOD32_BIT_SET(thread_ptr -> tx_thread_priority, priority_bit)
151                 _tx_thread_preempted_maps[MAP_INDEX] =  _tx_thread_preempted_maps[MAP_INDEX] & (~(priority_bit));
152 
153 #if TX_MAX_PRIORITIES > 32
154 
155                 /* Determine if there are any other bits set in this preempt map.  */
156                 if (_tx_thread_preempted_maps[MAP_INDEX] == ((ULONG) 0))
157                 {
158 
159                     /* No, clear the active bit to signify this preempt map has nothing set.  */
160                     TX_DIV32_BIT_SET(thread_ptr -> tx_thread_priority, priority_bit)
161                     _tx_thread_preempted_map_active =  _tx_thread_preempted_map_active & (~(priority_bit));
162                 }
163 #endif
164             }
165         }
166 #endif
167 
168         /* Return the user's preemption-threshold.   */
169         *old_threshold =  thread_ptr -> tx_thread_user_preempt_threshold;
170 
171         /* Setup the new threshold.  */
172         thread_ptr -> tx_thread_user_preempt_threshold =  new_threshold;
173 
174         /* Determine if the new threshold represents a higher priority than the priority inheritance threshold.  */
175         if (new_threshold < thread_ptr -> tx_thread_inherit_priority)
176         {
177 
178             /* Update the actual preemption-threshold with the new threshold.  */
179             thread_ptr -> tx_thread_preempt_threshold =  new_threshold;
180         }
181         else
182         {
183 
184             /* Update the actual preemption-threshold with the priority inheritance.  */
185             thread_ptr -> tx_thread_preempt_threshold =  thread_ptr -> tx_thread_inherit_priority;
186         }
187 
188         /* Is the thread priority less than the current highest priority?  If not, no preemption is required.  */
189         if (_tx_thread_highest_priority < thread_ptr -> tx_thread_priority)
190         {
191 
192             /* Is the new thread preemption-threshold less than the current highest priority?  If not, no preemption is required.  */
193             if (_tx_thread_highest_priority < new_threshold)
194             {
195 
196                 /* If the current execute pointer is the same at this thread, preemption needs to take place.  */
197                 if (_tx_thread_execute_ptr == thread_ptr)
198                 {
199 
200                     /* Preemption needs to take place.  */
201 
202 #ifndef TX_DISABLE_PREEMPTION_THRESHOLD
203 
204                     /* Determine if this thread has preemption threshold set.  */
205                     if (thread_ptr -> tx_thread_preempt_threshold != thread_ptr -> tx_thread_priority)
206                     {
207 
208 #if TX_MAX_PRIORITIES > 32
209 
210                         /* Calculate the index into the bit map array.  */
211                         map_index =  (thread_ptr -> tx_thread_priority)/((UINT) 32);
212 
213                         /* Set the active bit to remember that the preempt map has something set.  */
214                         TX_DIV32_BIT_SET(thread_ptr -> tx_thread_priority, priority_bit)
215                         _tx_thread_preempted_map_active =  _tx_thread_preempted_map_active | priority_bit;
216 #endif
217 
218                         /* Remember that this thread was preempted by a thread above the thread's threshold.  */
219                         TX_MOD32_BIT_SET(thread_ptr -> tx_thread_priority, priority_bit)
220                         _tx_thread_preempted_maps[MAP_INDEX] =  _tx_thread_preempted_maps[MAP_INDEX] | priority_bit;
221                     }
222 #endif
223 
224 #ifdef TX_THREAD_ENABLE_PERFORMANCE_INFO
225 
226                     /* Determine if the caller is an interrupt or from a thread.  */
227                     if (TX_THREAD_GET_SYSTEM_STATE() == ((ULONG) 0))
228                     {
229 
230                         /* Caller is a thread, so this is a solicited preemption.  */
231                         _tx_thread_performance_solicited_preemption_count++;
232 
233                         /* Increment the thread's solicited preemption counter.  */
234                         thread_ptr -> tx_thread_performance_solicited_preemption_count++;
235                     }
236 
237                     /* Remember the thread that preempted this thread.  */
238                     thread_ptr -> tx_thread_performance_last_preempting_thread =  _tx_thread_priority_list[_tx_thread_highest_priority];
239 
240                     /* Is the execute pointer different?  */
241                     if (_tx_thread_performance_execute_log[_tx_thread_performance__execute_log_index] != _tx_thread_execute_ptr)
242                     {
243 
244                         /* Move to next entry.  */
245                         _tx_thread_performance__execute_log_index++;
246 
247                         /* Check for wrap condition.  */
248                         if (_tx_thread_performance__execute_log_index >= TX_THREAD_EXECUTE_LOG_SIZE)
249                         {
250 
251                             /* Set the index to the beginning.  */
252                             _tx_thread_performance__execute_log_index =  ((UINT) 0);
253                         }
254 
255                         /* Log the new execute pointer.  */
256                         _tx_thread_performance_execute_log[_tx_thread_performance__execute_log_index] =  _tx_thread_execute_ptr;
257                     }
258 #endif
259 
260                     /* Setup the highest priority thread to execute.  */
261                     _tx_thread_execute_ptr =  _tx_thread_priority_list[_tx_thread_highest_priority];
262 
263                     /* Restore interrupts.  */
264                     TX_RESTORE
265 
266                     /* Check for preemption.  */
267                     _tx_thread_system_preempt_check();
268 
269                     /* Disable interrupts.  */
270                     TX_DISABLE
271                 }
272             }
273         }
274     }
275 
276     /* Restore interrupts.  */
277     TX_RESTORE
278 
279     /* Return completion status.  */
280     return(status);
281 }
282 
283