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 /** POSIX wrapper for THREADX */
17 /** */
18 /** */
19 /** */
20 /**************************************************************************/
21 /**************************************************************************/
22
23 /* Include necessary system files. */
24
25 #include "tx_api.h" /* Threadx API */
26 #include "pthread.h" /* Posix API */
27 #include "px_int.h" /* Posix helper functions */
28
29
30 /**************************************************************************/
31 /* */
32 /* FUNCTION RELEASE */
33 /* */
34 /* pthread_create PORTABLE C */
35 /* 6.2.0 */
36 /* AUTHOR */
37 /* */
38 /* William E. Lamie, Microsoft Corporation */
39 /* */
40 /* DESCRIPTION */
41 /* */
42 /* This creates a new thread with attributes specified by attr within */
43 /* a process.If the attr is NULL,then default attributes are used. */
44 /* Upon successful completion, pthread_create() stores the ID of the */
45 /* created thread in the location referenced by thread. */
46 /* The thread is created executing start_routine with arg as its sole */
47 /* argument. */
48 /* Initially, threads are created from within a process. Once created, */
49 /* threads are peers, and may create other threads. Note that an */
50 /* "initial thread" exists by default which runs 'main' */
51 /* If pthread_create( ) fails,no new thread is created and the contents*/
52 /* of the location referenced by thread are undefined. */
53 /* */
54 /* INPUT */
55 /* */
56 /* thread place to store newly created thread ID */
57 /* Each thread in a process is uniquely */
58 /* identified during its lifetime by a */
59 /* value of type pthread_t called as */
60 /* thread ID. */
61 /* */
62 /* attr attributes object , NULL = Default attr.*/
63 /* start_routine thread start up routine */
64 /* arg arguments to start up routine by ref. */
65 /* */
66 /* OUTPUT */
67 /* */
68 /* zero If successful */
69 /* error number If fails */
70 /* pthread_create() function will fail if: */
71 /* [EAGAIN] system lacked the necessary */
72 /* resources to create a thread, */
73 /* or the system-imposed limit on */
74 /* the number of pthreads in */
75 /* a process PTHREAD_THREADS_MAX */
76 /* would be exceeded. */
77 /* [EINVAL] value specified by attr is */
78 /* invalid. */
79 /* [EPERM] The caller does not have */
80 /* appropriate permission to set */
81 /* the required scheduling */
82 /* parameters or scheduling policy*/
83 /* */
84 /* This call will not return an error code of [EINTR]*/
85 /* */
86 /* */
87 /* CALLS */
88 /* */
89 /* posix_in_thread_context To check calling context. */
90 /* posix_internal_error Internal error */
91 /* posix_allocate_pthread_t Allocate control block for pthread */
92 /* */
93 /* CALLED BY */
94 /* */
95 /* Application Code */
96 /* */
97 /* RELEASE HISTORY */
98 /* */
99 /* DATE NAME DESCRIPTION */
100 /* */
101 /* 06-02-2021 William E. Lamie Initial Version 6.1.7 */
102 /* 10-31-2022 Scott Larson Add 64-bit support, */
103 /* remove double parenthesis, */
104 /* resulting in version 6.2.0 */
105 /* */
106 /**************************************************************************/
pthread_create(pthread_t * thread,pthread_attr_t * attr,void * (* start_routine)(void *),void * arg)107 INT pthread_create (pthread_t *thread, pthread_attr_t *attr,
108 void *(*start_routine)(void*),void *arg)
109 {
110
111 TX_INTERRUPT_SAVE_AREA
112
113
114 TX_THREAD *thread_ptr;
115 POSIX_TCB *pthread_ptr, *current_thread_ptr;
116 INT status,retval;
117
118
119
120 /* Make sure we're calling this routine from a thread context. */
121 if (!posix_in_thread_context())
122 {
123 /* return POSIX error. */
124 posix_internal_error(444);
125 }
126
127 /* Disable interrupts. */
128
129
130 /* check for any pthread_t attr suggested */
131 if (!attr)
132 {
133 /* no attributes passed so assume default attributes */
134 attr = &(posix_default_pthread_attr);
135 }
136 else
137 {
138 /* Check attributes passed , check for validity */
139 if ( (attr->inuse) == TX_FALSE)
140 {
141 /* attributes passed are not valid, return with an error */
142 posix_errno = EINVAL;
143 posix_set_pthread_errno(EINVAL);
144 return(EINVAL);
145 }
146 }
147
148
149 /* Get a pthread control block for this new pthread */
150 TX_DISABLE
151 status = posix_allocate_pthread_t(&pthread_ptr);
152 TX_RESTORE
153 /* Make sure we got a Thread control block */
154 if ((status == ERROR) || (!pthread_ptr))
155 {
156 /* Configuration/resource error. */
157 return(EAGAIN);
158 }
159
160 if(attr->inherit_sched==PTHREAD_INHERIT_SCHED)
161 {
162 /* get current thread tcb */
163 current_thread_ptr=posix_tid2tcb(pthread_self());
164
165 /* copy scheduling attributes */
166 pthread_ptr->current_priority = current_thread_ptr->current_priority ;
167 pthread_ptr->detach_state = current_thread_ptr->detach_state ;
168 pthread_ptr->inherit_sched = current_thread_ptr->inherit_sched ;
169 pthread_ptr->orig_priority = current_thread_ptr->orig_priority ;
170 pthread_ptr->sched_attr.sched_priority= current_thread_ptr->sched_attr.sched_priority ;
171 pthread_ptr->pthread_flags = current_thread_ptr->pthread_flags ;
172 pthread_ptr->sched_policy = current_thread_ptr->sched_policy;
173 pthread_ptr->stack_size = current_thread_ptr->stack_size ;
174 pthread_ptr->stack_address = NULL; /* will allocate our own stack */
175 pthread_ptr->threshold = pthread_ptr->current_priority ; /* preemption threshold */
176 }
177 else /* assume PTHREAD_EXPLICIT_SCHED */
178 {
179
180 /* copy pthread-attr to TCB */
181 posix_copy_pthread_attr(pthread_ptr,attr);
182
183 /* preemption treshold */
184 pthread_ptr->threshold = pthread_ptr->current_priority ;
185 /* scheduling */
186 if(pthread_ptr->sched_policy==SCHED_RR) pthread_ptr->time_slice = SCHED_RR_TIME_SLICE;
187 else pthread_ptr->time_slice = 0;
188 }
189
190 /* Now set up pthread initial parameters */
191
192 pthread_ptr->entry_parameter = arg;
193 pthread_ptr->start_routine = start_routine;
194 /* Newly created pthread not joined by anybody! */
195 pthread_ptr->is_joined_by = TX_FALSE;
196 pthread_ptr->joined_by_pthreadID =TX_FALSE;
197 /* Newly created pthread not yet joined to any other pthread */
198 pthread_ptr->is_joined_to = TX_FALSE;
199 pthread_ptr->joined_to_pthreadID = TX_FALSE;
200
201
202 /* Allow cancel */
203 pthread_ptr->cancel_state = PTHREAD_CANCEL_ENABLE;
204 pthread_ptr->cancel_type = PTHREAD_CANCEL_DEFERRED;
205 pthread_ptr->cancel_request = FALSE;
206
207 pthread_ptr->value_ptr = NULL;
208
209
210 /* default stack allocation */
211 if((attr->stack_address)==NULL)
212 {
213 pthread_ptr->stack_size = attr->stack_size ;
214 status = posix_memory_allocate( pthread_ptr->stack_size, &(pthread_ptr->stack_address));
215
216 /* problem allocating stack space */
217 if (status == ERROR)
218 {
219 /* Configuration/resource error. */
220 return(EAGAIN);
221 }
222
223 }
224
225 /* Create an event flags group for sigwait. */
226 retval = tx_event_flags_create(&(pthread_ptr -> signals.signal_event_flags), "posix sigwait events");
227
228 /* Get the thread info from the TCB. */
229 thread_ptr = posix_tcb2thread(pthread_ptr);
230
231 /* Now actually create and start the thread. */
232 /* convert Posix priorities to Threadx priority */
233 retval += tx_thread_create(thread_ptr,
234 "pthr",
235 posix_thread_wrapper,
236 (ULONG)(ALIGN_TYPE)pthread_ptr,
237 pthread_ptr->stack_address,
238 pthread_ptr->stack_size,
239 (TX_LOWEST_PRIORITY - pthread_ptr->current_priority + 1),
240 (TX_LOWEST_PRIORITY - pthread_ptr->threshold + 1),
241 pthread_ptr->time_slice,
242 TX_AUTO_START);
243
244 TX_THREAD_EXTENSION_PTR_SET(thread_ptr, pthread_ptr)
245
246 /* See if ThreadX encountered an error */
247 if (retval)
248 {
249 /* Internal error */
250 posix_error_handler(3333);
251 retval = EACCES;
252 }
253 else
254 {
255 /* Everything is fine. */
256 /* create a pthreadID by type casting POSIX_TCB into pthread_t */
257 pthread_ptr->pthreadID = (pthread_t )pthread_ptr;
258 *thread = pthread_ptr->pthreadID ;
259 retval = OK;
260 }
261
262 /* Everything worked fine if we got here */
263 return(retval);
264
265 }
266