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