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