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

4.11
Last change on this file since 69aa3349 was 69aa3349, checked in by Sebastian Huber <sebastian.huber@…>, on Apr 8, 2014 at 7:42:29 AM

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
Line 
1/**
2 * @file
3 *
4 * @brief Private Support Information for POSIX Threads
5 * @ingroup POSIX_PTHREADS Private Threads
6 */
7
8/*
9 *  COPYRIGHT (c) 1989-2014.
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
14 *  http://www.rtems.org/license/LICENSE.
15 */
16
17#if HAVE_CONFIG_H
18#include "config.h"
19#endif
20#include <stdio.h>
21
22#include <errno.h>
23#include <pthread.h>
24#include <limits.h>
25#include <assert.h>
26
27#include <rtems/system.h>
28#include <rtems/config.h>
29#include <rtems/score/apiext.h>
30#include <rtems/score/stack.h>
31#include <rtems/score/threadimpl.h>
32#include <rtems/score/threadqimpl.h>
33#include <rtems/score/userextimpl.h>
34#include <rtems/score/watchdogimpl.h>
35#include <rtems/score/wkspace.h>
36#include <rtems/posix/cancel.h>
37#include <rtems/posix/pthreadimpl.h>
38#include <rtems/posix/priorityimpl.h>
39#include <rtems/posix/psignalimpl.h>
40#include <rtems/posix/config.h>
41#include <rtems/posix/keyimpl.h>
42#include <rtems/posix/time.h>
43#include <rtems/score/timespec.h>
44#include <rtems/score/cpusetimpl.h>
45#include <rtems/score/assert.h>
46
47/*
48 *  The default pthreads attributes structure.
49 *
50 *  NOTE: Be careful .. if the default attribute set changes,
51 *        _POSIX_Threads_Initialize_user_threads will need to be examined.
52 */
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      =
61  {                           /* schedparam */
62    2,                        /* sched_priority */
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 */
67      { 0L, 0 },                /* sched_ss_init_budget */
68      0                         /* sched_ss_max_repl */
69    #endif
70  },
71
72  #if HAVE_DECL_PTHREAD_ATTR_SETGUARDSIZE
73    .guardsize = 0,                            /* guardsize */
74  #endif
75  #if defined(_POSIX_THREAD_CPUTIME)
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}}
83  #endif
84};
85
86/*
87 *  _POSIX_Threads_Sporadic_budget_TSR
88 */
89void _POSIX_Threads_Sporadic_budget_TSR(
90  Objects_Id      id __attribute__((unused)),
91  void           *argument
92)
93{
94  uint32_t            ticks;
95  uint32_t            new_priority;
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
103  /* ticks is guaranteed to be at least one */
104  ticks = _Timespec_To_ticks( &api->schedparam.sched_ss_init_budget );
105
106  the_thread->cpu_time_budget = ticks;
107
108  new_priority = _POSIX_Priority_To_core( api->schedparam.sched_priority );
109  the_thread->real_priority = new_priority;
110
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  }
129
130  /* ticks is guaranteed to be at least one */
131  ticks = _Timespec_To_ticks( &api->schedparam.sched_ss_repl_period );
132
133  _Watchdog_Insert_ticks( &api->Sporadic_timer, ticks );
134}
135
136/*
137 *  _POSIX_Threads_Sporadic_budget_callout
138 */
139void _POSIX_Threads_Sporadic_budget_callout(
140  Thread_Control *the_thread
141)
142{
143  POSIX_API_Control *api;
144  uint32_t           new_priority;
145
146  api = the_thread->API_Extensions[ THREAD_API_POSIX ];
147
148  /*
149   *  This will prevent the thread from consuming its entire "budget"
150   *  while at low priority.
151   */
152  the_thread->cpu_time_budget = UINT32_MAX;
153
154  new_priority = _POSIX_Priority_To_core(api->schedparam.sched_ss_low_priority);
155  the_thread->real_priority = new_priority;
156
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
167     *  to logically lower than sched_ss_low_priority, then we do not want to
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  }
177}
178
179/*
180 *  _POSIX_Threads_Create_extension
181 *
182 *  This method is invoked for each thread created.
183 */
184
185static bool _POSIX_Threads_Create_extension(
186  Thread_Control *executing __attribute__((unused)),
187  Thread_Control *created
188)
189{
190  POSIX_API_Control *api;
191  POSIX_API_Control *executing_api;
192
193  api = created->API_Extensions[ THREAD_API_POSIX ];
194
195  /* XXX check all fields are touched */
196  _POSIX_Threads_Initialize_attributes( &api->Attributes );
197  api->detachstate = _POSIX_Threads_Default_attributes.detachstate;
198  api->schedpolicy = _POSIX_Threads_Default_attributes.schedpolicy;
199  api->schedparam  = _POSIX_Threads_Default_attributes.schedparam;
200  api->schedparam.sched_priority =
201     _POSIX_Priority_From_core( created->current_priority );
202
203  /*
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;
209#ifndef HAVE_STRUCT__PTHREAD_CLEANUP_CONTEXT
210  _Chain_Initialize_empty (&api->Cancellation_Handlers);
211#else /* HAVE_STRUCT__PTHREAD_CLEANUP_CONTEXT */
212  api->last_cleanup_context = NULL;
213#endif /* HAVE_STRUCT__PTHREAD_CLEANUP_CONTEXT */
214
215  /*
216   *  If the thread is not a posix thread, then all posix signals are blocked
217   *  by default.
218   *
219   *  The check for class == 1 is debug.  Should never really happen.
220   */
221  api->signals_pending = SIGNAL_EMPTY_MASK;
222  if ( _Objects_Get_API( created->Object.id ) == OBJECTS_POSIX_API
223       #if defined(RTEMS_DEBUG)
224         && _Objects_Get_class( created->Object.id ) == 1
225       #endif
226  ) {
227    executing_api = _Thread_Get_executing()->API_Extensions[ THREAD_API_POSIX ];
228    api->signals_blocked = executing_api->signals_blocked;
229  } else {
230    api->signals_blocked = SIGNAL_ALL_MASK;
231  }
232
233  _Thread_Action_initialize(
234    &api->Signal_action,
235    _POSIX_signals_Action_handler
236  );
237
238  _Thread_queue_Initialize(
239    &api->Join_List,
240    THREAD_QUEUE_DISCIPLINE_FIFO,
241    STATES_WAITING_FOR_JOIN_AT_EXIT | STATES_INTERRUPTIBLE_BY_SIGNAL,
242    0
243  );
244
245  _Watchdog_Initialize(
246    &api->Sporadic_timer,
247    _POSIX_Threads_Sporadic_budget_TSR,
248    created->Object.id,
249    created
250  );
251
252  return true;
253}
254
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
264static void _POSIX_Threads_Terminate_extension(
265  Thread_Control *executing
266)
267{
268  Thread_Control     *the_thread;
269  POSIX_API_Control  *api;
270  void              **value_ptr;
271
272  api = executing->API_Extensions[ THREAD_API_POSIX ];
273
274  /*
275   *  Run the POSIX cancellation handlers
276   */
277  _POSIX_Threads_cancel_run( executing );
278
279  _Thread_Disable_dispatch();
280
281  /*
282   *  Wakeup all the tasks which joined with this one
283   */
284  value_ptr = (void **) executing->Wait.return_argument;
285
286  while ( (the_thread = _Thread_queue_Dequeue( &api->Join_List )) )
287      *(void **)the_thread->Wait.return_argument = value_ptr;
288
289  if ( api->schedpolicy == SCHED_SPORADIC )
290    (void) _Watchdog_Remove( &api->Sporadic_timer );
291
292  _Thread_Enable_dispatch();
293}
294
295/*
296 *  _POSIX_Threads_Exitted_extension
297 *
298 *  This method is invoked each time a thread exits.
299 */
300static void _POSIX_Threads_Exitted_extension(
301  Thread_Control *executing
302)
303{
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 );
310}
311
312/*
313 *  _POSIX_Threads_Initialize_user_threads
314 *
315 *  This routine creates and starts all configured user
316 *  initialization threads.
317 */
318static void _POSIX_Threads_Initialize_user_threads( void )
319{
320  if ( _POSIX_Threads_Initialize_user_threads_p )
321    (*_POSIX_Threads_Initialize_user_threads_p)();
322}
323
324/*
325 *  API Extension control structures
326 */
327API_extensions_Control _POSIX_Threads_API_extensions = {
328  #if defined(FUNCTIONALITY_NOT_CURRENTLY_USED_BY_ANY_API)
329    .predriver_hook = NULL,
330  #endif
331  .postdriver_hook = _POSIX_Threads_Initialize_user_threads
332};
333
334User_extensions_Control _POSIX_Threads_User_extensions = {
335  { NULL, NULL },
336  { { NULL, NULL }, NULL },
337  { _POSIX_Threads_Create_extension,          /* create */
338    NULL,                                     /* start */
339    _POSIX_Threads_Restart_extension,         /* restart */
340    NULL,                                     /* delete */
341    NULL,                                     /* switch */
342    NULL,                                     /* begin */
343    _POSIX_Threads_Exitted_extension,         /* exitted */
344    NULL,                                     /* fatal */
345    _POSIX_Threads_Terminate_extension        /* terminate */
346  }
347};
348
349/*
350 *  _POSIX_Threads_Manager_initialization
351 *
352 *  This routine initializes all threads manager related data structures.
353 */
354void _POSIX_Threads_Manager_initialization(void)
355{
356  #if defined(RTEMS_SMP) && defined(__RTEMS_HAVE_SYS_CPUSET_H__)
357    const CPU_set_Control *affinity;
358    pthread_attr_t *attr;
359
360    /* Initialize default attribute. */
361    attr = &_POSIX_Threads_Default_attributes;
362
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 ) );
366    attr->affinityset             = &attr->affinitysetpreallocated;
367    attr->affinitysetsize         = affinity->setsize;
368    CPU_COPY( attr->affinityset, affinity->set );
369  #endif
370
371  _Objects_Initialize_information(
372    &_POSIX_Threads_Information, /* object information table */
373    OBJECTS_POSIX_API,           /* object API */
374    OBJECTS_POSIX_THREADS,       /* object class */
375    Configuration_POSIX_API.maximum_threads,
376                                 /* maximum objects of this class */
377    _Thread_Control_size,        /* size of this object's control block */
378    true,                        /* true if names for this object are strings */
379    _POSIX_PATH_MAX              /* maximum length of each object's name */
380#if defined(RTEMS_MULTIPROCESSING)
381    ,
382    false,                       /* true if this is a global object class */
383    NULL                         /* Proxy extraction support callout */
384#endif
385  );
386
387  /*
388   *  Add all the extensions for this API
389   */
390  _User_extensions_Add_API_set( &_POSIX_Threads_User_extensions );
391
392  _API_extensions_Add( &_POSIX_Threads_API_extensions );
393
394  /*
395   *  If we supported MP, then here we would ...
396   *       Register the MP Process Packet routine.
397   */
398}
Note: See TracBrowser for help on using the repository browser.