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