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 #include "tx_initialize.h"
32 
33 
34 /**************************************************************************/
35 /*                                                                        */
36 /*  FUNCTION                                               RELEASE        */
37 /*                                                                        */
38 /*    _tx_thread_create                                   PORTABLE C      */
39 /*                                                           6.3.0        */
40 /*  AUTHOR                                                                */
41 /*                                                                        */
42 /*    William E. Lamie, Microsoft Corporation                             */
43 /*                                                                        */
44 /*  DESCRIPTION                                                           */
45 /*                                                                        */
46 /*    This function creates a thread and places it on the list of created */
47 /*    threads.                                                            */
48 /*                                                                        */
49 /*  INPUT                                                                 */
50 /*                                                                        */
51 /*    thread_ptr                            Thread control block pointer  */
52 /*    name                                  Pointer to thread name string */
53 /*    entry_function                        Entry function of the thread  */
54 /*    entry_input                           32-bit input value to thread  */
55 /*    stack_start                           Pointer to start of stack     */
56 /*    stack_size                            Stack size in bytes           */
57 /*    priority                              Priority of thread            */
58 /*                                            (default 0-31)              */
59 /*    preempt_threshold                     Preemption threshold          */
60 /*    time_slice                            Thread time-slice value       */
61 /*    auto_start                            Automatic start selection     */
62 /*                                                                        */
63 /*  OUTPUT                                                                */
64 /*                                                                        */
65 /*    return status                         Thread create return status   */
66 /*                                                                        */
67 /*  CALLS                                                                 */
68 /*                                                                        */
69 /*    _tx_thread_stack_build                Build initial thread stack    */
70 /*    _tx_thread_system_resume              Resume automatic start thread */
71 /*    _tx_thread_system_ni_resume           Noninterruptable resume thread*/
72 /*                                                                        */
73 /*  CALLED BY                                                             */
74 /*                                                                        */
75 /*    Application Code                                                    */
76 /*    _tx_timer_initialize                  Create system timer thread    */
77 /*                                                                        */
78 /*  RELEASE HISTORY                                                       */
79 /*                                                                        */
80 /*    DATE              NAME                      DESCRIPTION             */
81 /*                                                                        */
82 /*  05-19-2020      William E. Lamie        Initial Version 6.0           */
83 /*  09-30-2020      William E. Lamie        Modified comment(s), and      */
84 /*                                            changed stack calculations  */
85 /*                                            to use ALIGN_TYPE integers, */
86 /*                                            resulting in version 6.1    */
87 /*  06-02-2021      William E. Lamie        Modified comment(s), and      */
88 /*                                            supported TX_MISRA_ENABLE,  */
89 /*  08-02-2021      Scott Larson            Removed unneeded cast,        */
90 /*                                            resulting in version 6.1.8  */
91 /*  10-31-2023      Xiuwen Cai              Modified comment(s),          */
92 /*                                            added option for random     */
93 /*                                            number stack filling,       */
94 /*                                            resulting in version 6.3.0  */
95 /*                                                                        */
96 /**************************************************************************/
_tx_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)97 UINT  _tx_thread_create(TX_THREAD *thread_ptr, CHAR *name_ptr, VOID (*entry_function)(ULONG id), ULONG entry_input,
98                             VOID *stack_start, ULONG stack_size, UINT priority, UINT preempt_threshold,
99                             ULONG time_slice, UINT auto_start)
100 {
101 
102 TX_INTERRUPT_SAVE_AREA
103 
104 TX_THREAD               *next_thread;
105 TX_THREAD               *previous_thread;
106 TX_THREAD               *saved_thread_ptr;
107 UINT                    saved_threshold =  ((UINT) 0);
108 UCHAR                   *temp_ptr;
109 
110 #ifdef TX_ENABLE_STACK_CHECKING
111 ALIGN_TYPE              new_stack_start;
112 ALIGN_TYPE              updated_stack_start;
113 #endif
114 
115 #ifndef TX_DISABLE_STACK_FILLING
116 #if defined(TX_ENABLE_RANDOM_NUMBER_STACK_FILLING) && defined(TX_ENABLE_STACK_CHECKING)
117 
118     /* Initialize the stack fill value to a 8-bit random value.  */
119     thread_ptr -> tx_thread_stack_fill_value = ((ULONG) TX_RAND()) & 0xFFUL;
120 
121     /* Duplicate the random value in each of the 4 bytes of the stack fill value.  */
122     thread_ptr -> tx_thread_stack_fill_value = thread_ptr -> tx_thread_stack_fill_value |
123                     (thread_ptr -> tx_thread_stack_fill_value << 8) |
124                     (thread_ptr -> tx_thread_stack_fill_value << 16) |
125                     (thread_ptr -> tx_thread_stack_fill_value << 24);
126 #endif
127 
128     /* Set the thread stack to a pattern prior to creating the initial
129        stack frame.  This pattern is used by the stack checking routines
130        to see how much has been used.  */
131     TX_MEMSET(stack_start, ((UCHAR) TX_STACK_FILL), stack_size);
132 #endif
133 
134 #ifdef TX_ENABLE_STACK_CHECKING
135 
136     /* Ensure that there are two ULONG of 0xEF patterns at the top and
137        bottom of the thread's stack. This will be used to check for stack
138        overflow conditions during run-time.  */
139     stack_size =  ((stack_size/(sizeof(ULONG))) * (sizeof(ULONG))) - (sizeof(ULONG));
140 
141     /* Ensure the starting stack address is evenly aligned.  */
142 #ifdef TX_MISRA_ENABLE
143     new_stack_start = TX_POINTER_TO_ULONG_CONVERT(stack_start);
144 #else
145     new_stack_start =  TX_POINTER_TO_ALIGN_TYPE_CONVERT(stack_start);
146 #endif /* TX_MISRA_ENABLE */
147     updated_stack_start =  (((new_stack_start) + ((sizeof(ULONG)) - ((ULONG) 1)) ) & (~((sizeof(ULONG)) - ((ULONG) 1))));
148 
149     /* Determine if the starting stack address is different.  */
150     if (new_stack_start != updated_stack_start)
151     {
152 
153         /* Yes, subtract another ULONG from the size to avoid going past the stack area.  */
154         stack_size =  stack_size - (sizeof(ULONG));
155     }
156 
157     /* Update the starting stack pointer.  */
158 #ifdef TX_MISRA_ENABLE
159     stack_start = TX_ULONG_TO_POINTER_CONVERT(updated_stack_start);
160 #else
161     stack_start =  TX_ALIGN_TYPE_TO_POINTER_CONVERT(updated_stack_start);
162 #endif /* TX_MISRA_ENABLE */
163 #endif
164 
165     /* Prepare the thread control block prior to placing it on the created
166        list.  */
167 
168     /* Initialize thread control block to all zeros.  */
169     TX_MEMSET(thread_ptr, 0, (sizeof(TX_THREAD)));
170 
171     /* Place the supplied parameters into the thread's control block.  */
172     thread_ptr -> tx_thread_name =              name_ptr;
173     thread_ptr -> tx_thread_entry =             entry_function;
174     thread_ptr -> tx_thread_entry_parameter =   entry_input;
175     thread_ptr -> tx_thread_stack_start =       stack_start;
176     thread_ptr -> tx_thread_stack_size =        stack_size;
177     thread_ptr -> tx_thread_priority =          priority;
178     thread_ptr -> tx_thread_user_priority =     priority;
179     thread_ptr -> tx_thread_time_slice =        time_slice;
180     thread_ptr -> tx_thread_new_time_slice =    time_slice;
181     thread_ptr -> tx_thread_inherit_priority =  ((UINT) TX_MAX_PRIORITIES);
182 
183     /* Calculate the end of the thread's stack area.  */
184     temp_ptr =  TX_VOID_TO_UCHAR_POINTER_CONVERT(stack_start);
185     temp_ptr =  (TX_UCHAR_POINTER_ADD(temp_ptr, (stack_size - ((ULONG) 1))));
186     thread_ptr -> tx_thread_stack_end =         TX_UCHAR_TO_VOID_POINTER_CONVERT(temp_ptr);
187 
188 #ifndef TX_DISABLE_PREEMPTION_THRESHOLD
189 
190     /* Preemption-threshold is enabled, setup accordingly.  */
191     thread_ptr -> tx_thread_preempt_threshold =       preempt_threshold;
192     thread_ptr -> tx_thread_user_preempt_threshold =  preempt_threshold;
193 #else
194 
195     /* Preemption-threshold is disabled, determine if preemption-threshold was required.  */
196     if (priority != preempt_threshold)
197     {
198 
199         /* Preemption-threshold specified. Since specific preemption-threshold is not supported,
200            disable all preemption.  */
201         thread_ptr -> tx_thread_preempt_threshold =       ((UINT) 0);
202         thread_ptr -> tx_thread_user_preempt_threshold =  ((UINT) 0);
203     }
204     else
205     {
206 
207         /* Preemption-threshold is not specified, just setup with the priority.  */
208         thread_ptr -> tx_thread_preempt_threshold =       priority;
209         thread_ptr -> tx_thread_user_preempt_threshold =  priority;
210     }
211 #endif
212 
213     /* Now fill in the values that are required for thread initialization.  */
214     thread_ptr -> tx_thread_state =  TX_SUSPENDED;
215 
216     /* Setup the necessary fields in the thread timer block.  */
217     TX_THREAD_CREATE_TIMEOUT_SETUP(thread_ptr)
218 
219     /* Perform any additional thread setup activities for tool or user purpose.  */
220     TX_THREAD_CREATE_INTERNAL_EXTENSION(thread_ptr)
221 
222     /* Call the target specific stack frame building routine to build the
223        thread's initial stack and to setup the actual stack pointer in the
224        control block.  */
225     _tx_thread_stack_build(thread_ptr, _tx_thread_shell_entry);
226 
227 #ifdef TX_ENABLE_STACK_CHECKING
228 
229     /* Setup the highest usage stack pointer.  */
230     thread_ptr -> tx_thread_stack_highest_ptr =  thread_ptr -> tx_thread_stack_ptr;
231 #endif
232 
233     /* Prepare to make this thread a member of the created thread list.  */
234     TX_DISABLE
235 
236     /* Load the thread ID field in the thread control block.  */
237     thread_ptr -> tx_thread_id =  TX_THREAD_ID;
238 
239     /* Place the thread on the list of created threads.  First,
240        check for an empty list.  */
241     if (_tx_thread_created_count == TX_EMPTY)
242     {
243 
244         /* The created thread list is empty.  Add thread to empty list.  */
245         _tx_thread_created_ptr =                    thread_ptr;
246         thread_ptr -> tx_thread_created_next =      thread_ptr;
247         thread_ptr -> tx_thread_created_previous =  thread_ptr;
248     }
249     else
250     {
251 
252         /* This list is not NULL, add to the end of the list.  */
253         next_thread =  _tx_thread_created_ptr;
254         previous_thread =  next_thread -> tx_thread_created_previous;
255 
256         /* Place the new thread in the list.  */
257         next_thread -> tx_thread_created_previous =  thread_ptr;
258         previous_thread -> tx_thread_created_next =  thread_ptr;
259 
260         /* Setup this thread's created links.  */
261         thread_ptr -> tx_thread_created_previous =  previous_thread;
262         thread_ptr -> tx_thread_created_next =      next_thread;
263     }
264 
265     /* Increment the thread created count.  */
266     _tx_thread_created_count++;
267 
268     /* If trace is enabled, register this object.  */
269     TX_TRACE_OBJECT_REGISTER(TX_TRACE_OBJECT_TYPE_THREAD, thread_ptr, name_ptr, TX_POINTER_TO_ULONG_CONVERT(stack_start), stack_size)
270 
271     /* If trace is enabled, insert this event into the trace buffer.  */
272     TX_TRACE_IN_LINE_INSERT(TX_TRACE_THREAD_CREATE, thread_ptr, priority, TX_POINTER_TO_ULONG_CONVERT(stack_start), stack_size, TX_TRACE_THREAD_EVENTS)
273 
274     /* Register thread in the thread array structure.  */
275     TX_EL_THREAD_REGISTER(thread_ptr)
276 
277     /* Log this kernel call.  */
278     TX_EL_THREAD_CREATE_INSERT
279 
280 #ifndef TX_NOT_INTERRUPTABLE
281 
282     /* Temporarily disable preemption.  */
283     _tx_thread_preempt_disable++;
284 #endif
285 
286     /* Determine if an automatic start was requested.  If so, call the resume
287        thread function and then check for a preemption condition.  */
288     if (auto_start == TX_AUTO_START)
289     {
290 
291         /* Determine if the create call is being called from initialization.  */
292         if (TX_THREAD_GET_SYSTEM_STATE() >= TX_INITIALIZE_IN_PROGRESS)
293         {
294 
295             /* Yes, this create call was made from initialization.  */
296 
297             /* Pickup the current thread execute pointer, which corresponds to the
298                highest priority thread ready to execute.  Interrupt lockout is
299                not required, since interrupts are assumed to be disabled during
300                initialization.  */
301             saved_thread_ptr =  _tx_thread_execute_ptr;
302 
303             /* Determine if there is thread ready for execution.  */
304             if (saved_thread_ptr != TX_NULL)
305             {
306 
307                 /* Yes, a thread is ready for execution when initialization completes.  */
308 
309                 /* Save the current preemption-threshold.  */
310                 saved_threshold =  saved_thread_ptr -> tx_thread_preempt_threshold;
311 
312                 /* For initialization, temporarily set the preemption-threshold to the
313                    priority level to make sure the highest-priority thread runs once
314                    initialization is complete.  */
315                 saved_thread_ptr -> tx_thread_preempt_threshold =  saved_thread_ptr -> tx_thread_priority;
316             }
317         }
318         else
319         {
320 
321             /* Simply set the saved thread pointer to NULL.  */
322             saved_thread_ptr =  TX_NULL;
323         }
324 
325 #ifdef TX_NOT_INTERRUPTABLE
326 
327         /* Perform any additional activities for tool or user purpose.  */
328         TX_THREAD_CREATE_EXTENSION(thread_ptr)
329 
330         /* Resume the thread!  */
331         _tx_thread_system_ni_resume(thread_ptr);
332 
333         /* Restore previous interrupt posture.  */
334         TX_RESTORE
335 #else
336 
337         /* Restore previous interrupt posture.  */
338         TX_RESTORE
339 
340         /* Perform any additional activities for tool or user purpose.  */
341         TX_THREAD_CREATE_EXTENSION(thread_ptr)
342 
343         /* Call the resume thread function to make this thread ready.  */
344         _tx_thread_system_resume(thread_ptr);
345 #endif
346 
347         /* Determine if the thread's preemption-threshold needs to be restored.  */
348         if (saved_thread_ptr != TX_NULL)
349         {
350 
351             /* Yes, restore the previous highest-priority thread's preemption-threshold. This
352                can only happen if this routine is called from initialization.  */
353             saved_thread_ptr -> tx_thread_preempt_threshold =  saved_threshold;
354         }
355     }
356     else
357     {
358 
359 #ifdef TX_NOT_INTERRUPTABLE
360 
361         /* Perform any additional activities for tool or user purpose.  */
362         TX_THREAD_CREATE_EXTENSION(thread_ptr)
363 
364         /* Restore interrupts.  */
365         TX_RESTORE
366 #else
367 
368         /* Restore interrupts.  */
369         TX_RESTORE
370 
371         /* Perform any additional activities for tool or user purpose.  */
372         TX_THREAD_CREATE_EXTENSION(thread_ptr)
373 
374         /* Disable interrupts.  */
375         TX_DISABLE
376 
377         /* Re-enable preemption.  */
378         _tx_thread_preempt_disable--;
379 
380         /* Restore interrupts.  */
381         TX_RESTORE
382 
383         /* Check for preemption.  */
384         _tx_thread_system_preempt_check();
385 #endif
386     }
387 
388     /* Always return a success.  */
389     return(TX_SUCCESS);
390 }
391 
392