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