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