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_initialize.h"
29 #include "tx_thread.h"
30 #include "tx_timer.h"
31
32
33 /**************************************************************************/
34 /* */
35 /* FUNCTION RELEASE */
36 /* */
37 /* _txe_thread_create PORTABLE C */
38 /* 6.1 */
39 /* AUTHOR */
40 /* */
41 /* William E. Lamie, Microsoft Corporation */
42 /* */
43 /* DESCRIPTION */
44 /* */
45 /* This function checks for errors in the thread create function call. */
46 /* */
47 /* INPUT */
48 /* */
49 /* thread_ptr Thread control block pointer */
50 /* name Pointer to thread name string */
51 /* entry_function Entry function of the thread */
52 /* entry_input 32-bit input value to thread */
53 /* stack_start Pointer to start of stack */
54 /* stack_size Stack size in bytes */
55 /* priority Priority of thread (0-31) */
56 /* preempt_threshold Preemption threshold */
57 /* time_slice Thread time-slice value */
58 /* auto_start Automatic start selection */
59 /* thread_control_block_size Size of thread control block */
60 /* */
61 /* OUTPUT */
62 /* */
63 /* TX_THREAD_ERROR Invalid thread pointer */
64 /* TX_PTR_ERROR Invalid entry point or stack */
65 /* address */
66 /* TX_SIZE_ERROR Invalid stack size -too small */
67 /* TX_PRIORITY_ERROR Invalid thread priority */
68 /* TX_THRESH_ERROR Invalid preemption threshold */
69 /* status Actual completion status */
70 /* */
71 /* CALLS */
72 /* */
73 /* _tx_thread_create Actual thread create function */
74 /* _tx_thread_system_preempt_check Check for preemption */
75 /* */
76 /* CALLED BY */
77 /* */
78 /* Application Code */
79 /* */
80 /* RELEASE HISTORY */
81 /* */
82 /* DATE NAME DESCRIPTION */
83 /* */
84 /* 05-19-2020 William E. Lamie Initial Version 6.0 */
85 /* 09-30-2020 Yuxin Zhou Modified comment(s), */
86 /* resulting in version 6.1 */
87 /* */
88 /**************************************************************************/
_txe_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,UINT thread_control_block_size)89 UINT _txe_thread_create(TX_THREAD *thread_ptr, CHAR *name_ptr,
90 VOID (*entry_function)(ULONG id), ULONG entry_input,
91 VOID *stack_start, ULONG stack_size,
92 UINT priority, UINT preempt_threshold,
93 ULONG time_slice, UINT auto_start, UINT thread_control_block_size)
94 {
95
96 TX_INTERRUPT_SAVE_AREA
97
98 UINT status;
99 UINT break_flag;
100 ULONG i;
101 TX_THREAD *next_thread;
102 VOID *stack_end;
103 UCHAR *work_ptr;
104 #ifndef TX_TIMER_PROCESS_IN_ISR
105 TX_THREAD *current_thread;
106 #endif
107
108
109 /* Default status to success. */
110 status = TX_SUCCESS;
111
112 /* Check for an invalid thread pointer. */
113 if (thread_ptr == TX_NULL)
114 {
115
116 /* Thread pointer is invalid, return appropriate error code. */
117 status = TX_THREAD_ERROR;
118 }
119
120 /* Now check for invalid thread control block size. */
121 else if (thread_control_block_size != (sizeof(TX_THREAD)))
122 {
123
124 /* Thread pointer is invalid, return appropriate error code. */
125 status = TX_THREAD_ERROR;
126 }
127 else
128 {
129
130 /* Disable interrupts. */
131 TX_DISABLE
132
133 /* Increment the preempt disable flag. */
134 _tx_thread_preempt_disable++;
135
136 /* Restore interrupts. */
137 TX_RESTORE
138
139 /* Next see if it is already in the created list. */
140 break_flag = TX_FALSE;
141 next_thread = _tx_thread_created_ptr;
142 work_ptr = TX_VOID_TO_UCHAR_POINTER_CONVERT(stack_start);
143 work_ptr = TX_UCHAR_POINTER_ADD(work_ptr, (stack_size - ((ULONG) 1)));
144 stack_end = TX_UCHAR_TO_VOID_POINTER_CONVERT(work_ptr);
145 for (i = ((ULONG) 0); i < _tx_thread_created_count; i++)
146 {
147
148 /* Determine if this thread matches the thread in the list. */
149 if (thread_ptr == next_thread)
150 {
151
152 /* Set the break flag. */
153 break_flag = TX_TRUE;
154 }
155
156 /* Determine if we need to break the loop. */
157 if (break_flag == TX_TRUE)
158 {
159
160 /* Yes, break out of the loop. */
161 break;
162 }
163
164 /* Check the stack pointer to see if it overlaps with this thread's stack. */
165 if (stack_start >= next_thread -> tx_thread_stack_start)
166 {
167
168 if (stack_start < next_thread -> tx_thread_stack_end)
169 {
170
171 /* This stack overlaps with an existing thread, clear the stack pointer to
172 force a stack error below. */
173 stack_start = TX_NULL;
174
175 /* Set the break flag. */
176 break_flag = TX_TRUE;
177 }
178 }
179
180 /* Check the end of the stack to see if it is inside this thread's stack area as well. */
181 if (stack_end >= next_thread -> tx_thread_stack_start)
182 {
183
184 if (stack_end < next_thread -> tx_thread_stack_end)
185 {
186
187 /* This stack overlaps with an existing thread, clear the stack pointer to
188 force a stack error below. */
189 stack_start = TX_NULL;
190
191 /* Set the break flag. */
192 break_flag = TX_TRUE;
193 }
194 }
195
196 /* Move to the next thread. */
197 next_thread = next_thread -> tx_thread_created_next;
198 }
199
200 /* Disable interrupts. */
201 TX_DISABLE
202
203 /* Decrement the preempt disable flag. */
204 _tx_thread_preempt_disable--;
205
206 /* Restore interrupts. */
207 TX_RESTORE
208
209 /* Check for preemption. */
210 _tx_thread_system_preempt_check();
211
212 /* At this point, check to see if there is a duplicate thread. */
213 if (thread_ptr == next_thread)
214 {
215
216 /* Thread is already created, return appropriate error code. */
217 status = TX_THREAD_ERROR;
218 }
219
220 /* Check for invalid starting address of stack. */
221 else if (stack_start == TX_NULL)
222 {
223
224 /* Invalid stack or entry point, return appropriate error code. */
225 status = TX_PTR_ERROR;
226 }
227
228 /* Check for invalid thread entry point. */
229 else if (entry_function == TX_NULL)
230 {
231
232 /* Invalid stack or entry point, return appropriate error code. */
233 status = TX_PTR_ERROR;
234 }
235
236 /* Check the stack size. */
237 else if (stack_size < ((ULONG) TX_MINIMUM_STACK))
238 {
239
240 /* Stack is not big enough, return appropriate error code. */
241 status = TX_SIZE_ERROR;
242 }
243
244 /* Check the priority specified. */
245 else if (priority >= ((UINT) TX_MAX_PRIORITIES))
246 {
247
248 /* Invalid priority selected, return appropriate error code. */
249 status = TX_PRIORITY_ERROR;
250 }
251
252 /* Check preemption threshold. */
253 else if (preempt_threshold > priority)
254 {
255
256 /* Invalid preempt threshold, return appropriate error code. */
257 status = TX_THRESH_ERROR;
258 }
259
260 /* Check the start selection. */
261 else if (auto_start > TX_AUTO_START)
262 {
263
264 /* Invalid auto start selection, return appropriate error code. */
265 status = TX_START_ERROR;
266 }
267 else
268 {
269
270 #ifndef TX_TIMER_PROCESS_IN_ISR
271
272 /* Pickup thread pointer. */
273 TX_THREAD_GET_CURRENT(current_thread)
274
275 /* Check for invalid caller of this function. First check for a calling thread. */
276 if (current_thread == &_tx_timer_thread)
277 {
278
279 /* Invalid caller of this function, return appropriate error code. */
280 status = TX_CALLER_ERROR;
281 }
282 #endif
283
284 /* Check for interrupt call. */
285 if (TX_THREAD_GET_SYSTEM_STATE() != ((ULONG) 0))
286 {
287
288 /* Now, make sure the call is from an interrupt and not initialization. */
289 if (TX_THREAD_GET_SYSTEM_STATE() < TX_INITIALIZE_IN_PROGRESS)
290 {
291
292 /* Invalid caller of this function, return appropriate error code. */
293 status = TX_CALLER_ERROR;
294 }
295 }
296 }
297 }
298
299 /* Determine if everything is okay. */
300 if (status == TX_SUCCESS)
301 {
302
303 /* Call actual thread create function. */
304 status = _tx_thread_create(thread_ptr, name_ptr, entry_function, entry_input,
305 stack_start, stack_size, priority, preempt_threshold,
306 time_slice, auto_start);
307 }
308
309 /* Return completion status. */
310 return(status);
311 }
312
313