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 #define TX_THREAD_SMP_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 SMP     */
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_ptr                              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 (0-31)     */
58 /*    preempt_threshold                     Preemption threshold          */
59 /*    time_slice                            Thread time-slice value       */
60 /*    auto_start                            Automatic start selection     */
61 /*                                                                        */
62 /*  OUTPUT                                                                */
63 /*                                                                        */
64 /*    return status                         Thread create return status   */
65 /*                                                                        */
66 /*  CALLS                                                                 */
67 /*                                                                        */
68 /*    _tx_thread_smp_rebalance_execute_list Rebalance execution list      */
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 /*  09-30-2020      William E. Lamie        Initial Version 6.1           */
83 /*  12-31-2020      Andres Mlinar           Modified comment(s),          */
84 /*                                            resulting in version 6.1.3  */
85 /*  08-02-2021      Scott Larson            Removed unneeded cast,        */
86 /*                                            resulting in version 6.1.8  */
87 /*  10-31-2022      Scott Larson            Removed ifdef block to always */
88 /*                                            restore interrupts at end   */
89 /*                                            of if block,                */
90 /*                                            resulting in version 6.2.0  */
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,
98                             VOID (*entry_function)(ULONG id), ULONG entry_input,
99                             VOID *stack_start, ULONG stack_size, UINT priority, UINT preempt_threshold,
100                             ULONG time_slice, UINT auto_start)
101 {
102 
103 TX_INTERRUPT_SAVE_AREA
104 
105 UINT                    core_index;
106 TX_THREAD               *next_thread;
107 TX_THREAD               *previous_thread;
108 UCHAR                   *temp_ptr;
109 #ifdef TX_ENABLE_STACK_CHECKING
110 ALIGN_TYPE              new_stack_start;
111 ALIGN_TYPE              updated_stack_start;
112 #endif
113 
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     new_stack_start =  TX_POINTER_TO_ALIGN_TYPE_CONVERT(stack_start);
143     updated_stack_start =  (((new_stack_start) + ((sizeof(ULONG)) - ((ULONG) 1)) ) & (~((sizeof(ULONG)) - ((ULONG) 1))));
144 
145     /* Determine if the starting stack address is different.  */
146     if (new_stack_start != updated_stack_start)
147     {
148 
149         /* Yes, subtract another ULONG from the size to avoid going past the stack area.  */
150         stack_size =  stack_size - (sizeof(ULONG));
151     }
152 
153     /* Update the starting stack pointer.  */
154     stack_start =  TX_ALIGN_TYPE_TO_POINTER_CONVERT(updated_stack_start);
155 #endif
156 
157     /* Prepare the thread control block prior to placing it on the created
158        list.  */
159 
160     /* Initialize thread control block to all zeros.  */
161     TX_MEMSET(thread_ptr, 0, sizeof(TX_THREAD));
162 
163     /* Place the supplied parameters into the thread's control block.  */
164     thread_ptr -> tx_thread_name =                name_ptr;
165     thread_ptr -> tx_thread_entry =               entry_function;
166     thread_ptr -> tx_thread_entry_parameter =     entry_input;
167     thread_ptr -> tx_thread_stack_start =         stack_start;
168     thread_ptr -> tx_thread_stack_size =          stack_size;
169     thread_ptr -> tx_thread_priority =            priority;
170     thread_ptr -> tx_thread_user_priority =       priority;
171     thread_ptr -> tx_thread_time_slice =          time_slice;
172     thread_ptr -> tx_thread_new_time_slice =      time_slice;
173     thread_ptr -> tx_thread_inherit_priority =    ((UINT) TX_MAX_PRIORITIES);
174     thread_ptr -> tx_thread_smp_core_executing =  ((UINT) TX_THREAD_SMP_MAX_CORES);
175     thread_ptr -> tx_thread_smp_cores_excluded =  ((ULONG) 0);
176 #ifndef TX_THREAD_SMP_DYNAMIC_CORE_MAX
177     thread_ptr -> tx_thread_smp_cores_allowed =   ((ULONG) TX_THREAD_SMP_CORE_MASK);
178 #else
179     thread_ptr -> tx_thread_smp_cores_allowed =   (((ULONG) 1) << _tx_thread_smp_max_cores) - 1;
180 #endif
181 
182 #ifdef TX_THREAD_SMP_ONLY_CORE_0_DEFAULT
183 
184     /* Default thread creation such that core0 is the only allowed core for execution, i.e., bit 1 is set to exclude core1.  */
185     thread_ptr -> tx_thread_smp_cores_excluded =  (TX_THREAD_SMP_CORE_MASK & 0xFFFFFFFE);
186     thread_ptr -> tx_thread_smp_cores_allowed  =  1;
187 
188     /* Default the timers to run on core 0 as well.  */
189     thread_ptr -> tx_thread_timer.tx_timer_internal_smp_cores_excluded =  (TX_THREAD_SMP_CORE_MASK & 0xFFFFFFFE);
190 
191     /* Default the mapped to 0 too.  */
192     thread_ptr -> tx_thread_smp_core_mapped =  0;
193 #endif
194 
195     /* Calculate the end of the thread's stack area.  */
196     temp_ptr =  TX_VOID_TO_UCHAR_POINTER_CONVERT(stack_start);
197     temp_ptr =  (TX_UCHAR_POINTER_ADD(temp_ptr, (stack_size - ((ULONG) 1))));
198     thread_ptr -> tx_thread_stack_end =         TX_UCHAR_TO_VOID_POINTER_CONVERT(temp_ptr);
199 
200 
201 #ifndef TX_DISABLE_PREEMPTION_THRESHOLD
202 
203     /* Preemption-threshold is enabled, setup accordingly.  */
204     thread_ptr -> tx_thread_preempt_threshold =       preempt_threshold;
205     thread_ptr -> tx_thread_user_preempt_threshold =  preempt_threshold;
206 #else
207 
208     /* Preemption-threshold is disabled, determine if preemption-threshold was required.  */
209     if (priority != preempt_threshold)
210     {
211 
212         /* Preemption-threshold specified. Since specific preemption-threshold is not supported,
213            disable all preemption.  */
214         thread_ptr -> tx_thread_preempt_threshold =       ((UINT) 0);
215         thread_ptr -> tx_thread_user_preempt_threshold =  ((UINT) 0);
216     }
217     else
218     {
219 
220         /* Preemption-threshold is not specified, just setup with the priority.  */
221         thread_ptr -> tx_thread_preempt_threshold =       priority;
222         thread_ptr -> tx_thread_user_preempt_threshold =  priority;
223     }
224 #endif
225 
226     /* Now fill in the values that are required for thread initialization.  */
227     thread_ptr -> tx_thread_state =  TX_SUSPENDED;
228 
229     /* Setup the necessary fields in the thread timer block.  */
230     TX_THREAD_CREATE_TIMEOUT_SETUP(thread_ptr)
231 
232     /* Perform any additional thread setup activities for tool or user purpose.  */
233     TX_THREAD_CREATE_INTERNAL_EXTENSION(thread_ptr)
234 
235     /* Call the target specific stack frame building routine to build the
236        thread's initial stack and to setup the actual stack pointer in the
237        control block.  */
238     _tx_thread_stack_build(thread_ptr, _tx_thread_shell_entry);
239 
240 #ifdef TX_ENABLE_STACK_CHECKING
241 
242     /* Setup the highest usage stack pointer.  */
243     thread_ptr -> tx_thread_stack_highest_ptr =  thread_ptr -> tx_thread_stack_ptr;
244 #endif
245 
246     /* Prepare to make this thread a member of the created thread list.  */
247     TX_DISABLE
248 
249     /* Load the thread ID field in the thread control block.  */
250     thread_ptr -> tx_thread_id =  TX_THREAD_ID;
251 
252     /* Place the thread on the list of created threads.  First,
253        check for an empty list.  */
254     if (_tx_thread_created_count == TX_EMPTY)
255     {
256 
257         /* The created thread list is empty.  Add thread to empty list.  */
258         _tx_thread_created_ptr =                    thread_ptr;
259         thread_ptr -> tx_thread_created_next =      thread_ptr;
260         thread_ptr -> tx_thread_created_previous =  thread_ptr;
261     }
262     else
263     {
264 
265         /* This list is not NULL, add to the end of the list.  */
266         next_thread =  _tx_thread_created_ptr;
267         previous_thread =  next_thread -> tx_thread_created_previous;
268 
269         /* Place the new thread in the list.  */
270         next_thread -> tx_thread_created_previous =  thread_ptr;
271         previous_thread -> tx_thread_created_next =  thread_ptr;
272 
273         /* Setup this thread's created links.  */
274         thread_ptr -> tx_thread_created_previous =  previous_thread;
275         thread_ptr -> tx_thread_created_next =      next_thread;
276     }
277 
278     /* Increment the thread created count.  */
279     _tx_thread_created_count++;
280 
281     /* If trace is enabled, register this object.  */
282     TX_TRACE_OBJECT_REGISTER(TX_TRACE_OBJECT_TYPE_THREAD, thread_ptr, name_ptr, TX_POINTER_TO_ULONG_CONVERT(stack_start), stack_size)
283 
284     /* If trace is enabled, insert this event into the trace buffer.  */
285     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)
286 
287     /* Register thread in the thread array structure.  */
288     TX_EL_THREAD_REGISTER(thread_ptr)
289 
290     /* Log this kernel call.  */
291     TX_EL_THREAD_CREATE_INSERT
292 
293 #ifndef TX_NOT_INTERRUPTABLE
294 
295     /* Temporarily disable preemption.  */
296     _tx_thread_preempt_disable++;
297 #endif
298 
299     /* Determine if an automatic start was requested.  If so, call the resume
300        thread function and then check for a preemption condition.  */
301     if (auto_start == TX_AUTO_START)
302     {
303 
304 #ifdef TX_NOT_INTERRUPTABLE
305 
306         /* Perform any additional activities for tool or user purpose.  */
307         TX_THREAD_CREATE_EXTENSION(thread_ptr)
308 
309         /* Resume the thread!  */
310         _tx_thread_system_ni_resume(thread_ptr);
311 
312 #else
313 
314         /* Restore previous interrupt posture.  */
315         TX_RESTORE
316 
317         /* Perform any additional activities for tool or user purpose.  */
318         TX_THREAD_CREATE_EXTENSION(thread_ptr)
319 
320         /* Call the resume thread function to make this thread ready.  */
321         _tx_thread_system_resume(thread_ptr);
322 
323         /* Disable interrupts again.  */
324         TX_DISABLE
325 #endif
326 
327         /* Determine if the execution list needs to be re-evaluated.  */
328         if (_tx_thread_smp_current_state_get() >= TX_INITIALIZE_IN_PROGRESS)
329         {
330 
331 #ifndef TX_DISABLE_PREEMPTION_THRESHOLD
332 
333             /* Clear the preemption bit maps, since nothing has yet run during initialization.  */
334             TX_MEMSET(_tx_thread_preempted_maps, 0, sizeof(_tx_thread_preempted_maps));
335 #if TX_MAX_PRIORITIES > 32
336             _tx_thread_preempted_map_active =  ((ULONG) 0);
337 #endif
338 
339             /* Clear the entry in the preempted thread list.  */
340             _tx_thread_preemption_threshold_list[priority] =  TX_NULL;
341 #endif
342 
343             /* Set the pointer to the thread currently with preemption-threshold set to NULL.  */
344             _tx_thread_preemption__threshold_scheduled =  TX_NULL;
345 
346 #ifdef TX_THREAD_SMP_DEBUG_ENABLE
347 
348             /* Debug entry.  */
349             _tx_thread_smp_debug_entry_insert(12, 0, thread_ptr);
350 #endif
351 
352             /* Get the core index.  */
353             core_index =  TX_SMP_CORE_ID;
354 
355             /* Call the rebalance routine. This routine maps cores and ready threads.  */
356             _tx_thread_smp_rebalance_execute_list(core_index);
357 
358 #ifdef TX_THREAD_SMP_DEBUG_ENABLE
359 
360             /* Debug entry.  */
361             _tx_thread_smp_debug_entry_insert(13, 0, thread_ptr);
362 #endif
363         }
364 
365         /* Restore interrupts.  */
366         TX_RESTORE
367     }
368     else
369     {
370 
371 #ifdef TX_NOT_INTERRUPTABLE
372 
373         /* Perform any additional activities for tool or user purpose.  */
374         TX_THREAD_CREATE_EXTENSION(thread_ptr)
375 
376         /* Restore interrupts.  */
377         TX_RESTORE
378 #else
379 
380         /* Restore interrupts.  */
381         TX_RESTORE
382 
383         /* Perform any additional activities for tool or user purpose.  */
384         TX_THREAD_CREATE_EXTENSION(thread_ptr)
385 
386         /* Disable interrupts.  */
387         TX_DISABLE
388 
389         /* Re-enable preemption.  */
390         _tx_thread_preempt_disable--;
391 
392         /* Restore interrupts.  */
393         TX_RESTORE
394 
395         /* Check for preemption.  */
396         _tx_thread_system_preempt_check();
397 #endif
398     }
399 
400     /* Return success.  */
401     return(TX_SUCCESS);
402 }
403 
404