source: rtems/cpukit/posix/src/pthreadcreate.c @ 21275b58

Last change on this file since 21275b58 was 21275b58, checked in by Sebastian Huber <sebastian.huber@…>, on Nov 22, 2018 at 6:14:51 PM

score: Static Objects_Information initialization

Statically allocate the objects information together with the initial
set of objects either via <rtems/confdefs.h>. Provide default object
informations with zero objects via librtemscpu.a. This greatly
simplifies the workspace size estimate. RTEMS applications which do not
use the unlimited objects option are easier to debug since all objects
reside now in statically allocated objects of the right types.

Close #3621.

  • Property mode set to 100644
File size: 11.5 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#if defined(RTEMS_POSIX_API)
30#include <rtems/posix/psignalimpl.h>
31#endif
32#include <rtems/posix/pthreadimpl.h>
33#include <rtems/posix/pthreadattrimpl.h>
34#include <rtems/score/assert.h>
35#include <rtems/score/threadimpl.h>
36#include <rtems/score/apimutex.h>
37#include <rtems/score/stackimpl.h>
38#include <rtems/score/schedulerimpl.h>
39#include <rtems/score/userextimpl.h>
40#include <rtems/sysinit.h>
41
42static inline size_t _POSIX_Threads_Ensure_minimum_stack (
43  size_t size
44)
45{
46  if ( size >= PTHREAD_MINIMUM_STACK_SIZE )
47    return size;
48  return PTHREAD_MINIMUM_STACK_SIZE;
49}
50
51
52int pthread_create(
53  pthread_t              *thread,
54  const pthread_attr_t   *attr,
55  void                 *(*start_routine)( void * ),
56  void                   *arg
57)
58{
59  Thread_Entry_information entry = {
60    .adaptor = _Thread_Entry_adaptor_pointer,
61    .Kinds = {
62      .Pointer = {
63        .entry = start_routine,
64        .argument = arg
65      }
66    }
67  };
68  const pthread_attr_t               *the_attr;
69  int                                 normal_prio;
70  bool                                valid;
71  Priority_Control                    core_normal_prio;
72  Thread_CPU_budget_algorithms        budget_algorithm;
73  Thread_CPU_budget_algorithm_callout budget_callout;
74  bool                                is_fp;
75  bool                                status;
76  Thread_Control                     *the_thread;
77  Thread_Control                     *executing;
78  const Scheduler_Control            *scheduler;
79  int                                 schedpolicy = SCHED_RR;
80  struct sched_param                  schedparam;
81  size_t                              stacksize;
82  Objects_Name                        name;
83  int                                 error;
84  ISR_lock_Context                    lock_context;
85#if defined(RTEMS_POSIX_API)
86  int                                 low_prio;
87  Priority_Control                    core_low_prio;
88  POSIX_API_Control                  *api;
89  const POSIX_API_Control            *executing_api;
90#endif
91
92  if ( !start_routine )
93    return EFAULT;
94
95  the_attr = (attr) ? attr : &_POSIX_Threads_Default_attributes;
96
97  if ( !the_attr->is_initialized )
98    return EINVAL;
99
100  /*
101   *  Core Thread Initialize ensures we get the minimum amount of
102   *  stack space if it is allowed to allocate it itself.
103   *
104   *  NOTE: If the user provides the stack we will let it drop below
105   *        twice the minimum.
106   */
107  if ( the_attr->stackaddr != NULL ) {
108    if ( !_Stack_Is_enough(the_attr->stacksize) ) {
109      return EINVAL;
110    }
111
112    stacksize = the_attr->stacksize;
113  } else {
114    stacksize = _POSIX_Threads_Ensure_minimum_stack( the_attr->stacksize );
115  }
116
117  #if 0
118    int  cputime_clock_allowed;  /* see time.h */
119    rtems_set_errno_and_return_minus_one( ENOSYS );
120  #endif
121
122  executing = _Thread_Get_executing();
123
124  /*
125   *  P1003.1c/Draft 10, p. 121.
126   *
127   *  If inheritsched is set to PTHREAD_INHERIT_SCHED, then this thread
128   *  inherits scheduling attributes from the creating thread.   If it is
129   *  PTHREAD_EXPLICIT_SCHED, then scheduling parameters come from the
130   *  attributes structure.
131   */
132  switch ( the_attr->inheritsched ) {
133    case PTHREAD_INHERIT_SCHED:
134      error = pthread_getschedparam(
135        pthread_self(),
136        &schedpolicy,
137        &schedparam
138      );
139      _Assert( error == 0 );
140      break;
141
142    case PTHREAD_EXPLICIT_SCHED:
143      schedpolicy = the_attr->schedpolicy;
144      schedparam  = the_attr->schedparam;
145      break;
146
147    default:
148      return EINVAL;
149  }
150
151  /*
152   *  Check the contentionscope since rtems only supports PROCESS wide
153   *  contention (i.e. no system wide contention).
154   */
155  if ( the_attr->contentionscope != PTHREAD_SCOPE_PROCESS )
156    return ENOTSUP;
157
158  error = _POSIX_Thread_Translate_sched_param(
159    schedpolicy,
160    &schedparam,
161    &budget_algorithm,
162    &budget_callout
163  );
164  if ( error != 0 ) {
165    return error;
166  }
167
168  normal_prio = schedparam.sched_priority;
169
170  scheduler = _Thread_Scheduler_get_home( executing );
171
172  core_normal_prio = _POSIX_Priority_To_core( scheduler, normal_prio, &valid );
173  if ( !valid ) {
174    return EINVAL;
175  }
176
177#if defined(RTEMS_POSIX_API)
178  if ( schedpolicy == SCHED_SPORADIC ) {
179    low_prio = schedparam.sched_ss_low_priority;
180  } else {
181    low_prio = normal_prio;
182  }
183
184  core_low_prio = _POSIX_Priority_To_core( scheduler, low_prio, &valid );
185  if ( !valid ) {
186    return EINVAL;
187  }
188#endif
189
190  if ( the_attr->affinityset == NULL ) {
191    return EINVAL;
192  }
193
194  /*
195   *  Currently all POSIX threads are floating point if the hardware
196   *  supports it.
197   */
198  is_fp = true;
199
200  /*
201   *  Allocate the thread control block.
202   *
203   *  NOTE:  Global threads are not currently supported.
204   */
205  the_thread = _POSIX_Threads_Allocate();
206  if ( !the_thread ) {
207    _Objects_Allocator_unlock();
208    return EAGAIN;
209  }
210
211  /*
212   *  Initialize the core thread for this task.
213   */
214  name.name_p = NULL;   /* posix threads don't have a name by default */
215  status = _Thread_Initialize(
216    &_POSIX_Threads_Information,
217    the_thread,
218    scheduler,
219    the_attr->stackaddr,
220    stacksize,
221    is_fp,
222    core_normal_prio,
223    true,                 /* preemptible */
224    budget_algorithm,
225    budget_callout,
226    0,                    /* isr level */
227    name                  /* posix threads don't have a name */
228  );
229  if ( !status ) {
230    _POSIX_Threads_Free( the_thread );
231    _Objects_Allocator_unlock();
232    return EAGAIN;
233  }
234
235  if ( the_attr->detachstate == PTHREAD_CREATE_DETACHED ) {
236    the_thread->Life.state |= THREAD_LIFE_DETACHED;
237  }
238
239  the_thread->Life.state |= THREAD_LIFE_CHANGE_DEFERRED;
240
241  _ISR_lock_ISR_disable( &lock_context );
242   status = _Scheduler_Set_affinity(
243     the_thread,
244     the_attr->affinitysetsize,
245     the_attr->affinityset
246   );
247  _ISR_lock_ISR_enable( &lock_context );
248   if ( !status ) {
249     _POSIX_Threads_Free( the_thread );
250     _RTEMS_Unlock_allocator();
251     return EINVAL;
252   }
253
254  the_thread->was_created_with_inherited_scheduler =
255    ( the_attr->inheritsched == PTHREAD_INHERIT_SCHED );
256
257#if defined(RTEMS_POSIX_API)
258  /*
259   *  finish initializing the per API structure
260   */
261  api = the_thread->API_Extensions[ THREAD_API_POSIX ];
262  executing_api = executing->API_Extensions[ THREAD_API_POSIX ];
263
264  api->signals_unblocked = executing_api->signals_unblocked;
265
266  _Priority_Node_set_priority( &api->Sporadic.Low_priority, core_low_prio );
267  api->Sporadic.sched_ss_repl_period =
268    the_attr->schedparam.sched_ss_repl_period;
269  api->Sporadic.sched_ss_init_budget =
270    the_attr->schedparam.sched_ss_init_budget;
271  api->Sporadic.sched_ss_max_repl =
272    the_attr->schedparam.sched_ss_max_repl;
273
274  if ( schedpolicy == SCHED_SPORADIC ) {
275    _POSIX_Threads_Sporadic_timer( &api->Sporadic.Timer );
276  }
277#endif
278
279  /*
280   *  POSIX threads are allocated and started in one operation.
281   */
282  _ISR_lock_ISR_disable( &lock_context );
283  status = _Thread_Start( the_thread, &entry, &lock_context );
284
285  #if defined(RTEMS_DEBUG)
286    /*
287     *  _Thread_Start only fails if the thread was in the incorrect state
288     *
289     *  NOTE: This can only happen if someone slips in and touches the
290     *        thread while we are creating it.
291     */
292    if ( !status ) {
293      _POSIX_Threads_Free( the_thread );
294      _Objects_Allocator_unlock();
295      return EINVAL;
296    }
297  #endif
298
299  /*
300   *  Return the id and indicate we successfully created the thread
301   */
302  *thread = the_thread->Object.id;
303
304  _Objects_Allocator_unlock();
305  return 0;
306}
307
308#if defined(RTEMS_POSIX_API)
309void _POSIX_Threads_Sporadic_timer( Watchdog_Control *watchdog )
310{
311  POSIX_API_Control    *api;
312  Thread_Control       *the_thread;
313  Thread_queue_Context  queue_context;
314
315  api = RTEMS_CONTAINER_OF( watchdog, POSIX_API_Control, Sporadic.Timer );
316  the_thread = api->Sporadic.thread;
317
318  _Thread_queue_Context_initialize( &queue_context );
319  _Thread_queue_Context_clear_priority_updates( &queue_context );
320  _Thread_Wait_acquire( the_thread, &queue_context );
321
322  if ( _Priority_Node_is_active( &api->Sporadic.Low_priority ) ) {
323    _Thread_Priority_add(
324      the_thread,
325      &the_thread->Real_priority,
326      &queue_context
327    );
328    _Thread_Priority_remove(
329      the_thread,
330      &api->Sporadic.Low_priority,
331      &queue_context
332    );
333    _Priority_Node_set_inactive( &api->Sporadic.Low_priority );
334  }
335
336  _Watchdog_Per_CPU_remove_ticks( &api->Sporadic.Timer );
337  _POSIX_Threads_Sporadic_timer_insert( the_thread, api );
338
339  _Thread_Wait_release( the_thread, &queue_context );
340  _Thread_Priority_update( &queue_context );
341}
342
343void _POSIX_Threads_Sporadic_budget_callout( Thread_Control *the_thread )
344{
345  POSIX_API_Control    *api;
346  Thread_queue_Context  queue_context;
347
348  api = the_thread->API_Extensions[ THREAD_API_POSIX ];
349
350  _Thread_queue_Context_initialize( &queue_context );
351  _Thread_queue_Context_clear_priority_updates( &queue_context );
352  _Thread_Wait_acquire( the_thread, &queue_context );
353
354  /*
355   *  This will prevent the thread from consuming its entire "budget"
356   *  while at low priority.
357   */
358  the_thread->cpu_time_budget = UINT32_MAX;
359
360  if ( !_Priority_Node_is_active( &api->Sporadic.Low_priority ) ) {
361    _Thread_Priority_add(
362      the_thread,
363      &api->Sporadic.Low_priority,
364      &queue_context
365    );
366    _Thread_Priority_remove(
367      the_thread,
368      &the_thread->Real_priority,
369      &queue_context
370    );
371  }
372
373  _Thread_Wait_release( the_thread, &queue_context );
374  _Thread_Priority_update( &queue_context );
375}
376
377static bool _POSIX_Threads_Create_extension(
378  Thread_Control *executing RTEMS_UNUSED,
379  Thread_Control *created
380)
381{
382  POSIX_API_Control *api;
383
384  api = created->API_Extensions[ THREAD_API_POSIX ];
385
386  api->Sporadic.thread = created;
387  _Watchdog_Preinitialize( &api->Sporadic.Timer, _Per_CPU_Get_by_index( 0 ) );
388  _Watchdog_Initialize( &api->Sporadic.Timer, _POSIX_Threads_Sporadic_timer );
389  _Priority_Node_set_inactive( &api->Sporadic.Low_priority );
390
391  return true;
392}
393
394static void _POSIX_Threads_Terminate_extension( Thread_Control *executing )
395{
396  POSIX_API_Control *api;
397  ISR_lock_Context   lock_context;
398
399  api = executing->API_Extensions[ THREAD_API_POSIX ];
400
401  _Thread_State_acquire( executing, &lock_context );
402  _Watchdog_Per_CPU_remove_ticks( &api->Sporadic.Timer );
403  _Thread_State_release( executing, &lock_context );
404}
405#endif
406
407static void _POSIX_Threads_Exitted_extension(
408  Thread_Control *executing
409)
410{
411  /*
412   *  If the executing thread was not created with the POSIX API, then this
413   *  API do not get to define its exit behavior.
414   */
415  if ( _Objects_Get_API( executing->Object.id ) == OBJECTS_POSIX_API )
416    pthread_exit( executing->Wait.return_argument );
417}
418
419static User_extensions_Control _POSIX_Threads_User_extensions = {
420  .Callouts = {
421#if defined(RTEMS_POSIX_API)
422    .thread_create    = _POSIX_Threads_Create_extension,
423    .thread_terminate = _POSIX_Threads_Terminate_extension,
424#endif
425    .thread_exitted   = _POSIX_Threads_Exitted_extension
426  }
427};
428
429static void _POSIX_Threads_Manager_initialization( void )
430{
431  _Thread_Initialize_information( &_POSIX_Threads_Information );
432  _User_extensions_Add_API_set( &_POSIX_Threads_User_extensions );
433}
434
435RTEMS_SYSINIT_ITEM(
436  _POSIX_Threads_Manager_initialization,
437  RTEMS_SYSINIT_POSIX_THREADS,
438  RTEMS_SYSINIT_ORDER_MIDDLE
439);
Note: See TracBrowser for help on using the repository browser.