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 /**   Module Manager                                                      */
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 #include "tx_timer.h"
34 #include "txm_module.h"
35 
36 
37 /**************************************************************************/
38 /*                                                                        */
39 /*  FUNCTION                                               RELEASE        */
40 /*                                                                        */
41 /*    _txm_module_manager_thread_create                   PORTABLE C      */
42 /*                                                           6.3.0        */
43 /*  AUTHOR                                                                */
44 /*                                                                        */
45 /*    Scott Larson, Microsoft Corporation                                 */
46 /*                                                                        */
47 /*  DESCRIPTION                                                           */
48 /*                                                                        */
49 /*    This function creates a thread and places it on the list of created */
50 /*    threads.                                                            */
51 /*                                                                        */
52 /*  INPUT                                                                 */
53 /*                                                                        */
54 /*    thread_ptr                            Thread control block pointer  */
55 /*    name                                  Pointer to thread name string */
56 /*    shell_function                        Shell function of the thread  */
57 /*    entry_function                        Entry function of the thread  */
58 /*    entry_input                           32-bit input value to thread  */
59 /*    stack_start                           Pointer to start of stack     */
60 /*    stack_size                            Stack size in bytes           */
61 /*    priority                              Priority of thread            */
62 /*                                            (default 0-31)              */
63 /*    preempt_threshold                     Preemption threshold          */
64 /*    time_slice                            Thread time-slice value       */
65 /*    auto_start                            Automatic start selection     */
66 /*                                                                        */
67 /*  OUTPUT                                                                */
68 /*                                                                        */
69 /*    return status                         Thread create return status   */
70 /*                                                                        */
71 /*  CALLS                                                                 */
72 /*                                                                        */
73 /*    _txm_module_manager_thread_stack_build Build initial thread stack   */
74 /*    _tx_thread_system_resume              Resume automatic start thread */
75 /*    _tx_thread_system_ni_resume           Noninterruptable resume thread*/
76 /*    _tx_thread_system_preempt_check       Check for preemption          */
77 /*                                                                        */
78 /*  CALLED BY                                                             */
79 /*                                                                        */
80 /*    _txm_module_manager_start             Initiate module's start thread*/
81 /*    _txm_module_manager_stop              Initiate module's stop thread */
82 /*    _txm_module_manager_kernel_dispatch   Kernel dispatch function      */
83 /*                                                                        */
84 /*  RELEASE HISTORY                                                       */
85 /*                                                                        */
86 /*    DATE              NAME                      DESCRIPTION             */
87 /*                                                                        */
88 /*  09-30-2020      Scott Larson            Initial Version 6.1           */
89 /*  12-31-2020      Scott Larson            Modified comment(s),          */
90 /*                                            fix stack overlap checking, */
91 /*                                            added 64-bit support,       */
92 /*                                            added SMP support,          */
93 /*                                            resulting in version 6.1.3  */
94 /*  03-08-2023      Scott Larson            Check module stack for        */
95 /*                                            overlap,                    */
96 /*                                            resulting in version 6.2.1  */
97 /*  10-31-2023      Xiuwen Cai, Yajun xia   Modified comment(s),          */
98 /*                                            added option for random     */
99 /*                                            number stack filling,       */
100 /*                                            fixed the kernel stack      */
101 /*                                            allocation issue,           */
102 /*                                            resulting in version 6.3.0  */
103 /*                                                                        */
104 /**************************************************************************/
_txm_module_manager_thread_create(TX_THREAD * thread_ptr,CHAR * name_ptr,VOID (* shell_function)(TX_THREAD *,TXM_MODULE_INSTANCE *),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,UINT thread_control_block_size,TXM_MODULE_INSTANCE * module_instance)105 UINT  _txm_module_manager_thread_create(TX_THREAD *thread_ptr, CHAR *name_ptr,
106                             VOID (*shell_function)(TX_THREAD *, TXM_MODULE_INSTANCE *),
107                             VOID (*entry_function)(ULONG id), ULONG entry_input,
108                             VOID *stack_start, ULONG stack_size, UINT priority, UINT preempt_threshold,
109                             ULONG time_slice, UINT auto_start,
110                             UINT thread_control_block_size, TXM_MODULE_INSTANCE *module_instance)
111 {
112 
113 TX_INTERRUPT_SAVE_AREA
114 
115 #ifdef TX_THREAD_SMP
116 UINT                    core_index;
117 #endif
118 TX_THREAD               *next_thread;
119 TX_THREAD               *previous_thread;
120 TX_THREAD               *saved_thread_ptr;
121 UINT                    saved_threshold =  ((UINT) 0);
122 UCHAR                   *temp_ptr;
123 #ifdef TX_ENABLE_STACK_CHECKING
124 ALIGN_TYPE              new_stack_start;
125 ALIGN_TYPE              updated_stack_start;
126 #endif
127 TXM_MODULE_THREAD_ENTRY_INFO *thread_entry_info;
128 VOID                    *stack_end;
129 ULONG                   i;
130 
131     /* First, check for an invalid thread pointer.  */
132     if (thread_ptr == TX_NULL)
133     {
134 
135         /* Thread pointer is invalid, return appropriate error code.  */
136         return(TX_THREAD_ERROR);
137     }
138 
139     /* Now check for invalid thread control block size.  */
140     else if (thread_control_block_size != (sizeof(TX_THREAD)))
141     {
142 
143         /* Thread pointer is invalid, return appropriate error code.  */
144         return(TX_THREAD_ERROR);
145     }
146 
147     /* Disable interrupts.  */
148     TX_DISABLE
149 
150     /* Increment the preempt disable flag.  */
151     _tx_thread_preempt_disable++;
152 
153     /* Restore interrupts.  */
154     TX_RESTORE
155 
156     /* Next see if it is already in the created list.  */
157     next_thread =  _tx_thread_created_ptr;
158     stack_end   =  (VOID *) (((UCHAR *) ((VOID *) stack_start)) + (stack_size - 1));
159     for (i = 0; i < _tx_thread_created_count; i++)
160     {
161 
162         /* Determine if this thread matches the thread in the list.  */
163         if (thread_ptr == next_thread)
164         {
165 
166             break;
167         }
168 
169         /* Check the stack pointer to see if it overlaps with this thread's stack.  */
170         if ((((UCHAR *) ((VOID *) stack_start)) <= ((UCHAR *) ((VOID *) next_thread -> tx_thread_module_stack_end))) &&
171             (((UCHAR *) ((VOID *) stack_end)) >= ((UCHAR *) ((VOID *) next_thread -> tx_thread_module_stack_start))))
172         {
173             /* Stacks overlap, clear the stack pointer to force a stack error below.  */
174             stack_start =  TX_NULL;
175             break;
176         }
177 
178         /* Move to the next thread.  */
179         next_thread =  next_thread -> tx_thread_created_next;
180     }
181 
182     /* Disable interrupts.  */
183     TX_DISABLE
184 
185     /* Decrement the preempt disable flag.  */
186     _tx_thread_preempt_disable--;
187 
188     /* Restore interrupts.  */
189     TX_RESTORE
190 
191     /* Check for preemption.  */
192     _tx_thread_system_preempt_check();
193 
194     /* At this point, check to see if there is a duplicate thread.  */
195     if (thread_ptr == next_thread)
196     {
197 
198         /* Thread is already created, return appropriate error code.  */
199         return(TX_THREAD_ERROR);
200     }
201 
202     /* Check for invalid starting address of stack.  */
203     if (stack_start == TX_NULL)
204     {
205 
206         /* Invalid stack or entry point, return appropriate error code.  */
207         return(TX_PTR_ERROR);
208     }
209 
210     /* Check for invalid thread entry point.  */
211     if (entry_function == TX_NULL)
212     {
213 
214         /* Invalid stack or entry point, return appropriate error code.  */
215         return(TX_PTR_ERROR);
216     }
217 
218     /* Check the stack size.  */
219     if (stack_size < TX_MINIMUM_STACK)
220     {
221 
222         /* Stack is not big enough, return appropriate error code.  */
223         return(TX_SIZE_ERROR);
224     }
225 
226     /* Check the priority specified.  */
227     if (priority >= TX_MAX_PRIORITIES)
228     {
229 
230         /* Invalid priority selected, return appropriate error code.  */
231         return(TX_PRIORITY_ERROR);
232     }
233 
234     /* Check preemption threshold. */
235     if (preempt_threshold > priority)
236     {
237 
238         /* Invalid preempt threshold, return appropriate error code.  */
239         return(TX_THRESH_ERROR);
240     }
241 
242     /* Check the start selection.  */
243     if (auto_start > TX_AUTO_START)
244     {
245 
246         /* Invalid auto start selection, return appropriate error code.  */
247         return(TX_START_ERROR);
248     }
249 
250 #ifndef TX_TIMER_PROCESS_IN_ISR
251     {
252         TX_THREAD *current_thread;
253 
254         /* Pickup thread pointer.  */
255         TX_THREAD_GET_CURRENT(current_thread)
256 
257         /* Check for invalid caller of this function.  First check for a calling thread.  */
258         if (current_thread == &_tx_timer_thread)
259         {
260 
261             /* Invalid caller of this function, return appropriate error code.  */
262             return(TX_CALLER_ERROR);
263         }
264     }
265 #endif
266 
267     /* Check for interrupt call.  */
268     if (TX_THREAD_GET_SYSTEM_STATE() != 0)
269     {
270 
271         /* Now, make sure the call is from an interrupt and not initialization.  */
272         if (TX_THREAD_GET_SYSTEM_STATE() < TX_INITIALIZE_IN_PROGRESS)
273         {
274 
275             /* Invalid caller of this function, return appropriate error code.  */
276             return(TX_CALLER_ERROR);
277         }
278     }
279 
280 #ifndef TX_DISABLE_STACK_FILLING
281 #if defined(TX_ENABLE_RANDOM_NUMBER_STACK_FILLING) && defined(TX_ENABLE_STACK_CHECKING)
282 
283     /* Initialize the stack fill value to a 8-bit random value.  */
284     thread_ptr -> tx_thread_stack_fill_value = ((ULONG) TX_RAND()) & 0xFFUL;
285 
286     /* Duplicate the random value in each of the 4 bytes of the stack fill value.  */
287     thread_ptr -> tx_thread_stack_fill_value = thread_ptr -> tx_thread_stack_fill_value |
288                     (thread_ptr -> tx_thread_stack_fill_value << 8) |
289                     (thread_ptr -> tx_thread_stack_fill_value << 16) |
290                     (thread_ptr -> tx_thread_stack_fill_value << 24);
291 #endif
292 
293     /* Set the thread stack to a pattern prior to creating the initial
294        stack frame.  This pattern is used by the stack checking routines
295        to see how much has been used.  */
296     TX_MEMSET(stack_start, ((UCHAR) TX_STACK_FILL), stack_size);
297 #endif
298 
299 #ifdef TX_ENABLE_STACK_CHECKING
300 
301     /* Ensure that there are two ULONG of 0xEF patterns at the top and
302        bottom of the thread's stack. This will be used to check for stack
303        overflow conditions during run-time.  */
304     stack_size =  ((stack_size/(sizeof(ULONG))) * (sizeof(ULONG))) - (sizeof(ULONG));
305 
306     /* Ensure the starting stack address is evenly aligned.  */
307     new_stack_start =  TX_POINTER_TO_ALIGN_TYPE_CONVERT(stack_start);
308     updated_stack_start =  ((((ULONG) new_stack_start) + ((sizeof(ULONG)) - ((ULONG) 1)) ) & (~((sizeof(ULONG)) - ((ULONG) 1))));
309 
310     /* Determine if the starting stack address is different.  */
311     if (new_stack_start != updated_stack_start)
312     {
313 
314         /* Yes, subtract another ULONG from the size to avoid going past the stack area.  */
315         stack_size =  stack_size - (sizeof(ULONG));
316     }
317 
318     /* Update the starting stack pointer.  */
319     stack_start =  TX_ALIGN_TYPE_TO_POINTER_CONVERT(updated_stack_start);
320 #endif
321 
322     /* Allocate the thread entry information at the top of thread's stack - Leaving one
323        ULONG worth of 0xEF pattern between the actual stack and the entry info structure.  */
324     stack_size =  stack_size - (sizeof(TXM_MODULE_THREAD_ENTRY_INFO) + (3*sizeof(ULONG)));
325 
326     /* Prepare the thread control block prior to placing it on the created
327        list.  */
328 
329     /* Initialize thread control block to all zeros.  */
330     TX_MEMSET(thread_ptr, 0, sizeof(TX_THREAD));
331 
332     /* If the thread runs on user mode, allocate the kernel stack for syscall.  */
333     if((module_instance -> txm_module_instance_property_flags) & TXM_MODULE_USER_MODE)
334     {
335         ULONG status;
336 
337         /* Allocate kernel stack space. */
338         status = _txm_module_manager_object_allocate((VOID **) &(thread_ptr -> tx_thread_module_kernel_stack_start), TXM_MODULE_KERNEL_STACK_SIZE, module_instance);
339         if(status)
340         {
341             return(status);
342         }
343 
344 #ifndef TX_DISABLE_STACK_FILLING
345         /* Set the thread stack to a pattern prior to creating the initial
346            stack frame.  This pattern is used by the stack checking routines
347            to see how much has been used.  */
348         TX_MEMSET(thread_ptr -> tx_thread_module_kernel_stack_start, ((UCHAR) TX_STACK_FILL), TXM_MODULE_KERNEL_STACK_SIZE);
349 #endif
350 
351         /* Align kernel stack pointer.  */
352         thread_ptr -> tx_thread_module_kernel_stack_end = (VOID *) (((ALIGN_TYPE)(thread_ptr -> tx_thread_module_kernel_stack_start) + TXM_MODULE_KERNEL_STACK_SIZE) & ~0x07);
353 
354         /* Set kernel stack size.  */
355         thread_ptr -> tx_thread_module_kernel_stack_size = TXM_MODULE_KERNEL_STACK_SIZE;
356     }
357 
358 #if TXM_MODULE_MEMORY_PROTECTION
359     /* Place the stack parameters into the thread's control block.  */
360     thread_ptr -> tx_thread_module_stack_start =  stack_start;
361     thread_ptr -> tx_thread_module_stack_size =   stack_size;
362 #endif
363 
364     /* Place the supplied parameters into the thread's control block.  */
365     thread_ptr -> tx_thread_name =                name_ptr;
366     thread_ptr -> tx_thread_entry =               entry_function;
367     thread_ptr -> tx_thread_entry_parameter =     entry_input;
368     thread_ptr -> tx_thread_stack_start =         stack_start;
369     thread_ptr -> tx_thread_stack_size =          stack_size;
370     thread_ptr -> tx_thread_priority =            priority;
371     thread_ptr -> tx_thread_user_priority =       priority;
372     thread_ptr -> tx_thread_time_slice =          time_slice;
373     thread_ptr -> tx_thread_new_time_slice =      time_slice;
374     thread_ptr -> tx_thread_inherit_priority =    ((UINT) TX_MAX_PRIORITIES);
375 #ifdef TX_THREAD_SMP
376     thread_ptr -> tx_thread_smp_core_executing =  ((UINT) TX_THREAD_SMP_MAX_CORES);
377     thread_ptr -> tx_thread_smp_cores_excluded =  ((ULONG) 0);
378 #ifndef TX_THREAD_SMP_DYNAMIC_CORE_MAX
379     thread_ptr -> tx_thread_smp_cores_allowed =   ((ULONG) TX_THREAD_SMP_CORE_MASK);
380 #else
381     thread_ptr -> tx_thread_smp_cores_allowed =   (((ULONG) 1) << _tx_thread_smp_max_cores) - 1;
382 #endif
383 
384 #ifdef TX_THREAD_SMP_ONLY_CORE_0_DEFAULT
385 
386     /* Default thread creation such that core0 is the only allowed core for execution, i.e., bit 1 is set to exclude core1.  */
387     thread_ptr -> tx_thread_smp_cores_excluded =  (TX_THREAD_SMP_CORE_MASK & 0xFFFFFFFE);
388     thread_ptr -> tx_thread_smp_cores_allowed  =  1;
389 
390     /* Default the timers to run on core 0 as well.  */
391     thread_ptr -> tx_thread_timer.tx_timer_internal_smp_cores_excluded =  (TX_THREAD_SMP_CORE_MASK & 0xFFFFFFFE);
392 
393     /* Default the mapped to 0 too.  */
394     thread_ptr -> tx_thread_smp_core_mapped =  0;
395 #endif
396 #endif
397 
398     /* Calculate the end of the thread's stack area.  */
399     temp_ptr =  TX_VOID_TO_UCHAR_POINTER_CONVERT(stack_start);
400     temp_ptr =  (TX_UCHAR_POINTER_ADD(temp_ptr, (stack_size - ((ULONG) 1))));
401     thread_ptr -> tx_thread_stack_end =         TX_UCHAR_TO_VOID_POINTER_CONVERT(temp_ptr);
402 #if TXM_MODULE_MEMORY_PROTECTION
403     thread_ptr -> tx_thread_module_stack_end =  thread_ptr -> tx_thread_stack_end;
404 #endif /* TXM_MODULE_MEMORY_PROTECTION */
405 
406 #ifndef TX_DISABLE_PREEMPTION_THRESHOLD
407 
408     /* Preemption-threshold is enabled, setup accordingly.  */
409     thread_ptr -> tx_thread_preempt_threshold =       preempt_threshold;
410     thread_ptr -> tx_thread_user_preempt_threshold =  preempt_threshold;
411 #else
412 
413     /* Preemption-threshold is disabled, determine if preemption-threshold was required.  */
414     if (priority != preempt_threshold)
415     {
416 
417         /* Preemption-threshold specified. Since specific preemption-threshold is not supported,
418            disable all preemption.  */
419         thread_ptr -> tx_thread_preempt_threshold =       ((UINT) 0);
420         thread_ptr -> tx_thread_user_preempt_threshold =  ((UINT) 0);
421     }
422     else
423     {
424 
425         /* Preemption-threshold is not specified, just setup with the priority.  */
426         thread_ptr -> tx_thread_preempt_threshold =       priority;
427         thread_ptr -> tx_thread_user_preempt_threshold =  priority;
428     }
429 #endif
430 
431     /* Now fill in the values that are required for thread initialization.  */
432     thread_ptr -> tx_thread_state =  TX_SUSPENDED;
433 
434     /* Setup the necessary fields in the thread timer block.  */
435     TX_THREAD_CREATE_TIMEOUT_SETUP(thread_ptr)
436 
437     /* Perform any additional thread setup activities for tool or user purpose.  */
438     TX_THREAD_CREATE_INTERNAL_EXTENSION(thread_ptr)
439 
440     /* Setup pointer to the thread entry information structure, which will live at the top of each
441        module thread's stack. This will allow the module thread entry function to avoid direct
442        access to the actual thread control block.  */
443     thread_entry_info =  (TXM_MODULE_THREAD_ENTRY_INFO *) (((UCHAR *) thread_ptr -> tx_thread_stack_end) + (2*sizeof(ULONG)) + 1);
444     thread_entry_info =  (TXM_MODULE_THREAD_ENTRY_INFO *) (((ALIGN_TYPE)(thread_entry_info)) & (~0x3));
445 
446     /* Build the thread entry information structure.  */
447     thread_entry_info -> txm_module_thread_entry_info_thread =                   thread_ptr;
448     thread_entry_info -> txm_module_thread_entry_info_module =                   module_instance;
449     thread_entry_info -> txm_module_thread_entry_info_data_base_address =        module_instance -> txm_module_instance_module_data_base_address;
450     thread_entry_info -> txm_module_thread_entry_info_code_base_address =        module_instance -> txm_module_instance_code_start;
451     thread_entry_info -> txm_module_thread_entry_info_entry =                    thread_ptr -> tx_thread_entry;
452     thread_entry_info -> txm_module_thread_entry_info_parameter =                thread_ptr -> tx_thread_entry_parameter;
453     thread_entry_info -> txm_module_thread_entry_info_callback_request_queue =   &(module_instance -> txm_module_instance_callback_request_queue);
454     thread_entry_info -> txm_module_thread_entry_info_callback_request_thread =  &(module_instance -> txm_module_instance_callback_request_thread);
455 
456     /* Populate thread control block with some stock information from the module.  */
457     TXM_MODULE_MANAGER_THREAD_SETUP(thread_ptr, module_instance)
458 
459 #ifndef TX_DISABLE_NOTIFY_CALLBACKS
460     thread_entry_info ->  txm_module_thread_entry_info_exit_notify =        thread_ptr -> tx_thread_entry_exit_notify;
461 #else /* TX_DISABLE_NOTIFY_CALLBACKS */
462     thread_entry_info ->  txm_module_thread_entry_info_exit_notify =        TX_NULL;
463 #endif /* TX_DISABLE_NOTIFY_CALLBACKS */
464     if (thread_ptr -> tx_thread_entry == module_instance -> txm_module_instance_start_thread_entry)
465         thread_entry_info ->  txm_module_thread_entry_info_start_thread =   TX_TRUE;
466     else
467         thread_entry_info ->  txm_module_thread_entry_info_start_thread =   TX_FALSE;
468 
469     /* Place pointers to the thread info and module instance in the thread control block.  */
470     thread_ptr -> tx_thread_module_instance_ptr =    (VOID *) module_instance;
471     thread_ptr -> tx_thread_module_entry_info_ptr =  (VOID *) thread_entry_info;
472 
473     /* Place the thread entry information pointer in the thread control block so it can be picked up
474        in the following stack build function. This is supplied to the module's shell entry function
475        to avoid direct access to the actual thread control block. Note that this is overwritten
476        with the actual stack pointer at the end of stack build.  */
477     thread_ptr -> tx_thread_stack_ptr =  (VOID *) thread_entry_info;
478 
479     /* Call the target specific stack frame building routine to build the
480        thread's initial stack and to setup the actual stack pointer in the
481        control block.  */
482     _txm_module_manager_thread_stack_build(thread_ptr, shell_function);
483 
484 #ifdef TX_ENABLE_STACK_CHECKING
485 
486     /* Setup the highest usage stack pointer.  */
487     thread_ptr -> tx_thread_stack_highest_ptr =  thread_ptr -> tx_thread_stack_ptr;
488 #endif
489 
490     /* Prepare to make this thread a member of the created thread list.  */
491     TX_DISABLE
492 
493     /* Load the thread ID field in the thread control block.  */
494     thread_ptr -> tx_thread_id =  TX_THREAD_ID;
495 
496     /* Place the thread on the list of created threads.  First,
497        check for an empty list.  */
498     if (_tx_thread_created_count == TX_EMPTY)
499     {
500 
501         /* The created thread list is empty.  Add thread to empty list.  */
502         _tx_thread_created_ptr =                    thread_ptr;
503         thread_ptr -> tx_thread_created_next =      thread_ptr;
504         thread_ptr -> tx_thread_created_previous =  thread_ptr;
505     }
506     else
507     {
508 
509         /* This list is not NULL, add to the end of the list.  */
510         next_thread =  _tx_thread_created_ptr;
511         previous_thread =  next_thread -> tx_thread_created_previous;
512 
513         /* Place the new thread in the list.  */
514         next_thread -> tx_thread_created_previous =  thread_ptr;
515         previous_thread -> tx_thread_created_next =  thread_ptr;
516 
517         /* Setup this thread's created links.  */
518         thread_ptr -> tx_thread_created_previous =  previous_thread;
519         thread_ptr -> tx_thread_created_next =      next_thread;
520     }
521 
522     /* Increment the thread created count.  */
523     _tx_thread_created_count++;
524 
525     /* If trace is enabled, register this object.  */
526     TX_TRACE_OBJECT_REGISTER(TX_TRACE_OBJECT_TYPE_THREAD, thread_ptr, name_ptr, TX_POINTER_TO_ULONG_CONVERT(stack_start), stack_size)
527 
528     /* If trace is enabled, insert this event into the trace buffer.  */
529     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)
530 
531     /* Register thread in the thread array structure.  */
532     TX_EL_THREAD_REGISTER(thread_ptr)
533 
534     /* Log this kernel call.  */
535     TX_EL_THREAD_CREATE_INSERT
536 
537 #ifdef TX_THREAD_SMP
538 
539 #ifndef TX_NOT_INTERRUPTABLE
540 
541     /* Temporarily disable preemption.  */
542     _tx_thread_preempt_disable++;
543 #endif
544 
545     /* Determine if an automatic start was requested.  If so, call the resume
546        thread function and then check for a preemption condition.  */
547     if (auto_start == TX_AUTO_START)
548     {
549 
550 #ifdef TX_NOT_INTERRUPTABLE
551 
552         /* Perform any additional activities for tool or user purpose.  */
553         TX_THREAD_CREATE_EXTENSION(thread_ptr)
554 
555         /* Resume the thread!  */
556         _tx_thread_system_ni_resume(thread_ptr);
557 
558 #else
559 
560         /* Restore previous interrupt posture.  */
561         TX_RESTORE
562 
563         /* Perform any additional activities for tool or user purpose.  */
564         TX_THREAD_CREATE_EXTENSION(thread_ptr)
565 
566         /* Call the resume thread function to make this thread ready.  */
567         _tx_thread_system_resume(thread_ptr);
568 
569         /* Disable interrupts again.  */
570         TX_DISABLE
571 #endif
572 
573         /* Determine if the execution list needs to be re-evaluated.  */
574         if (_tx_thread_smp_current_state_get() >= TX_INITIALIZE_IN_PROGRESS)
575         {
576 
577 #ifndef TX_DISABLE_PREEMPTION_THRESHOLD
578 
579             /* Clear the preemption bit maps, since nothing has yet run during initialization.  */
580             TX_MEMSET(_tx_thread_preempted_maps, 0, sizeof(_tx_thread_preempted_maps));
581 #if TX_MAX_PRIORITIES > 32
582             _tx_thread_preempted_map_active =  ((ULONG) 0);
583 #endif
584 
585             /* Clear the entry in the preempted thread list.  */
586             _tx_thread_preemption_threshold_list[priority] =  TX_NULL;
587 #endif
588 
589             /* Set the pointer to the thread currently with preemption-threshold set to NULL.  */
590             _tx_thread_preemption__threshold_scheduled =  TX_NULL;
591 
592 #ifdef TX_THREAD_SMP_DEBUG_ENABLE
593 
594             /* Debug entry.  */
595             _tx_thread_smp_debug_entry_insert(12, 0, thread_ptr);
596 #endif
597 
598             /* Get the core index.  */
599             core_index =  TX_SMP_CORE_ID;
600 
601             /* Call the rebalance routine. This routine maps cores and ready threads.  */
602             _tx_thread_smp_rebalance_execute_list(core_index);
603 
604 #ifdef TX_THREAD_SMP_DEBUG_ENABLE
605 
606             /* Debug entry.  */
607             _tx_thread_smp_debug_entry_insert(13, 0, thread_ptr);
608 #endif
609         }
610 
611 #ifndef TX_NOT_INTERRUPTABLE
612 
613         /* Restore interrupts.  */
614         TX_RESTORE
615 #endif
616     }
617     else
618     {
619 
620 #ifdef TX_NOT_INTERRUPTABLE
621 
622         /* Perform any additional activities for tool or user purpose.  */
623         TX_THREAD_CREATE_EXTENSION(thread_ptr)
624 
625         /* Restore interrupts.  */
626         TX_RESTORE
627 #else
628 
629         /* Restore interrupts.  */
630         TX_RESTORE
631 
632         /* Perform any additional activities for tool or user purpose.  */
633         TX_THREAD_CREATE_EXTENSION(thread_ptr)
634 
635         /* Disable interrupts.  */
636         TX_DISABLE
637 
638         /* Re-enable preemption.  */
639         _tx_thread_preempt_disable--;
640 
641         /* Restore interrupts.  */
642         TX_RESTORE
643 
644         /* Check for preemption.  */
645         _tx_thread_system_preempt_check();
646 #endif
647     }
648 
649 #else /* TX_THREAD_SMP */
650 
651 #ifndef TX_NOT_INTERRUPTABLE
652 
653     /* Temporarily disable preemption.  */
654     _tx_thread_preempt_disable++;
655 #endif
656 
657     /* Determine if an automatic start was requested.  If so, call the resume
658        thread function and then check for a preemption condition.  */
659     if (auto_start == TX_AUTO_START)
660     {
661 
662         /* Determine if the create call is being called from initialization.  */
663         if (TX_THREAD_GET_SYSTEM_STATE() >= TX_INITIALIZE_IN_PROGRESS)
664         {
665 
666             /* Yes, this create call was made from initialization.  */
667 
668             /* Pickup the current thread execute pointer, which corresponds to the
669                highest priority thread ready to execute.  Interrupt lockout is
670                not required, since interrupts are assumed to be disabled during
671                initialization.  */
672             saved_thread_ptr =  _tx_thread_execute_ptr;
673 
674             /* Determine if there is thread ready for execution.  */
675             if (saved_thread_ptr != TX_NULL)
676             {
677 
678                 /* Yes, a thread is ready for execution when initialization completes.  */
679 
680                 /* Save the current preemption-threshold.  */
681                 saved_threshold =  saved_thread_ptr -> tx_thread_preempt_threshold;
682 
683                 /* For initialization, temporarily set the preemption-threshold to the
684                    priority level to make sure the highest-priority thread runs once
685                    initialization is complete.  */
686                 saved_thread_ptr -> tx_thread_preempt_threshold =  saved_thread_ptr -> tx_thread_priority;
687             }
688         }
689         else
690         {
691 
692             /* Simply set the saved thread pointer to NULL.  */
693             saved_thread_ptr =  TX_NULL;
694         }
695 
696 #ifdef TX_NOT_INTERRUPTABLE
697 
698         /* Perform any additional activities for tool or user purpose.  */
699         TX_THREAD_CREATE_EXTENSION(thread_ptr)
700 
701         /* Resume the thread!  */
702         _tx_thread_system_ni_resume(thread_ptr);
703 
704         /* Restore previous interrupt posture.  */
705         TX_RESTORE
706 #else
707 
708         /* Restore previous interrupt posture.  */
709         TX_RESTORE
710 
711         /* Perform any additional activities for tool or user purpose.  */
712         TX_THREAD_CREATE_EXTENSION(thread_ptr)
713 
714         /* Call the resume thread function to make this thread ready.  */
715         _tx_thread_system_resume(thread_ptr);
716 #endif
717 
718         /* Determine if the thread's preemption-threshold needs to be restored.  */
719         if (saved_thread_ptr != TX_NULL)
720         {
721 
722             /* Yes, restore the previous highest-priority thread's preemption-threshold. This
723                can only happen if this routine is called from initialization.  */
724             saved_thread_ptr -> tx_thread_preempt_threshold =  saved_threshold;
725         }
726     }
727     else
728     {
729 
730 #ifdef TX_NOT_INTERRUPTABLE
731 
732         /* Perform any additional activities for tool or user purpose.  */
733         TX_THREAD_CREATE_EXTENSION(thread_ptr)
734 
735         /* Restore interrupts.  */
736         TX_RESTORE
737 #else
738 
739         /* Restore interrupts.  */
740         TX_RESTORE
741 
742         /* Perform any additional activities for tool or user purpose.  */
743         TX_THREAD_CREATE_EXTENSION(thread_ptr)
744 
745         /* Disable interrupts.  */
746         TX_DISABLE
747 
748         /* Re-enable preemption.  */
749         _tx_thread_preempt_disable--;
750 
751         /* Restore interrupts.  */
752         TX_RESTORE
753 
754         /* Check for preemption.  */
755         _tx_thread_system_preempt_check();
756 #endif
757     }
758 
759 #endif /* TX_THREAD_SMP */
760 
761     /* Return success.  */
762     return(TX_SUCCESS);
763 }
764 
765