source: rtems/cpukit/posix/src/pthread.c @ 69aa3349

4.115
Last change on this file since 69aa3349 was 69aa3349, checked in by Sebastian Huber <sebastian.huber@…>, on 04/08/14 at 07:42:29

score: Simplify thread control initialization

The thread control block contains fields that point to application
configuration dependent memory areas, like the scheduler information,
the API control blocks, the user extension context table, the RTEMS
notepads and the Newlib re-entrancy support. Account for these areas in
the configuration and avoid extra workspace allocations for these areas.

This helps also to avoid heap fragementation and reduces the per thread
memory due to a reduced heap allocation overhead.

  • Property mode set to 100644
File size: 11.6 KB
RevLine 
[eb08acf]1/**
2 * @file
3 *
4 * @brief Private Support Information for POSIX Threads
5 * @ingroup POSIX_PTHREADS Private Threads
6 */
7
[8165b48f]8/*
[e6c87f7]9 *  COPYRIGHT (c) 1989-2014.
[412dbff6]10 *  On-Line Applications Research Corporation (OAR).
11 *
12 *  The license and distribution terms for this file may be
13 *  found in the file LICENSE in this distribution or at
[c499856]14 *  http://www.rtems.org/license/LICENSE.
[5e9b32b]15 */
16
[f42b726]17#if HAVE_CONFIG_H
18#include "config.h"
19#endif
[185e46f]20#include <stdio.h>
[f42b726]21
[5e9b32b]22#include <errno.h>
23#include <pthread.h>
24#include <limits.h>
[185e46f]25#include <assert.h>
[5e9b32b]26
[f4719d5a]27#include <rtems/system.h>
[309e2f6]28#include <rtems/config.h>
[5a18e04]29#include <rtems/score/apiext.h>
[5e9b32b]30#include <rtems/score/stack.h>
[5618c37a]31#include <rtems/score/threadimpl.h>
[a112364]32#include <rtems/score/threadqimpl.h>
[3be0c9a]33#include <rtems/score/userextimpl.h>
[4b48ece0]34#include <rtems/score/watchdogimpl.h>
[5a18e04]35#include <rtems/score/wkspace.h>
[2df1974]36#include <rtems/posix/cancel.h>
[0c5317d]37#include <rtems/posix/pthreadimpl.h>
[97552c98]38#include <rtems/posix/priorityimpl.h>
[f9340ed7]39#include <rtems/posix/psignalimpl.h>
[5a18e04]40#include <rtems/posix/config.h>
[2ad250e]41#include <rtems/posix/keyimpl.h>
[624133c]42#include <rtems/posix/time.h>
[c16bcc0]43#include <rtems/score/timespec.h>
[7205189]44#include <rtems/score/cpusetimpl.h>
45#include <rtems/score/assert.h>
[5e9b32b]46
[a1f0ca28]47/*
[5e9b32b]48 *  The default pthreads attributes structure.
[65c421f]49 *
[874297f3]50 *  NOTE: Be careful .. if the default attribute set changes,
[65c421f]51 *        _POSIX_Threads_Initialize_user_threads will need to be examined.
[5e9b32b]52 */
[185e46f]53pthread_attr_t _POSIX_Threads_Default_attributes = {
54  .is_initialized  = true,                       /* is_initialized */
55  .stackaddr       = NULL,                       /* stackaddr */
56  .stacksize       = 0,                          /* stacksize -- will be adjusted to minimum */
57  .contentionscope = PTHREAD_SCOPE_PROCESS,      /* contentionscope */
58  .inheritsched    = PTHREAD_INHERIT_SCHED,      /* inheritsched */
59  .schedpolicy     = SCHED_FIFO,                 /* schedpolicy */
60  .schedparam      =
[0b710dbb]61  {                           /* schedparam */
62    2,                        /* sched_priority */
[85e0a22]63    #if defined(_POSIX_SPORADIC_SERVER) || \
64        defined(_POSIX_THREAD_SPORADIC_SERVER)
65      0,                        /* sched_ss_low_priority */
66      { 0L, 0 },                /* sched_ss_repl_period */
[29aed671]67      { 0L, 0 },                /* sched_ss_init_budget */
68      0                         /* sched_ss_max_repl */
[85e0a22]69    #endif
[5e9b32b]70  },
[185e46f]71
[21dd3ab8]72  #if HAVE_DECL_PTHREAD_ATTR_SETGUARDSIZE
[185e46f]73    .guardsize = 0,                            /* guardsize */
[21dd3ab8]74  #endif
[85e0a22]75  #if defined(_POSIX_THREAD_CPUTIME)
[185e46f]76    .cputime_clock_allowed = 1,                        /* cputime_clock_allowed */
77  #endif
78  .detachstate             = PTHREAD_CREATE_JOINABLE,    /* detachstate */
79  #if defined(__RTEMS_HAVE_SYS_CPUSET_H__)
80    .affinitysetsize         = 0,
81    .affinityset             = NULL,
82    .affinitysetpreallocated = {{0x0}}
[85e0a22]83  #endif
[5e9b32b]84};
85
[a1f0ca28]86/*
[65a5c1b]87 *  _POSIX_Threads_Sporadic_budget_TSR
88 */
89void _POSIX_Threads_Sporadic_budget_TSR(
[92f4671]90  Objects_Id      id __attribute__((unused)),
[65a5c1b]91  void           *argument
92)
93{
[39cefdd]94  uint32_t            ticks;
95  uint32_t            new_priority;
[65a5c1b]96  Thread_Control     *the_thread;
97  POSIX_API_Control  *api;
98
99  the_thread = argument;
100
101  api = the_thread->API_Extensions[ THREAD_API_POSIX ];
102
[770db69]103  /* ticks is guaranteed to be at least one */
[3bacb250]104  ticks = _Timespec_To_ticks( &api->schedparam.sched_ss_init_budget );
[65a5c1b]105
[2014063]106  the_thread->cpu_time_budget = ticks;
[874297f3]107
[3bacb250]108  new_priority = _POSIX_Priority_To_core( api->schedparam.sched_priority );
[2014063]109  the_thread->real_priority = new_priority;
110
[a1f0ca28]111  /*
112   *  If holding a resource, then do not change it.
113   */
114  #if 0
115    printk( "TSR %d %d %d\n", the_thread->resource_count,
116        the_thread->current_priority, new_priority );
117  #endif
118  if ( the_thread->resource_count == 0 ) {
119    /*
120     *  If this would make them less important, then do not change it.
121     */
122    if ( the_thread->current_priority > new_priority ) {
123      _Thread_Change_priority( the_thread, new_priority, true );
124      #if 0
125        printk( "raise priority\n" );
126      #endif
127    }
128  }
[2014063]129
[770db69]130  /* ticks is guaranteed to be at least one */
[3bacb250]131  ticks = _Timespec_To_ticks( &api->schedparam.sched_ss_repl_period );
[2014063]132
133  _Watchdog_Insert_ticks( &api->Sporadic_timer, ticks );
[65a5c1b]134}
135
[a1f0ca28]136/*
[65a5c1b]137 *  _POSIX_Threads_Sporadic_budget_callout
138 */
139void _POSIX_Threads_Sporadic_budget_callout(
140  Thread_Control *the_thread
141)
142{
[2014063]143  POSIX_API_Control *api;
[39cefdd]144  uint32_t           new_priority;
[65a5c1b]145
[2014063]146  api = the_thread->API_Extensions[ THREAD_API_POSIX ];
[65a5c1b]147
[2014063]148  /*
149   *  This will prevent the thread from consuming its entire "budget"
150   *  while at low priority.
151   */
[8ae999c3]152  the_thread->cpu_time_budget = UINT32_MAX;
[2014063]153
[3bacb250]154  new_priority = _POSIX_Priority_To_core(api->schedparam.sched_ss_low_priority);
[2014063]155  the_thread->real_priority = new_priority;
156
[a1f0ca28]157  /*
158   *  If holding a resource, then do not change it.
159   */
160  #if 0
161    printk( "callout %d %d %d\n", the_thread->resource_count,
162        the_thread->current_priority, new_priority );
163  #endif
164  if ( the_thread->resource_count == 0 ) {
165    /*
166     *  Make sure we are actually lowering it. If they have lowered it
[3bacb250]167     *  to logically lower than sched_ss_low_priority, then we do not want to
[a1f0ca28]168     *  change it.
169     */
170    if ( the_thread->current_priority < new_priority ) {
171      _Thread_Change_priority( the_thread, new_priority, true );
172      #if 0
173        printk( "lower priority\n" );
174      #endif
175    }
176  }
[65a5c1b]177}
178
[a1f0ca28]179/*
[5a18e04]180 *  _POSIX_Threads_Create_extension
181 *
[a1f0ca28]182 *  This method is invoked for each thread created.
[5a18e04]183 */
[874297f3]184
[29aed671]185static bool _POSIX_Threads_Create_extension(
[92f4671]186  Thread_Control *executing __attribute__((unused)),
[5a18e04]187  Thread_Control *created
188)
189{
190  POSIX_API_Control *api;
[65c421f]191  POSIX_API_Control *executing_api;
[874297f3]192
[69aa3349]193  api = created->API_Extensions[ THREAD_API_POSIX ];
[874297f3]194
[b85649c4]195  /* XXX check all fields are touched */
[185e46f]196  _POSIX_Threads_Initialize_attributes( &api->Attributes );
[895efd9]197  api->detachstate = _POSIX_Threads_Default_attributes.detachstate;
198  api->schedpolicy = _POSIX_Threads_Default_attributes.schedpolicy;
199  api->schedparam  = _POSIX_Threads_Default_attributes.schedparam;
[874297f3]200  api->schedparam.sched_priority =
[895efd9]201     _POSIX_Priority_From_core( created->current_priority );
[874297f3]202
203  /*
[b6c868e]204   *  POSIX 1003.1 1996, 18.2.2.2
205   */
206  api->cancelation_requested = 0;
207  api->cancelability_state = PTHREAD_CANCEL_ENABLE;
208  api->cancelability_type = PTHREAD_CANCEL_DEFERRED;
[927a0a1]209#ifndef HAVE_STRUCT__PTHREAD_CLEANUP_CONTEXT
[b6c868e]210  _Chain_Initialize_empty (&api->Cancellation_Handlers);
[927a0a1]211#else /* HAVE_STRUCT__PTHREAD_CLEANUP_CONTEXT */
212  api->last_cleanup_context = NULL;
213#endif /* HAVE_STRUCT__PTHREAD_CLEANUP_CONTEXT */
[b6c868e]214
[b85649c4]215  /*
216   *  If the thread is not a posix thread, then all posix signals are blocked
217   *  by default.
[2212a2ad]218   *
219   *  The check for class == 1 is debug.  Should never really happen.
[b85649c4]220   */
[fa820b9]221  api->signals_pending = SIGNAL_EMPTY_MASK;
[2212a2ad]222  if ( _Objects_Get_API( created->Object.id ) == OBJECTS_POSIX_API
223       #if defined(RTEMS_DEBUG)
[a1f0ca28]224         && _Objects_Get_class( created->Object.id ) == 1
[2212a2ad]225       #endif
226  ) {
[fb7199d]227    executing_api = _Thread_Get_executing()->API_Extensions[ THREAD_API_POSIX ];
[7349e6d0]228    api->signals_blocked = executing_api->signals_blocked;
229  } else {
[fa820b9]230    api->signals_blocked = SIGNAL_ALL_MASK;
[7349e6d0]231  }
[b85649c4]232
[fc521e2d]233  _Thread_Action_initialize(
234    &api->Signal_action,
235    _POSIX_signals_Action_handler
236  );
237
[895efd9]238  _Thread_queue_Initialize(
239    &api->Join_List,
240    THREAD_QUEUE_DISCIPLINE_FIFO,
[f05af6b7]241    STATES_WAITING_FOR_JOIN_AT_EXIT | STATES_INTERRUPTIBLE_BY_SIGNAL,
[895efd9]242    0
243  );
[874297f3]244
[895efd9]245  _Watchdog_Initialize(
246    &api->Sporadic_timer,
247    _POSIX_Threads_Sporadic_budget_TSR,
248    created->Object.id,
249    created
250  );
[5a18e04]251
[f8437c8]252  return true;
[5a18e04]253}
[895efd9]254
[391ad3e]255static void _POSIX_Threads_Restart_extension(
256  Thread_Control *executing,
257  Thread_Control *restarted
258)
259{
260  (void) executing;
261  _POSIX_Threads_cancel_run( restarted );
262}
263
[1b1be254]264static void _POSIX_Threads_Terminate_extension(
265  Thread_Control *executing
266)
[5a18e04]267{
[895efd9]268  Thread_Control     *the_thread;
269  POSIX_API_Control  *api;
270  void              **value_ptr;
271
[1b1be254]272  api = executing->API_Extensions[ THREAD_API_POSIX ];
[874297f3]273
[f845e96e]274  /*
275   *  Run the POSIX cancellation handlers
276   */
[1b1be254]277  _POSIX_Threads_cancel_run( executing );
278
279  _Thread_Disable_dispatch();
[895efd9]280
281  /*
282   *  Wakeup all the tasks which joined with this one
283   */
[1b1be254]284  value_ptr = (void **) executing->Wait.return_argument;
[895efd9]285
286  while ( (the_thread = _Thread_queue_Dequeue( &api->Join_List )) )
287      *(void **)the_thread->Wait.return_argument = value_ptr;
[874297f3]288
[895efd9]289  if ( api->schedpolicy == SCHED_SPORADIC )
290    (void) _Watchdog_Remove( &api->Sporadic_timer );
[a61f1a46]291
[1b1be254]292  _Thread_Enable_dispatch();
[5a18e04]293}
294
[260b0c2]295/*
296 *  _POSIX_Threads_Exitted_extension
[a1f0ca28]297 *
298 *  This method is invoked each time a thread exits.
[260b0c2]299 */
[29aed671]300static void _POSIX_Threads_Exitted_extension(
[260b0c2]301  Thread_Control *executing
302)
303{
[092fe28e]304  /*
305   *  If the executing thread was not created with the POSIX API, then this
306   *  API do not get to define its exit behavior.
307   */
308  if ( _Objects_Get_API( executing->Object.id ) == OBJECTS_POSIX_API )
309    pthread_exit( executing->Wait.return_argument );
[260b0c2]310}
311
[a1f0ca28]312/*
[dd32d883]313 *  _POSIX_Threads_Initialize_user_threads
[5a18e04]314 *
315 *  This routine creates and starts all configured user
[76f1677]316 *  initialization threads.
[5a18e04]317 */
[29aed671]318static void _POSIX_Threads_Initialize_user_threads( void )
[5a18e04]319{
[0ab34c90]320  if ( _POSIX_Threads_Initialize_user_threads_p )
321    (*_POSIX_Threads_Initialize_user_threads_p)();
[5a18e04]322}
323
[a1f0ca28]324/*
[22b4b2e]325 *  API Extension control structures
326 */
[5a18e04]327API_extensions_Control _POSIX_Threads_API_extensions = {
[27b961a]328  #if defined(FUNCTIONALITY_NOT_CURRENTLY_USED_BY_ANY_API)
[04b5d17]329    .predriver_hook = NULL,
[27b961a]330  #endif
[04b5d17]331  .postdriver_hook = _POSIX_Threads_Initialize_user_threads
332};
333
[5a18e04]334User_extensions_Control _POSIX_Threads_User_extensions = {
335  { NULL, NULL },
[aa08739a]336  { { NULL, NULL }, NULL },
[5a18e04]337  { _POSIX_Threads_Create_extension,          /* create */
338    NULL,                                     /* start */
[391ad3e]339    _POSIX_Threads_Restart_extension,         /* restart */
[69aa3349]340    NULL,                                     /* delete */
[5a18e04]341    NULL,                                     /* switch */
342    NULL,                                     /* begin */
[260b0c2]343    _POSIX_Threads_Exitted_extension,         /* exitted */
[1b1be254]344    NULL,                                     /* fatal */
345    _POSIX_Threads_Terminate_extension        /* terminate */
[5a18e04]346  }
347};
[874297f3]348
[a1f0ca28]349/*
[5e9b32b]350 *  _POSIX_Threads_Manager_initialization
351 *
352 *  This routine initializes all threads manager related data structures.
353 */
[309e2f6]354void _POSIX_Threads_Manager_initialization(void)
[5e9b32b]355{
[a0a073d1]356  #if defined(RTEMS_SMP) && defined(__RTEMS_HAVE_SYS_CPUSET_H__)
[7205189]357    const CPU_set_Control *affinity;
[185e46f]358    pthread_attr_t *attr;
359
360    /* Initialize default attribute. */
361    attr = &_POSIX_Threads_Default_attributes;
362
[7205189]363    /*  Initialize the affinity to be the default cpu set for the system */
364    affinity = _CPU_set_Default();
365    _Assert( affinity->setsize == sizeof( attr->affinitysetpreallocated ) );
[185e46f]366    attr->affinityset             = &attr->affinitysetpreallocated;
[7205189]367    attr->affinitysetsize         = affinity->setsize;
368    CPU_COPY( attr->affinityset, affinity->set );
[185e46f]369  #endif
370
[5e9b32b]371  _Objects_Initialize_information(
[3c465878]372    &_POSIX_Threads_Information, /* object information table */
373    OBJECTS_POSIX_API,           /* object API */
374    OBJECTS_POSIX_THREADS,       /* object class */
[309e2f6]375    Configuration_POSIX_API.maximum_threads,
376                                 /* maximum objects of this class */
[69aa3349]377    _Thread_Control_size,        /* size of this object's control block */
[b1dbfd7]378    true,                        /* true if names for this object are strings */
[309e2f6]379    _POSIX_PATH_MAX              /* maximum length of each object's name */
[3c465878]380#if defined(RTEMS_MULTIPROCESSING)
381    ,
[b1dbfd7]382    false,                       /* true if this is a global object class */
[3c465878]383    NULL                         /* Proxy extraction support callout */
384#endif
[5e9b32b]385  );
[5a18e04]386
[613cff6]387  /*
388   *  Add all the extensions for this API
389   */
390  _User_extensions_Add_API_set( &_POSIX_Threads_User_extensions );
[f845e96e]391
[613cff6]392  _API_extensions_Add( &_POSIX_Threads_API_extensions );
[f845e96e]393
[613cff6]394  /*
395   *  If we supported MP, then here we would ...
396   *       Register the MP Process Packet routine.
397   */
[5e9b32b]398}
Note: See TracBrowser for help on using the repository browser.