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 /** Thread */
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
33
34 /**************************************************************************/
35 /* */
36 /* FUNCTION RELEASE */
37 /* */
38 /* _tx_thread_create PORTABLE SMP */
39 /* 6.3.0 */
40 /* AUTHOR */
41 /* */
42 /* William E. Lamie, Microsoft Corporation */
43 /* */
44 /* DESCRIPTION */
45 /* */
46 /* This function creates a thread and places it on the list of created */
47 /* threads. */
48 /* */
49 /* INPUT */
50 /* */
51 /* thread_ptr Thread control block pointer */
52 /* name_ptr Pointer to thread name string */
53 /* entry_function Entry function of the thread */
54 /* entry_input 32-bit input value to thread */
55 /* stack_start Pointer to start of stack */
56 /* stack_size Stack size in bytes */
57 /* priority Priority of thread (0-31) */
58 /* preempt_threshold Preemption threshold */
59 /* time_slice Thread time-slice value */
60 /* auto_start Automatic start selection */
61 /* */
62 /* OUTPUT */
63 /* */
64 /* return status Thread create return status */
65 /* */
66 /* CALLS */
67 /* */
68 /* _tx_thread_smp_rebalance_execute_list Rebalance execution list */
69 /* _tx_thread_stack_build Build initial thread stack */
70 /* _tx_thread_system_resume Resume automatic start thread */
71 /* _tx_thread_system_ni_resume Noninterruptable resume thread*/
72 /* */
73 /* CALLED BY */
74 /* */
75 /* Application Code */
76 /* _tx_timer_initialize Create system timer thread */
77 /* */
78 /* RELEASE HISTORY */
79 /* */
80 /* DATE NAME DESCRIPTION */
81 /* */
82 /* 09-30-2020 William E. Lamie Initial Version 6.1 */
83 /* 12-31-2020 Andres Mlinar Modified comment(s), */
84 /* resulting in version 6.1.3 */
85 /* 08-02-2021 Scott Larson Removed unneeded cast, */
86 /* resulting in version 6.1.8 */
87 /* 10-31-2022 Scott Larson Removed ifdef block to always */
88 /* restore interrupts at end */
89 /* of if block, */
90 /* resulting in version 6.2.0 */
91 /* 10-31-2023 Xiuwen Cai Modified comment(s), */
92 /* added option for random */
93 /* number stack filling, */
94 /* resulting in version 6.3.0 */
95 /* */
96 /**************************************************************************/
_tx_thread_create(TX_THREAD * thread_ptr,CHAR * name_ptr,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)97 UINT _tx_thread_create(TX_THREAD *thread_ptr, CHAR *name_ptr,
98 VOID (*entry_function)(ULONG id), ULONG entry_input,
99 VOID *stack_start, ULONG stack_size, UINT priority, UINT preempt_threshold,
100 ULONG time_slice, UINT auto_start)
101 {
102
103 TX_INTERRUPT_SAVE_AREA
104
105 UINT core_index;
106 TX_THREAD *next_thread;
107 TX_THREAD *previous_thread;
108 UCHAR *temp_ptr;
109 #ifdef TX_ENABLE_STACK_CHECKING
110 ALIGN_TYPE new_stack_start;
111 ALIGN_TYPE updated_stack_start;
112 #endif
113
114
115 #ifndef TX_DISABLE_STACK_FILLING
116 #if defined(TX_ENABLE_RANDOM_NUMBER_STACK_FILLING) && defined(TX_ENABLE_STACK_CHECKING)
117
118 /* Initialize the stack fill value to a 8-bit random value. */
119 thread_ptr -> tx_thread_stack_fill_value = ((ULONG) TX_RAND()) & 0xFFUL;
120
121 /* Duplicate the random value in each of the 4 bytes of the stack fill value. */
122 thread_ptr -> tx_thread_stack_fill_value = thread_ptr -> tx_thread_stack_fill_value |
123 (thread_ptr -> tx_thread_stack_fill_value << 8) |
124 (thread_ptr -> tx_thread_stack_fill_value << 16) |
125 (thread_ptr -> tx_thread_stack_fill_value << 24);
126 #endif
127
128 /* Set the thread stack to a pattern prior to creating the initial
129 stack frame. This pattern is used by the stack checking routines
130 to see how much has been used. */
131 TX_MEMSET(stack_start, ((UCHAR) TX_STACK_FILL), stack_size);
132 #endif
133
134 #ifdef TX_ENABLE_STACK_CHECKING
135
136 /* Ensure that there are two ULONG of 0xEF patterns at the top and
137 bottom of the thread's stack. This will be used to check for stack
138 overflow conditions during run-time. */
139 stack_size = ((stack_size/(sizeof(ULONG))) * (sizeof(ULONG))) - (sizeof(ULONG));
140
141 /* Ensure the starting stack address is evenly aligned. */
142 new_stack_start = TX_POINTER_TO_ALIGN_TYPE_CONVERT(stack_start);
143 updated_stack_start = (((new_stack_start) + ((sizeof(ULONG)) - ((ULONG) 1)) ) & (~((sizeof(ULONG)) - ((ULONG) 1))));
144
145 /* Determine if the starting stack address is different. */
146 if (new_stack_start != updated_stack_start)
147 {
148
149 /* Yes, subtract another ULONG from the size to avoid going past the stack area. */
150 stack_size = stack_size - (sizeof(ULONG));
151 }
152
153 /* Update the starting stack pointer. */
154 stack_start = TX_ALIGN_TYPE_TO_POINTER_CONVERT(updated_stack_start);
155 #endif
156
157 /* Prepare the thread control block prior to placing it on the created
158 list. */
159
160 /* Initialize thread control block to all zeros. */
161 TX_MEMSET(thread_ptr, 0, sizeof(TX_THREAD));
162
163 /* Place the supplied parameters into the thread's control block. */
164 thread_ptr -> tx_thread_name = name_ptr;
165 thread_ptr -> tx_thread_entry = entry_function;
166 thread_ptr -> tx_thread_entry_parameter = entry_input;
167 thread_ptr -> tx_thread_stack_start = stack_start;
168 thread_ptr -> tx_thread_stack_size = stack_size;
169 thread_ptr -> tx_thread_priority = priority;
170 thread_ptr -> tx_thread_user_priority = priority;
171 thread_ptr -> tx_thread_time_slice = time_slice;
172 thread_ptr -> tx_thread_new_time_slice = time_slice;
173 thread_ptr -> tx_thread_inherit_priority = ((UINT) TX_MAX_PRIORITIES);
174 thread_ptr -> tx_thread_smp_core_executing = ((UINT) TX_THREAD_SMP_MAX_CORES);
175 thread_ptr -> tx_thread_smp_cores_excluded = ((ULONG) 0);
176 #ifndef TX_THREAD_SMP_DYNAMIC_CORE_MAX
177 thread_ptr -> tx_thread_smp_cores_allowed = ((ULONG) TX_THREAD_SMP_CORE_MASK);
178 #else
179 thread_ptr -> tx_thread_smp_cores_allowed = (((ULONG) 1) << _tx_thread_smp_max_cores) - 1;
180 #endif
181
182 #ifdef TX_THREAD_SMP_ONLY_CORE_0_DEFAULT
183
184 /* Default thread creation such that core0 is the only allowed core for execution, i.e., bit 1 is set to exclude core1. */
185 thread_ptr -> tx_thread_smp_cores_excluded = (TX_THREAD_SMP_CORE_MASK & 0xFFFFFFFE);
186 thread_ptr -> tx_thread_smp_cores_allowed = 1;
187
188 /* Default the timers to run on core 0 as well. */
189 thread_ptr -> tx_thread_timer.tx_timer_internal_smp_cores_excluded = (TX_THREAD_SMP_CORE_MASK & 0xFFFFFFFE);
190
191 /* Default the mapped to 0 too. */
192 thread_ptr -> tx_thread_smp_core_mapped = 0;
193 #endif
194
195 /* Calculate the end of the thread's stack area. */
196 temp_ptr = TX_VOID_TO_UCHAR_POINTER_CONVERT(stack_start);
197 temp_ptr = (TX_UCHAR_POINTER_ADD(temp_ptr, (stack_size - ((ULONG) 1))));
198 thread_ptr -> tx_thread_stack_end = TX_UCHAR_TO_VOID_POINTER_CONVERT(temp_ptr);
199
200
201 #ifndef TX_DISABLE_PREEMPTION_THRESHOLD
202
203 /* Preemption-threshold is enabled, setup accordingly. */
204 thread_ptr -> tx_thread_preempt_threshold = preempt_threshold;
205 thread_ptr -> tx_thread_user_preempt_threshold = preempt_threshold;
206 #else
207
208 /* Preemption-threshold is disabled, determine if preemption-threshold was required. */
209 if (priority != preempt_threshold)
210 {
211
212 /* Preemption-threshold specified. Since specific preemption-threshold is not supported,
213 disable all preemption. */
214 thread_ptr -> tx_thread_preempt_threshold = ((UINT) 0);
215 thread_ptr -> tx_thread_user_preempt_threshold = ((UINT) 0);
216 }
217 else
218 {
219
220 /* Preemption-threshold is not specified, just setup with the priority. */
221 thread_ptr -> tx_thread_preempt_threshold = priority;
222 thread_ptr -> tx_thread_user_preempt_threshold = priority;
223 }
224 #endif
225
226 /* Now fill in the values that are required for thread initialization. */
227 thread_ptr -> tx_thread_state = TX_SUSPENDED;
228
229 /* Setup the necessary fields in the thread timer block. */
230 TX_THREAD_CREATE_TIMEOUT_SETUP(thread_ptr)
231
232 /* Perform any additional thread setup activities for tool or user purpose. */
233 TX_THREAD_CREATE_INTERNAL_EXTENSION(thread_ptr)
234
235 /* Call the target specific stack frame building routine to build the
236 thread's initial stack and to setup the actual stack pointer in the
237 control block. */
238 _tx_thread_stack_build(thread_ptr, _tx_thread_shell_entry);
239
240 #ifdef TX_ENABLE_STACK_CHECKING
241
242 /* Setup the highest usage stack pointer. */
243 thread_ptr -> tx_thread_stack_highest_ptr = thread_ptr -> tx_thread_stack_ptr;
244 #endif
245
246 /* Prepare to make this thread a member of the created thread list. */
247 TX_DISABLE
248
249 /* Load the thread ID field in the thread control block. */
250 thread_ptr -> tx_thread_id = TX_THREAD_ID;
251
252 /* Place the thread on the list of created threads. First,
253 check for an empty list. */
254 if (_tx_thread_created_count == TX_EMPTY)
255 {
256
257 /* The created thread list is empty. Add thread to empty list. */
258 _tx_thread_created_ptr = thread_ptr;
259 thread_ptr -> tx_thread_created_next = thread_ptr;
260 thread_ptr -> tx_thread_created_previous = thread_ptr;
261 }
262 else
263 {
264
265 /* This list is not NULL, add to the end of the list. */
266 next_thread = _tx_thread_created_ptr;
267 previous_thread = next_thread -> tx_thread_created_previous;
268
269 /* Place the new thread in the list. */
270 next_thread -> tx_thread_created_previous = thread_ptr;
271 previous_thread -> tx_thread_created_next = thread_ptr;
272
273 /* Setup this thread's created links. */
274 thread_ptr -> tx_thread_created_previous = previous_thread;
275 thread_ptr -> tx_thread_created_next = next_thread;
276 }
277
278 /* Increment the thread created count. */
279 _tx_thread_created_count++;
280
281 /* If trace is enabled, register this object. */
282 TX_TRACE_OBJECT_REGISTER(TX_TRACE_OBJECT_TYPE_THREAD, thread_ptr, name_ptr, TX_POINTER_TO_ULONG_CONVERT(stack_start), stack_size)
283
284 /* If trace is enabled, insert this event into the trace buffer. */
285 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)
286
287 /* Register thread in the thread array structure. */
288 TX_EL_THREAD_REGISTER(thread_ptr)
289
290 /* Log this kernel call. */
291 TX_EL_THREAD_CREATE_INSERT
292
293 #ifndef TX_NOT_INTERRUPTABLE
294
295 /* Temporarily disable preemption. */
296 _tx_thread_preempt_disable++;
297 #endif
298
299 /* Determine if an automatic start was requested. If so, call the resume
300 thread function and then check for a preemption condition. */
301 if (auto_start == TX_AUTO_START)
302 {
303
304 #ifdef TX_NOT_INTERRUPTABLE
305
306 /* Perform any additional activities for tool or user purpose. */
307 TX_THREAD_CREATE_EXTENSION(thread_ptr)
308
309 /* Resume the thread! */
310 _tx_thread_system_ni_resume(thread_ptr);
311
312 #else
313
314 /* Restore previous interrupt posture. */
315 TX_RESTORE
316
317 /* Perform any additional activities for tool or user purpose. */
318 TX_THREAD_CREATE_EXTENSION(thread_ptr)
319
320 /* Call the resume thread function to make this thread ready. */
321 _tx_thread_system_resume(thread_ptr);
322
323 /* Disable interrupts again. */
324 TX_DISABLE
325 #endif
326
327 /* Determine if the execution list needs to be re-evaluated. */
328 if (_tx_thread_smp_current_state_get() >= TX_INITIALIZE_IN_PROGRESS)
329 {
330
331 #ifndef TX_DISABLE_PREEMPTION_THRESHOLD
332
333 /* Clear the preemption bit maps, since nothing has yet run during initialization. */
334 TX_MEMSET(_tx_thread_preempted_maps, 0, sizeof(_tx_thread_preempted_maps));
335 #if TX_MAX_PRIORITIES > 32
336 _tx_thread_preempted_map_active = ((ULONG) 0);
337 #endif
338
339 /* Clear the entry in the preempted thread list. */
340 _tx_thread_preemption_threshold_list[priority] = TX_NULL;
341 #endif
342
343 /* Set the pointer to the thread currently with preemption-threshold set to NULL. */
344 _tx_thread_preemption__threshold_scheduled = TX_NULL;
345
346 #ifdef TX_THREAD_SMP_DEBUG_ENABLE
347
348 /* Debug entry. */
349 _tx_thread_smp_debug_entry_insert(12, 0, thread_ptr);
350 #endif
351
352 /* Get the core index. */
353 core_index = TX_SMP_CORE_ID;
354
355 /* Call the rebalance routine. This routine maps cores and ready threads. */
356 _tx_thread_smp_rebalance_execute_list(core_index);
357
358 #ifdef TX_THREAD_SMP_DEBUG_ENABLE
359
360 /* Debug entry. */
361 _tx_thread_smp_debug_entry_insert(13, 0, thread_ptr);
362 #endif
363 }
364
365 /* Restore interrupts. */
366 TX_RESTORE
367 }
368 else
369 {
370
371 #ifdef TX_NOT_INTERRUPTABLE
372
373 /* Perform any additional activities for tool or user purpose. */
374 TX_THREAD_CREATE_EXTENSION(thread_ptr)
375
376 /* Restore interrupts. */
377 TX_RESTORE
378 #else
379
380 /* Restore interrupts. */
381 TX_RESTORE
382
383 /* Perform any additional activities for tool or user purpose. */
384 TX_THREAD_CREATE_EXTENSION(thread_ptr)
385
386 /* Disable interrupts. */
387 TX_DISABLE
388
389 /* Re-enable preemption. */
390 _tx_thread_preempt_disable--;
391
392 /* Restore interrupts. */
393 TX_RESTORE
394
395 /* Check for preemption. */
396 _tx_thread_system_preempt_check();
397 #endif
398 }
399
400 /* Return success. */
401 return(TX_SUCCESS);
402 }
403
404