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 #define TX_SOURCE_CODE
23 
24 #ifndef TX_NO_TIMER
25 
26 /* Include necessary system files.  */
27 
28 #include "tx_api.h"
29 #include "tx_timer.h"
30 #include "tx_thread.h"
31 #include "tx_trace.h"
32 
33 
34 /**************************************************************************/
35 /*                                                                        */
36 /*  FUNCTION                                               RELEASE        */
37 /*                                                                        */
38 /*    _tx_thread_time_slice                               PORTABLE C      */
39 /*                                                           6.1          */
40 /*  AUTHOR                                                                */
41 /*                                                                        */
42 /*    William E. Lamie, Microsoft Corporation                             */
43 /*                                                                        */
44 /*  DESCRIPTION                                                           */
45 /*                                                                        */
46 /*    This function moves the currently executing thread to the end of    */
47 /*    the threads ready at the same priority level as a result of a       */
48 /*    time-slice interrupt.  If no other thread of the same priority is   */
49 /*    ready, this function simply returns.                                */
50 /*                                                                        */
51 /*  INPUT                                                                 */
52 /*                                                                        */
53 /*    None                                                                */
54 /*                                                                        */
55 /*  OUTPUT                                                                */
56 /*                                                                        */
57 /*    None                                                                */
58 /*                                                                        */
59 /*  CALLS                                                                 */
60 /*                                                                        */
61 /*    None                                                                */
62 /*                                                                        */
63 /*  CALLED BY                                                             */
64 /*                                                                        */
65 /*    _tx_timer_interrupt                   Timer interrupt handling      */
66 /*                                                                        */
67 /*  RELEASE HISTORY                                                       */
68 /*                                                                        */
69 /*    DATE              NAME                      DESCRIPTION             */
70 /*                                                                        */
71 /*  05-19-2020     William E. Lamie         Initial Version 6.0           */
72 /*  09-30-2020     Scott Larson             Modified comment(s), and      */
73 /*                                            opt out of function when    */
74 /*                                            TX_NO_TIMER is defined,     */
75 /*                                            resulting in version 6.1    */
76 /*                                                                        */
77 /**************************************************************************/
_tx_thread_time_slice(VOID)78 VOID  _tx_thread_time_slice(VOID)
79 {
80 
81 TX_INTERRUPT_SAVE_AREA
82 
83 TX_THREAD       *thread_ptr;
84 #ifdef TX_ENABLE_STACK_CHECKING
85 TX_THREAD       *next_thread_ptr;
86 #endif
87 #ifdef TX_ENABLE_EVENT_TRACE
88 ULONG           system_state;
89 UINT            preempt_disable;
90 #endif
91 
92     /* Pickup thread pointer.  */
93     TX_THREAD_GET_CURRENT(thread_ptr)
94 
95 #ifdef TX_ENABLE_STACK_CHECKING
96 
97     /* Check this thread's stack.  */
98     TX_THREAD_STACK_CHECK(thread_ptr)
99 
100     /* Set the next thread pointer to NULL.  */
101     next_thread_ptr =  TX_NULL;
102 #endif
103 
104     /* Lockout interrupts while the time-slice is evaluated.  */
105     TX_DISABLE
106 
107     /* Clear the expired time-slice flag.  */
108     _tx_timer_expired_time_slice =  TX_FALSE;
109 
110     /* Make sure the thread pointer is valid.  */
111     if (thread_ptr != TX_NULL)
112     {
113 
114         /* Make sure the thread is still active, i.e. not suspended.  */
115         if (thread_ptr -> tx_thread_state == TX_READY)
116         {
117 
118             /* Setup a fresh time-slice for the thread.  */
119             thread_ptr -> tx_thread_time_slice =  thread_ptr -> tx_thread_new_time_slice;
120 
121             /* Reset the actual time-slice variable.  */
122             _tx_timer_time_slice =  thread_ptr -> tx_thread_time_slice;
123 
124             /* Determine if there is another thread at the same priority and preemption-threshold
125                is not set.  Preemption-threshold overrides time-slicing.  */
126             if (thread_ptr -> tx_thread_ready_next != thread_ptr)
127             {
128 
129                 /* Check to see if preemption-threshold is not being used.  */
130                 if (thread_ptr -> tx_thread_priority == thread_ptr -> tx_thread_preempt_threshold)
131                 {
132 
133                     /* Preemption-threshold is not being used by this thread.  */
134 
135                     /* There is another thread at this priority, make it the highest at
136                        this priority level.  */
137                     _tx_thread_priority_list[thread_ptr -> tx_thread_priority] =  thread_ptr -> tx_thread_ready_next;
138 
139                     /* Designate the highest priority thread as the one to execute.  Don't use this
140                        thread's priority as an index just in case a higher priority thread is now
141                        ready!  */
142                     _tx_thread_execute_ptr =  _tx_thread_priority_list[_tx_thread_highest_priority];
143 
144 #ifdef TX_THREAD_ENABLE_PERFORMANCE_INFO
145 
146                     /* Increment the thread's time-slice counter.  */
147                     thread_ptr -> tx_thread_performance_time_slice_count++;
148 
149                     /* Increment the total number of thread time-slice operations.  */
150                     _tx_thread_performance_time_slice_count++;
151 #endif
152 
153 
154 #ifdef TX_ENABLE_STACK_CHECKING
155 
156                     /* Pickup the next execute pointer.  */
157                     next_thread_ptr =  _tx_thread_execute_ptr;
158 #endif
159                 }
160             }
161         }
162     }
163 
164 #ifdef TX_ENABLE_EVENT_TRACE
165 
166     /* Pickup the volatile information.  */
167     system_state =  TX_THREAD_GET_SYSTEM_STATE();
168     preempt_disable =  _tx_thread_preempt_disable;
169 
170     /* Insert this event into the trace buffer.  */
171     TX_TRACE_IN_LINE_INSERT(TX_TRACE_TIME_SLICE, _tx_thread_execute_ptr, system_state, preempt_disable, TX_POINTER_TO_ULONG_CONVERT(&thread_ptr), TX_TRACE_INTERNAL_EVENTS)
172 #endif
173 
174     /* Restore previous interrupt posture.  */
175     TX_RESTORE
176 
177 #ifdef TX_ENABLE_STACK_CHECKING
178 
179     /* Determine if there is a next thread pointer to perform stack checking on.  */
180     if (next_thread_ptr != TX_NULL)
181     {
182 
183         /* Yes, check this thread's stack.  */
184         TX_THREAD_STACK_CHECK(next_thread_ptr)
185     }
186 #endif
187 }
188 
189 #endif
190