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