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