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