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