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