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
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 C */
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 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 */
58 /* (default 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_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 /* 05-19-2020 William E. Lamie Initial Version 6.0 */
83 /* 09-30-2020 William E. Lamie Modified comment(s), and */
84 /* changed stack calculations */
85 /* to use ALIGN_TYPE integers, */
86 /* resulting in version 6.1 */
87 /* 06-02-2021 William E. Lamie Modified comment(s), and */
88 /* supported TX_MISRA_ENABLE, */
89 /* 08-02-2021 Scott Larson Removed unneeded cast, */
90 /* resulting in version 6.1.8 */
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, VOID (*entry_function)(ULONG id), ULONG entry_input,
98 VOID *stack_start, ULONG stack_size, UINT priority, UINT preempt_threshold,
99 ULONG time_slice, UINT auto_start)
100 {
101
102 TX_INTERRUPT_SAVE_AREA
103
104 TX_THREAD *next_thread;
105 TX_THREAD *previous_thread;
106 TX_THREAD *saved_thread_ptr;
107 UINT saved_threshold = ((UINT) 0);
108 UCHAR *temp_ptr;
109
110 #ifdef TX_ENABLE_STACK_CHECKING
111 ALIGN_TYPE new_stack_start;
112 ALIGN_TYPE updated_stack_start;
113 #endif
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 #ifdef TX_MISRA_ENABLE
143 new_stack_start = TX_POINTER_TO_ULONG_CONVERT(stack_start);
144 #else
145 new_stack_start = TX_POINTER_TO_ALIGN_TYPE_CONVERT(stack_start);
146 #endif /* TX_MISRA_ENABLE */
147 updated_stack_start = (((new_stack_start) + ((sizeof(ULONG)) - ((ULONG) 1)) ) & (~((sizeof(ULONG)) - ((ULONG) 1))));
148
149 /* Determine if the starting stack address is different. */
150 if (new_stack_start != updated_stack_start)
151 {
152
153 /* Yes, subtract another ULONG from the size to avoid going past the stack area. */
154 stack_size = stack_size - (sizeof(ULONG));
155 }
156
157 /* Update the starting stack pointer. */
158 #ifdef TX_MISRA_ENABLE
159 stack_start = TX_ULONG_TO_POINTER_CONVERT(updated_stack_start);
160 #else
161 stack_start = TX_ALIGN_TYPE_TO_POINTER_CONVERT(updated_stack_start);
162 #endif /* TX_MISRA_ENABLE */
163 #endif
164
165 /* Prepare the thread control block prior to placing it on the created
166 list. */
167
168 /* Initialize thread control block to all zeros. */
169 TX_MEMSET(thread_ptr, 0, (sizeof(TX_THREAD)));
170
171 /* Place the supplied parameters into the thread's control block. */
172 thread_ptr -> tx_thread_name = name_ptr;
173 thread_ptr -> tx_thread_entry = entry_function;
174 thread_ptr -> tx_thread_entry_parameter = entry_input;
175 thread_ptr -> tx_thread_stack_start = stack_start;
176 thread_ptr -> tx_thread_stack_size = stack_size;
177 thread_ptr -> tx_thread_priority = priority;
178 thread_ptr -> tx_thread_user_priority = priority;
179 thread_ptr -> tx_thread_time_slice = time_slice;
180 thread_ptr -> tx_thread_new_time_slice = time_slice;
181 thread_ptr -> tx_thread_inherit_priority = ((UINT) TX_MAX_PRIORITIES);
182
183 /* Calculate the end of the thread's stack area. */
184 temp_ptr = TX_VOID_TO_UCHAR_POINTER_CONVERT(stack_start);
185 temp_ptr = (TX_UCHAR_POINTER_ADD(temp_ptr, (stack_size - ((ULONG) 1))));
186 thread_ptr -> tx_thread_stack_end = TX_UCHAR_TO_VOID_POINTER_CONVERT(temp_ptr);
187
188 #ifndef TX_DISABLE_PREEMPTION_THRESHOLD
189
190 /* Preemption-threshold is enabled, setup accordingly. */
191 thread_ptr -> tx_thread_preempt_threshold = preempt_threshold;
192 thread_ptr -> tx_thread_user_preempt_threshold = preempt_threshold;
193 #else
194
195 /* Preemption-threshold is disabled, determine if preemption-threshold was required. */
196 if (priority != preempt_threshold)
197 {
198
199 /* Preemption-threshold specified. Since specific preemption-threshold is not supported,
200 disable all preemption. */
201 thread_ptr -> tx_thread_preempt_threshold = ((UINT) 0);
202 thread_ptr -> tx_thread_user_preempt_threshold = ((UINT) 0);
203 }
204 else
205 {
206
207 /* Preemption-threshold is not specified, just setup with the priority. */
208 thread_ptr -> tx_thread_preempt_threshold = priority;
209 thread_ptr -> tx_thread_user_preempt_threshold = priority;
210 }
211 #endif
212
213 /* Now fill in the values that are required for thread initialization. */
214 thread_ptr -> tx_thread_state = TX_SUSPENDED;
215
216 /* Setup the necessary fields in the thread timer block. */
217 TX_THREAD_CREATE_TIMEOUT_SETUP(thread_ptr)
218
219 /* Perform any additional thread setup activities for tool or user purpose. */
220 TX_THREAD_CREATE_INTERNAL_EXTENSION(thread_ptr)
221
222 /* Call the target specific stack frame building routine to build the
223 thread's initial stack and to setup the actual stack pointer in the
224 control block. */
225 _tx_thread_stack_build(thread_ptr, _tx_thread_shell_entry);
226
227 #ifdef TX_ENABLE_STACK_CHECKING
228
229 /* Setup the highest usage stack pointer. */
230 thread_ptr -> tx_thread_stack_highest_ptr = thread_ptr -> tx_thread_stack_ptr;
231 #endif
232
233 /* Prepare to make this thread a member of the created thread list. */
234 TX_DISABLE
235
236 /* Load the thread ID field in the thread control block. */
237 thread_ptr -> tx_thread_id = TX_THREAD_ID;
238
239 /* Place the thread on the list of created threads. First,
240 check for an empty list. */
241 if (_tx_thread_created_count == TX_EMPTY)
242 {
243
244 /* The created thread list is empty. Add thread to empty list. */
245 _tx_thread_created_ptr = thread_ptr;
246 thread_ptr -> tx_thread_created_next = thread_ptr;
247 thread_ptr -> tx_thread_created_previous = thread_ptr;
248 }
249 else
250 {
251
252 /* This list is not NULL, add to the end of the list. */
253 next_thread = _tx_thread_created_ptr;
254 previous_thread = next_thread -> tx_thread_created_previous;
255
256 /* Place the new thread in the list. */
257 next_thread -> tx_thread_created_previous = thread_ptr;
258 previous_thread -> tx_thread_created_next = thread_ptr;
259
260 /* Setup this thread's created links. */
261 thread_ptr -> tx_thread_created_previous = previous_thread;
262 thread_ptr -> tx_thread_created_next = next_thread;
263 }
264
265 /* Increment the thread created count. */
266 _tx_thread_created_count++;
267
268 /* If trace is enabled, register this object. */
269 TX_TRACE_OBJECT_REGISTER(TX_TRACE_OBJECT_TYPE_THREAD, thread_ptr, name_ptr, TX_POINTER_TO_ULONG_CONVERT(stack_start), stack_size)
270
271 /* If trace is enabled, insert this event into the trace buffer. */
272 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)
273
274 /* Register thread in the thread array structure. */
275 TX_EL_THREAD_REGISTER(thread_ptr)
276
277 /* Log this kernel call. */
278 TX_EL_THREAD_CREATE_INSERT
279
280 #ifndef TX_NOT_INTERRUPTABLE
281
282 /* Temporarily disable preemption. */
283 _tx_thread_preempt_disable++;
284 #endif
285
286 /* Determine if an automatic start was requested. If so, call the resume
287 thread function and then check for a preemption condition. */
288 if (auto_start == TX_AUTO_START)
289 {
290
291 /* Determine if the create call is being called from initialization. */
292 if (TX_THREAD_GET_SYSTEM_STATE() >= TX_INITIALIZE_IN_PROGRESS)
293 {
294
295 /* Yes, this create call was made from initialization. */
296
297 /* Pickup the current thread execute pointer, which corresponds to the
298 highest priority thread ready to execute. Interrupt lockout is
299 not required, since interrupts are assumed to be disabled during
300 initialization. */
301 saved_thread_ptr = _tx_thread_execute_ptr;
302
303 /* Determine if there is thread ready for execution. */
304 if (saved_thread_ptr != TX_NULL)
305 {
306
307 /* Yes, a thread is ready for execution when initialization completes. */
308
309 /* Save the current preemption-threshold. */
310 saved_threshold = saved_thread_ptr -> tx_thread_preempt_threshold;
311
312 /* For initialization, temporarily set the preemption-threshold to the
313 priority level to make sure the highest-priority thread runs once
314 initialization is complete. */
315 saved_thread_ptr -> tx_thread_preempt_threshold = saved_thread_ptr -> tx_thread_priority;
316 }
317 }
318 else
319 {
320
321 /* Simply set the saved thread pointer to NULL. */
322 saved_thread_ptr = TX_NULL;
323 }
324
325 #ifdef TX_NOT_INTERRUPTABLE
326
327 /* Perform any additional activities for tool or user purpose. */
328 TX_THREAD_CREATE_EXTENSION(thread_ptr)
329
330 /* Resume the thread! */
331 _tx_thread_system_ni_resume(thread_ptr);
332
333 /* Restore previous interrupt posture. */
334 TX_RESTORE
335 #else
336
337 /* Restore previous interrupt posture. */
338 TX_RESTORE
339
340 /* Perform any additional activities for tool or user purpose. */
341 TX_THREAD_CREATE_EXTENSION(thread_ptr)
342
343 /* Call the resume thread function to make this thread ready. */
344 _tx_thread_system_resume(thread_ptr);
345 #endif
346
347 /* Determine if the thread's preemption-threshold needs to be restored. */
348 if (saved_thread_ptr != TX_NULL)
349 {
350
351 /* Yes, restore the previous highest-priority thread's preemption-threshold. This
352 can only happen if this routine is called from initialization. */
353 saved_thread_ptr -> tx_thread_preempt_threshold = saved_threshold;
354 }
355 }
356 else
357 {
358
359 #ifdef TX_NOT_INTERRUPTABLE
360
361 /* Perform any additional activities for tool or user purpose. */
362 TX_THREAD_CREATE_EXTENSION(thread_ptr)
363
364 /* Restore interrupts. */
365 TX_RESTORE
366 #else
367
368 /* Restore interrupts. */
369 TX_RESTORE
370
371 /* Perform any additional activities for tool or user purpose. */
372 TX_THREAD_CREATE_EXTENSION(thread_ptr)
373
374 /* Disable interrupts. */
375 TX_DISABLE
376
377 /* Re-enable preemption. */
378 _tx_thread_preempt_disable--;
379
380 /* Restore interrupts. */
381 TX_RESTORE
382
383 /* Check for preemption. */
384 _tx_thread_system_preempt_check();
385 #endif
386 }
387
388 /* Always return a success. */
389 return(TX_SUCCESS);
390 }
391
392