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 
25 /* Include necessary system files.  */
26 
27 #include "tx_api.h"
28 #include "tx_thread.h"
29 
30 
31 /**************************************************************************/
32 /*                                                                        */
33 /*  FUNCTION                                               RELEASE        */
34 /*                                                                        */
35 /*    _tx_thread_stack_analyze                            PORTABLE C      */
36 /*                                                           6.1          */
37 /*  AUTHOR                                                                */
38 /*                                                                        */
39 /*    William E. Lamie, Microsoft Corporation                             */
40 /*                                                                        */
41 /*  DESCRIPTION                                                           */
42 /*                                                                        */
43 /*    This function analyzes the stack to calculate the highest stack     */
44 /*    pointer in the thread's stack. This can then be used to derive the  */
45 /*    minimum amount of stack left for any given thread.                  */
46 /*                                                                        */
47 /*  INPUT                                                                 */
48 /*                                                                        */
49 /*    thread_ptr                            Thread control block pointer  */
50 /*                                                                        */
51 /*  OUTPUT                                                                */
52 /*                                                                        */
53 /*    None                                                                */
54 /*                                                                        */
55 /*  CALLS                                                                 */
56 /*                                                                        */
57 /*    None                                                                */
58 /*                                                                        */
59 /*  CALLED BY                                                             */
60 /*                                                                        */
61 /*    ThreadX internal code                                               */
62 /*                                                                        */
63 /*  RELEASE HISTORY                                                       */
64 /*                                                                        */
65 /*    DATE              NAME                      DESCRIPTION             */
66 /*                                                                        */
67 /*  05-19-2020     William E. Lamie         Initial Version 6.0           */
68 /*  09-30-2020     Yuxin Zhou               Modified comment(s),          */
69 /*                                            resulting in version 6.1    */
70 /*                                                                        */
71 /**************************************************************************/
_tx_thread_stack_analyze(TX_THREAD * thread_ptr)72 VOID  _tx_thread_stack_analyze(TX_THREAD *thread_ptr)
73 {
74 
75 TX_INTERRUPT_SAVE_AREA
76 
77 ULONG       *stack_ptr;
78 ULONG       *stack_lowest;
79 ULONG       *stack_highest;
80 ULONG       size;
81 
82 
83     /* Disable interrupts.  */
84     TX_DISABLE
85 
86     /* Determine if the thread pointer is NULL.  */
87     if (thread_ptr != TX_NULL)
88     {
89 
90         /* Determine if the thread ID is invalid.  */
91         if (thread_ptr -> tx_thread_id == TX_THREAD_ID)
92         {
93 
94             /* Pickup the current stack variables.  */
95             stack_lowest =   TX_VOID_TO_ULONG_POINTER_CONVERT(thread_ptr -> tx_thread_stack_start);
96 
97             /* Determine if the pointer is null.  */
98             if (stack_lowest != TX_NULL)
99             {
100 
101                 /* Pickup the highest stack pointer.  */
102                 stack_highest =  TX_VOID_TO_ULONG_POINTER_CONVERT(thread_ptr -> tx_thread_stack_highest_ptr);
103 
104                 /* Determine if the pointer is null.  */
105                 if (stack_highest != TX_NULL)
106                 {
107 
108                     /* Restore interrupts.  */
109                     TX_RESTORE
110 
111                     /* We need to binary search the remaining stack for missing 0xEFEFEFEF 32-bit data pattern.
112                        This is a best effort algorithm to find the highest stack usage. */
113                     do
114                     {
115 
116                         /* Calculate the size again. */
117                         size =  (ULONG) (TX_ULONG_POINTER_DIF(stack_highest, stack_lowest))/((ULONG) 2);
118                         stack_ptr =  TX_ULONG_POINTER_ADD(stack_lowest, size);
119 
120                         /* Determine if the pattern is still there.  */
121                         if (*stack_ptr != TX_STACK_FILL)
122                         {
123 
124                             /* Update the stack highest, since we need to look in the upper half now.  */
125                             stack_highest =  stack_ptr;
126                         }
127                         else
128                         {
129 
130                             /* Update the stack lowest, since we need to look in the lower half now.  */
131                             stack_lowest =  stack_ptr;
132                         }
133 
134                     } while(size > ((ULONG) 1));
135 
136                     /* Position to first used word - at this point we are within a few words.  */
137                     while (*stack_ptr == TX_STACK_FILL)
138                     {
139 
140                         /* Position to next word in stack.  */
141                         stack_ptr =  TX_ULONG_POINTER_ADD(stack_ptr, 1);
142                     }
143 
144                     /* Optional processing extension.  */
145                     TX_THREAD_STACK_ANALYZE_EXTENSION
146 
147                     /* Disable interrupts.  */
148                     TX_DISABLE
149 
150                     /* Check to see if the thread is still created.  */
151                     if (thread_ptr -> tx_thread_id == TX_THREAD_ID)
152                     {
153 
154                         /* Yes, thread is still created.  */
155 
156                         /* Now check the new highest stack pointer is past the stack start.  */
157                         if (stack_ptr > (TX_VOID_TO_ULONG_POINTER_CONVERT(thread_ptr -> tx_thread_stack_start)))
158                         {
159 
160                             /* Yes, now check that the new highest stack pointer is less than the previous highest stack pointer.  */
161                             if (stack_ptr < (TX_VOID_TO_ULONG_POINTER_CONVERT(thread_ptr -> tx_thread_stack_highest_ptr)))
162                             {
163 
164                                 /* Yes, is the current highest stack pointer pointing at used memory?  */
165                                 if (*stack_ptr != TX_STACK_FILL)
166                                 {
167 
168                                     /* Yes, setup the highest stack usage.  */
169                                     thread_ptr -> tx_thread_stack_highest_ptr =  stack_ptr;
170                                 }
171                             }
172                         }
173                     }
174                 }
175             }
176         }
177     }
178 
179     /* Restore interrupts.  */
180     TX_RESTORE
181 }
182 
183