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_initialize.h"
30 #include "tx_thread.h"
31 #include "tx_timer.h"
32 
33 
34 /**************************************************************************/
35 /*                                                                        */
36 /*  FUNCTION                                               RELEASE        */
37 /*                                                                        */
38 /*    _txe_thread_create                                  PORTABLE C      */
39 /*                                                           6.1          */
40 /*  AUTHOR                                                                */
41 /*                                                                        */
42 /*    William E. Lamie, Microsoft Corporation                             */
43 /*                                                                        */
44 /*  DESCRIPTION                                                           */
45 /*                                                                        */
46 /*    This function checks for errors in the thread create function call. */
47 /*                                                                        */
48 /*  INPUT                                                                 */
49 /*                                                                        */
50 /*    thread_ptr                            Thread control block pointer  */
51 /*    name                                  Pointer to thread name string */
52 /*    entry_function                        Entry function of the thread  */
53 /*    entry_input                           32-bit input value to thread  */
54 /*    stack_start                           Pointer to start of stack     */
55 /*    stack_size                            Stack size in bytes           */
56 /*    priority                              Priority of thread (0-31)     */
57 /*    preempt_threshold                     Preemption threshold          */
58 /*    time_slice                            Thread time-slice value       */
59 /*    auto_start                            Automatic start selection     */
60 /*    thread_control_block_size             Size of thread control block  */
61 /*                                                                        */
62 /*  OUTPUT                                                                */
63 /*                                                                        */
64 /*    TX_THREAD_ERROR                       Invalid thread pointer        */
65 /*    TX_PTR_ERROR                          Invalid entry point or stack  */
66 /*                                            address                     */
67 /*    TX_SIZE_ERROR                         Invalid stack size -too small */
68 /*    TX_PRIORITY_ERROR                     Invalid thread priority       */
69 /*    TX_THRESH_ERROR                       Invalid preemption threshold  */
70 /*    status                                Actual completion status      */
71 /*                                                                        */
72 /*  CALLS                                                                 */
73 /*                                                                        */
74 /*    _tx_thread_create                     Actual thread create function */
75 /*    _tx_thread_system_preempt_check       Check for preemption          */
76 /*                                                                        */
77 /*  CALLED BY                                                             */
78 /*                                                                        */
79 /*    Application Code                                                    */
80 /*                                                                        */
81 /*  RELEASE HISTORY                                                       */
82 /*                                                                        */
83 /*    DATE              NAME                      DESCRIPTION             */
84 /*                                                                        */
85 /*  05-19-2020     William E. Lamie         Initial Version 6.0           */
86 /*  09-30-2020     Yuxin Zhou               Modified comment(s),          */
87 /*                                            resulting in version 6.1    */
88 /*                                                                        */
89 /**************************************************************************/
_txe_thread_create(TX_THREAD * thread_ptr,CHAR * name_ptr,VOID (* entry_function)(ULONG id),ULONG entry_input,VOID * stack_start,ULONG stack_size,UINT priority,UINT preempt_threshold,ULONG time_slice,UINT auto_start,UINT thread_control_block_size)90 UINT    _txe_thread_create(TX_THREAD *thread_ptr, CHAR *name_ptr,
91                 VOID (*entry_function)(ULONG id), ULONG entry_input,
92                 VOID *stack_start, ULONG stack_size,
93                 UINT priority, UINT preempt_threshold,
94                 ULONG time_slice, UINT auto_start, UINT thread_control_block_size)
95 {
96 
97 TX_INTERRUPT_SAVE_AREA
98 
99 UINT            status;
100 UINT            break_flag;
101 ULONG           i;
102 TX_THREAD       *next_thread;
103 VOID            *stack_end;
104 UCHAR           *work_ptr;
105 #ifndef TX_TIMER_PROCESS_IN_ISR
106 TX_THREAD       *current_thread;
107 #endif
108 
109 
110     /* Default status to success.  */
111     status =  TX_SUCCESS;
112 
113     /* Check for an invalid thread pointer.  */
114     if (thread_ptr == TX_NULL)
115     {
116 
117         /* Thread pointer is invalid, return appropriate error code.  */
118         status =  TX_THREAD_ERROR;
119     }
120 
121     /* Now check for invalid thread control block size.  */
122     else if (thread_control_block_size != (sizeof(TX_THREAD)))
123     {
124 
125         /* Thread pointer is invalid, return appropriate error code.  */
126         status =  TX_THREAD_ERROR;
127     }
128     else
129     {
130 
131         /* Disable interrupts.  */
132         TX_DISABLE
133 
134         /* Increment the preempt disable flag.  */
135         _tx_thread_preempt_disable++;
136 
137         /* Restore interrupts.  */
138         TX_RESTORE
139 
140         /* Next see if it is already in the created list.  */
141         break_flag =   TX_FALSE;
142         next_thread =  _tx_thread_created_ptr;
143         work_ptr =     TX_VOID_TO_UCHAR_POINTER_CONVERT(stack_start);
144         work_ptr =     TX_UCHAR_POINTER_ADD(work_ptr, (stack_size - ((ULONG) 1)));
145         stack_end =    TX_UCHAR_TO_VOID_POINTER_CONVERT(work_ptr);
146         for (i = ((ULONG) 0); i < _tx_thread_created_count; i++)
147         {
148 
149             /* Determine if this thread matches the thread in the list.  */
150             if (thread_ptr == next_thread)
151             {
152 
153                 /* Set the break flag.  */
154                 break_flag =  TX_TRUE;
155             }
156 
157             /* Determine if we need to break the loop.  */
158             if (break_flag == TX_TRUE)
159             {
160 
161                 /* Yes, break out of the loop.  */
162                 break;
163             }
164 
165             /* Check the stack pointer to see if it overlaps with this thread's stack.  */
166             if (stack_start >= next_thread -> tx_thread_stack_start)
167             {
168 
169                 if (stack_start < next_thread -> tx_thread_stack_end)
170                 {
171 
172                     /* This stack overlaps with an existing thread, clear the stack pointer to
173                        force a stack error below.  */
174                     stack_start =  TX_NULL;
175 
176                     /* Set the break flag.  */
177                     break_flag =  TX_TRUE;
178                 }
179             }
180 
181             /* Check the end of the stack to see if it is inside this thread's stack area as well.  */
182             if (stack_end >= next_thread -> tx_thread_stack_start)
183             {
184 
185                 if (stack_end < next_thread -> tx_thread_stack_end)
186                 {
187 
188                     /* This stack overlaps with an existing thread, clear the stack pointer to
189                        force a stack error below.  */
190                     stack_start =  TX_NULL;
191 
192                     /* Set the break flag.  */
193                     break_flag =  TX_TRUE;
194                 }
195             }
196 
197             /* Move to the next thread.  */
198             next_thread =  next_thread -> tx_thread_created_next;
199         }
200 
201         /* Disable interrupts.  */
202         TX_DISABLE
203 
204         /* Decrement the preempt disable flag.  */
205         _tx_thread_preempt_disable--;
206 
207         /* Restore interrupts.  */
208         TX_RESTORE
209 
210         /* Check for preemption.  */
211         _tx_thread_system_preempt_check();
212 
213         /* At this point, check to see if there is a duplicate thread.  */
214         if (thread_ptr == next_thread)
215         {
216 
217             /* Thread is already created, return appropriate error code.  */
218             status =  TX_THREAD_ERROR;
219         }
220 
221         /* Check for invalid starting address of stack.  */
222         else if (stack_start == TX_NULL)
223         {
224 
225             /* Invalid stack or entry point, return appropriate error code.  */
226             status =  TX_PTR_ERROR;
227         }
228 
229         /* Check for invalid thread entry point.  */
230         else if (entry_function == TX_NULL)
231         {
232 
233             /* Invalid stack or entry point, return appropriate error code.  */
234             status =  TX_PTR_ERROR;
235         }
236 
237         /* Check the stack size.  */
238         else if (stack_size < ((ULONG) TX_MINIMUM_STACK))
239         {
240 
241             /* Stack is not big enough, return appropriate error code.  */
242             status =  TX_SIZE_ERROR;
243         }
244 
245         /* Check the priority specified.  */
246         else if (priority >= ((UINT) TX_MAX_PRIORITIES))
247         {
248 
249             /* Invalid priority selected, return appropriate error code.  */
250             status =  TX_PRIORITY_ERROR;
251         }
252 
253         /* Check preemption threshold. */
254         else if (preempt_threshold > priority)
255         {
256 
257             /* Invalid preempt threshold, return appropriate error code.  */
258             status =  TX_THRESH_ERROR;
259         }
260 
261         /* Check the start selection.  */
262         else if (auto_start > TX_AUTO_START)
263         {
264 
265             /* Invalid auto start selection, return appropriate error code.  */
266             status =  TX_START_ERROR;
267         }
268         else
269         {
270 
271 #ifndef TX_TIMER_PROCESS_IN_ISR
272 
273             /* Pickup thread pointer.  */
274             TX_THREAD_GET_CURRENT(current_thread)
275 
276             /* Check for invalid caller of this function.  First check for a calling thread.  */
277             if (current_thread == &_tx_timer_thread)
278             {
279 
280                 /* Invalid caller of this function, return appropriate error code.  */
281                 status =  TX_CALLER_ERROR;
282             }
283 #endif
284 
285             /* Check for interrupt call.  */
286             if (TX_THREAD_GET_SYSTEM_STATE() != ((ULONG) 0))
287             {
288 
289                 /* Now, make sure the call is from an interrupt and not initialization.  */
290                 if (TX_THREAD_GET_SYSTEM_STATE() < TX_INITIALIZE_IN_PROGRESS)
291                 {
292 
293                     /* Invalid caller of this function, return appropriate error code.  */
294                     status =  TX_CALLER_ERROR;
295                 }
296             }
297         }
298     }
299 
300     /* Determine if everything is okay.  */
301     if (status == TX_SUCCESS)
302     {
303 
304         /* Call actual thread create function.  */
305         status =  _tx_thread_create(thread_ptr, name_ptr, entry_function, entry_input,
306                         stack_start, stack_size, priority, preempt_threshold,
307                         time_slice, auto_start);
308     }
309 
310     /* Return completion status.  */
311     return(status);
312 }
313 
314