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