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