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