source: rtems/cpukit/posix/src/pthreadcreate.c @ ef16a11

5
Last change on this file since ef16a11 was 54f35888, checked in by Sebastian Huber <sebastian.huber@…>, on 10/25/18 at 08:54:12

posix: Provide threads by default

Update #2514.

  • Property mode set to 100644
File size: 7.7 KB
Line 
1/**
2 * @file
3 *
4 * @brief Function Starts a New Thread in The Calling Process
5 * @ingroup POSIXAPI
6 */
7
8/*
9 *  16.1.2 Thread Creation, P1003.1c/Draft 10, p. 144
10 */
11
12/*
13 *  COPYRIGHT (c) 1989-2014.
14 *  On-Line Applications Research Corporation (OAR).
15 *
16 *  The license and distribution terms for this file may be
17 *  found in the file LICENSE in this distribution or at
18 *  http://www.rtems.org/license/LICENSE.
19 */
20
21#if HAVE_CONFIG_H
22#include "config.h"
23#endif
24
25#include <pthread.h>
26#include <errno.h>
27
28#include <rtems/posix/priorityimpl.h>
29#include <rtems/posix/pthreadimpl.h>
30#include <rtems/posix/pthreadattrimpl.h>
31#include <rtems/score/assert.h>
32#include <rtems/score/threadimpl.h>
33#include <rtems/score/apimutex.h>
34#include <rtems/score/stackimpl.h>
35#include <rtems/score/schedulerimpl.h>
36
37static inline size_t _POSIX_Threads_Ensure_minimum_stack (
38  size_t size
39)
40{
41  if ( size >= PTHREAD_MINIMUM_STACK_SIZE )
42    return size;
43  return PTHREAD_MINIMUM_STACK_SIZE;
44}
45
46
47int pthread_create(
48  pthread_t              *thread,
49  const pthread_attr_t   *attr,
50  void                 *(*start_routine)( void * ),
51  void                   *arg
52)
53{
54  Thread_Entry_information entry = {
55    .adaptor = _Thread_Entry_adaptor_pointer,
56    .Kinds = {
57      .Pointer = {
58        .entry = start_routine,
59        .argument = arg
60      }
61    }
62  };
63  const pthread_attr_t               *the_attr;
64  int                                 normal_prio;
65  bool                                valid;
66  Priority_Control                    core_normal_prio;
67  Thread_CPU_budget_algorithms        budget_algorithm;
68  Thread_CPU_budget_algorithm_callout budget_callout;
69  bool                                is_fp;
70  bool                                status;
71  Thread_Control                     *the_thread;
72  Thread_Control                     *executing;
73  const Scheduler_Control            *scheduler;
74  int                                 schedpolicy = SCHED_RR;
75  struct sched_param                  schedparam;
76  size_t                              stacksize;
77  Objects_Name                        name;
78  int                                 error;
79  ISR_lock_Context                    lock_context;
80#if defined(RTEMS_POSIX_API)
81  int                                 low_prio;
82  Priority_Control                    core_low_prio;
83  POSIX_API_Control                  *api;
84  const POSIX_API_Control            *executing_api;
85#endif
86
87  if ( !start_routine )
88    return EFAULT;
89
90  the_attr = (attr) ? attr : &_POSIX_Threads_Default_attributes;
91
92  if ( !the_attr->is_initialized )
93    return EINVAL;
94
95  /*
96   *  Core Thread Initialize ensures we get the minimum amount of
97   *  stack space if it is allowed to allocate it itself.
98   *
99   *  NOTE: If the user provides the stack we will let it drop below
100   *        twice the minimum.
101   */
102  if ( the_attr->stackaddr != NULL ) {
103    if ( !_Stack_Is_enough(the_attr->stacksize) ) {
104      return EINVAL;
105    }
106
107    stacksize = the_attr->stacksize;
108  } else {
109    stacksize = _POSIX_Threads_Ensure_minimum_stack( the_attr->stacksize );
110  }
111
112  #if 0
113    int  cputime_clock_allowed;  /* see time.h */
114    rtems_set_errno_and_return_minus_one( ENOSYS );
115  #endif
116
117  executing = _Thread_Get_executing();
118
119  /*
120   *  P1003.1c/Draft 10, p. 121.
121   *
122   *  If inheritsched is set to PTHREAD_INHERIT_SCHED, then this thread
123   *  inherits scheduling attributes from the creating thread.   If it is
124   *  PTHREAD_EXPLICIT_SCHED, then scheduling parameters come from the
125   *  attributes structure.
126   */
127  switch ( the_attr->inheritsched ) {
128    case PTHREAD_INHERIT_SCHED:
129      error = pthread_getschedparam(
130        pthread_self(),
131        &schedpolicy,
132        &schedparam
133      );
134      _Assert( error == 0 );
135      break;
136
137    case PTHREAD_EXPLICIT_SCHED:
138      schedpolicy = the_attr->schedpolicy;
139      schedparam  = the_attr->schedparam;
140      break;
141
142    default:
143      return EINVAL;
144  }
145
146  /*
147   *  Check the contentionscope since rtems only supports PROCESS wide
148   *  contention (i.e. no system wide contention).
149   */
150  if ( the_attr->contentionscope != PTHREAD_SCOPE_PROCESS )
151    return ENOTSUP;
152
153  error = _POSIX_Thread_Translate_sched_param(
154    schedpolicy,
155    &schedparam,
156    &budget_algorithm,
157    &budget_callout
158  );
159  if ( error != 0 ) {
160    return error;
161  }
162
163  normal_prio = schedparam.sched_priority;
164
165  scheduler = _Thread_Scheduler_get_home( executing );
166
167  core_normal_prio = _POSIX_Priority_To_core( scheduler, normal_prio, &valid );
168  if ( !valid ) {
169    return EINVAL;
170  }
171
172#if defined(RTEMS_POSIX_API)
173  if ( schedpolicy == SCHED_SPORADIC ) {
174    low_prio = schedparam.sched_ss_low_priority;
175  } else {
176    low_prio = normal_prio;
177  }
178
179  core_low_prio = _POSIX_Priority_To_core( scheduler, low_prio, &valid );
180  if ( !valid ) {
181    return EINVAL;
182  }
183#endif
184
185  if ( the_attr->affinityset == NULL ) {
186    return EINVAL;
187  }
188
189  /*
190   *  Currently all POSIX threads are floating point if the hardware
191   *  supports it.
192   */
193  is_fp = true;
194
195  /*
196   *  Allocate the thread control block.
197   *
198   *  NOTE:  Global threads are not currently supported.
199   */
200  the_thread = _POSIX_Threads_Allocate();
201  if ( !the_thread ) {
202    _Objects_Allocator_unlock();
203    return EAGAIN;
204  }
205
206  /*
207   *  Initialize the core thread for this task.
208   */
209  name.name_p = NULL;   /* posix threads don't have a name by default */
210  status = _Thread_Initialize(
211    &_POSIX_Threads_Information,
212    the_thread,
213    scheduler,
214    the_attr->stackaddr,
215    stacksize,
216    is_fp,
217    core_normal_prio,
218    true,                 /* preemptible */
219    budget_algorithm,
220    budget_callout,
221    0,                    /* isr level */
222    name                  /* posix threads don't have a name */
223  );
224  if ( !status ) {
225    _POSIX_Threads_Free( the_thread );
226    _Objects_Allocator_unlock();
227    return EAGAIN;
228  }
229
230  if ( the_attr->detachstate == PTHREAD_CREATE_DETACHED ) {
231    the_thread->Life.state |= THREAD_LIFE_DETACHED;
232  }
233
234  the_thread->Life.state |= THREAD_LIFE_CHANGE_DEFERRED;
235
236  _ISR_lock_ISR_disable( &lock_context );
237   status = _Scheduler_Set_affinity(
238     the_thread,
239     the_attr->affinitysetsize,
240     the_attr->affinityset
241   );
242  _ISR_lock_ISR_enable( &lock_context );
243   if ( !status ) {
244     _POSIX_Threads_Free( the_thread );
245     _RTEMS_Unlock_allocator();
246     return EINVAL;
247   }
248
249  the_thread->was_created_with_inherited_scheduler =
250    ( the_attr->inheritsched == PTHREAD_INHERIT_SCHED );
251
252#if defined(RTEMS_POSIX_API)
253  /*
254   *  finish initializing the per API structure
255   */
256  api = the_thread->API_Extensions[ THREAD_API_POSIX ];
257  executing_api = executing->API_Extensions[ THREAD_API_POSIX ];
258
259  api->signals_unblocked = executing_api->signals_unblocked;
260
261  _Priority_Node_set_priority( &api->Sporadic.Low_priority, core_low_prio );
262  api->Sporadic.sched_ss_repl_period =
263    the_attr->schedparam.sched_ss_repl_period;
264  api->Sporadic.sched_ss_init_budget =
265    the_attr->schedparam.sched_ss_init_budget;
266  api->Sporadic.sched_ss_max_repl =
267    the_attr->schedparam.sched_ss_max_repl;
268
269  if ( schedpolicy == SCHED_SPORADIC ) {
270    _POSIX_Threads_Sporadic_timer( &api->Sporadic.Timer );
271  }
272#endif
273
274  /*
275   *  POSIX threads are allocated and started in one operation.
276   */
277  _ISR_lock_ISR_disable( &lock_context );
278  status = _Thread_Start( the_thread, &entry, &lock_context );
279
280  #if defined(RTEMS_DEBUG)
281    /*
282     *  _Thread_Start only fails if the thread was in the incorrect state
283     *
284     *  NOTE: This can only happen if someone slips in and touches the
285     *        thread while we are creating it.
286     */
287    if ( !status ) {
288      _POSIX_Threads_Free( the_thread );
289      _Objects_Allocator_unlock();
290      return EINVAL;
291    }
292  #endif
293
294  /*
295   *  Return the id and indicate we successfully created the thread
296   */
297  *thread = the_thread->Object.id;
298
299  _Objects_Allocator_unlock();
300  return 0;
301}
Note: See TracBrowser for help on using the repository browser.