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