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