source: rtems/cpukit/posix/src/pthread.c @ 1b1be254

4.115
Last change on this file since 1b1be254 was 1b1be254, checked in by Sebastian Huber <sebastian.huber@…>, on 03/25/14 at 09:54:49

score: Thread life cycle re-implementation

The thread deletion is now supported on SMP.

This change fixes the following PRs:

PR1814: SMP race condition between stack free and dispatch

PR2035: psxcancel reveals NULL pointer access in _Thread_queue_Extract()

The POSIX cleanup handler are now called in the right context (should be
called in the context of the terminating thread).

http://pubs.opengroup.org/onlinepubs/009695399/functions/xsh_chap02_09.html

Add a user extension the reflects a thread termination event. This is
used to reclaim the Newlib reentrancy structure (may use file
operations), the POSIX cleanup handlers and the POSIX key destructors.

  • Property mode set to 100644
File size: 12.0 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
45/*
46 *  The default pthreads attributes structure.
47 *
48 *  NOTE: Be careful .. if the default attribute set changes,
49 *        _POSIX_Threads_Initialize_user_threads will need to be examined.
50 */
51pthread_attr_t _POSIX_Threads_Default_attributes = {
52  .is_initialized  = true,                       /* is_initialized */
53  .stackaddr       = NULL,                       /* stackaddr */
54  .stacksize       = 0,                          /* stacksize -- will be adjusted to minimum */
55  .contentionscope = PTHREAD_SCOPE_PROCESS,      /* contentionscope */
56  .inheritsched    = PTHREAD_INHERIT_SCHED,      /* inheritsched */
57  .schedpolicy     = SCHED_FIFO,                 /* schedpolicy */
58  .schedparam      =
59  {                           /* schedparam */
60    2,                        /* sched_priority */
61    #if defined(_POSIX_SPORADIC_SERVER) || \
62        defined(_POSIX_THREAD_SPORADIC_SERVER)
63      0,                        /* sched_ss_low_priority */
64      { 0L, 0 },                /* sched_ss_repl_period */
65      { 0L, 0 },                /* sched_ss_init_budget */
66      0                         /* sched_ss_max_repl */
67    #endif
68  },
69
70  #if HAVE_DECL_PTHREAD_ATTR_SETGUARDSIZE
71    .guardsize = 0,                            /* guardsize */
72  #endif
73  #if defined(_POSIX_THREAD_CPUTIME)
74    .cputime_clock_allowed = 1,                        /* cputime_clock_allowed */
75  #endif
76  .detachstate             = PTHREAD_CREATE_JOINABLE,    /* detachstate */
77  #if defined(__RTEMS_HAVE_SYS_CPUSET_H__)
78    .affinitysetsize         = 0,
79    .affinityset             = NULL,
80    .affinitysetpreallocated = {{0x0}}
81  #endif
82};
83
84/*
85 *  _POSIX_Threads_Sporadic_budget_TSR
86 */
87void _POSIX_Threads_Sporadic_budget_TSR(
88  Objects_Id      id __attribute__((unused)),
89  void           *argument
90)
91{
92  uint32_t            ticks;
93  uint32_t            new_priority;
94  Thread_Control     *the_thread;
95  POSIX_API_Control  *api;
96
97  the_thread = argument;
98
99  api = the_thread->API_Extensions[ THREAD_API_POSIX ];
100
101  /* ticks is guaranteed to be at least one */
102  ticks = _Timespec_To_ticks( &api->schedparam.sched_ss_init_budget );
103
104  the_thread->cpu_time_budget = ticks;
105
106  new_priority = _POSIX_Priority_To_core( api->schedparam.sched_priority );
107  the_thread->real_priority = new_priority;
108
109  /*
110   *  If holding a resource, then do not change it.
111   */
112  #if 0
113    printk( "TSR %d %d %d\n", the_thread->resource_count,
114        the_thread->current_priority, new_priority );
115  #endif
116  if ( the_thread->resource_count == 0 ) {
117    /*
118     *  If this would make them less important, then do not change it.
119     */
120    if ( the_thread->current_priority > new_priority ) {
121      _Thread_Change_priority( the_thread, new_priority, true );
122      #if 0
123        printk( "raise priority\n" );
124      #endif
125    }
126  }
127
128  /* ticks is guaranteed to be at least one */
129  ticks = _Timespec_To_ticks( &api->schedparam.sched_ss_repl_period );
130
131  _Watchdog_Insert_ticks( &api->Sporadic_timer, ticks );
132}
133
134/*
135 *  _POSIX_Threads_Sporadic_budget_callout
136 */
137void _POSIX_Threads_Sporadic_budget_callout(
138  Thread_Control *the_thread
139)
140{
141  POSIX_API_Control *api;
142  uint32_t           new_priority;
143
144  api = the_thread->API_Extensions[ THREAD_API_POSIX ];
145
146  /*
147   *  This will prevent the thread from consuming its entire "budget"
148   *  while at low priority.
149   */
150  the_thread->cpu_time_budget = UINT32_MAX;
151
152  new_priority = _POSIX_Priority_To_core(api->schedparam.sched_ss_low_priority);
153  the_thread->real_priority = new_priority;
154
155  /*
156   *  If holding a resource, then do not change it.
157   */
158  #if 0
159    printk( "callout %d %d %d\n", the_thread->resource_count,
160        the_thread->current_priority, new_priority );
161  #endif
162  if ( the_thread->resource_count == 0 ) {
163    /*
164     *  Make sure we are actually lowering it. If they have lowered it
165     *  to logically lower than sched_ss_low_priority, then we do not want to
166     *  change it.
167     */
168    if ( the_thread->current_priority < new_priority ) {
169      _Thread_Change_priority( the_thread, new_priority, true );
170      #if 0
171        printk( "lower priority\n" );
172      #endif
173    }
174  }
175}
176
177/*
178 *  _POSIX_Threads_Create_extension
179 *
180 *  This method is invoked for each thread created.
181 */
182
183static bool _POSIX_Threads_Create_extension(
184  Thread_Control *executing __attribute__((unused)),
185  Thread_Control *created
186)
187{
188  POSIX_API_Control *api;
189  POSIX_API_Control *executing_api;
190
191  api = _Workspace_Allocate( sizeof( POSIX_API_Control ) );
192
193  if ( !api )
194    return false;
195
196  created->API_Extensions[ THREAD_API_POSIX ] = api;
197
198  /* XXX check all fields are touched */
199  _POSIX_Threads_Initialize_attributes( &api->Attributes );
200  api->detachstate = _POSIX_Threads_Default_attributes.detachstate;
201  api->schedpolicy = _POSIX_Threads_Default_attributes.schedpolicy;
202  api->schedparam  = _POSIX_Threads_Default_attributes.schedparam;
203  api->schedparam.sched_priority =
204     _POSIX_Priority_From_core( created->current_priority );
205
206  /*
207   *  POSIX 1003.1 1996, 18.2.2.2
208   */
209  api->cancelation_requested = 0;
210  api->cancelability_state = PTHREAD_CANCEL_ENABLE;
211  api->cancelability_type = PTHREAD_CANCEL_DEFERRED;
212#ifndef HAVE_STRUCT__PTHREAD_CLEANUP_CONTEXT
213  _Chain_Initialize_empty (&api->Cancellation_Handlers);
214#else /* HAVE_STRUCT__PTHREAD_CLEANUP_CONTEXT */
215  api->last_cleanup_context = NULL;
216#endif /* HAVE_STRUCT__PTHREAD_CLEANUP_CONTEXT */
217
218  /*
219   *  If the thread is not a posix thread, then all posix signals are blocked
220   *  by default.
221   *
222   *  The check for class == 1 is debug.  Should never really happen.
223   */
224  api->signals_pending = SIGNAL_EMPTY_MASK;
225  if ( _Objects_Get_API( created->Object.id ) == OBJECTS_POSIX_API
226       #if defined(RTEMS_DEBUG)
227         && _Objects_Get_class( created->Object.id ) == 1
228       #endif
229  ) {
230    executing_api = _Thread_Executing->API_Extensions[ THREAD_API_POSIX ];
231    api->signals_blocked = executing_api->signals_blocked;
232  } else {
233    api->signals_blocked = SIGNAL_ALL_MASK;
234  }
235
236  _Thread_Action_initialize(
237    &api->Signal_action,
238    _POSIX_signals_Action_handler
239  );
240
241  _Thread_queue_Initialize(
242    &api->Join_List,
243    THREAD_QUEUE_DISCIPLINE_FIFO,
244    STATES_WAITING_FOR_JOIN_AT_EXIT | STATES_INTERRUPTIBLE_BY_SIGNAL,
245    0
246  );
247
248  _Watchdog_Initialize(
249    &api->Sporadic_timer,
250    _POSIX_Threads_Sporadic_budget_TSR,
251    created->Object.id,
252    created
253  );
254
255  return true;
256}
257
258static void _POSIX_Threads_Restart_extension(
259  Thread_Control *executing,
260  Thread_Control *restarted
261)
262{
263  (void) executing;
264  _POSIX_Threads_cancel_run( restarted );
265}
266
267/*
268 *  _POSIX_Threads_Delete_extension
269 *
270 *  This method is invoked for each thread deleted.
271 */
272static void _POSIX_Threads_Delete_extension(
273  Thread_Control *executing __attribute__((unused)),
274  Thread_Control *deleted
275)
276{
277  _Workspace_Free( deleted->API_Extensions[ THREAD_API_POSIX ] );
278}
279
280static void _POSIX_Threads_Terminate_extension(
281  Thread_Control *executing
282)
283{
284  Thread_Control     *the_thread;
285  POSIX_API_Control  *api;
286  void              **value_ptr;
287
288  api = executing->API_Extensions[ THREAD_API_POSIX ];
289
290  /*
291   *  Run the POSIX cancellation handlers
292   */
293  _POSIX_Threads_cancel_run( executing );
294
295  _Thread_Disable_dispatch();
296
297  /*
298   *  Wakeup all the tasks which joined with this one
299   */
300  value_ptr = (void **) executing->Wait.return_argument;
301
302  while ( (the_thread = _Thread_queue_Dequeue( &api->Join_List )) )
303      *(void **)the_thread->Wait.return_argument = value_ptr;
304
305  if ( api->schedpolicy == SCHED_SPORADIC )
306    (void) _Watchdog_Remove( &api->Sporadic_timer );
307
308  _Thread_Enable_dispatch();
309}
310
311/*
312 *  _POSIX_Threads_Exitted_extension
313 *
314 *  This method is invoked each time a thread exits.
315 */
316static void _POSIX_Threads_Exitted_extension(
317  Thread_Control *executing
318)
319{
320  /*
321   *  If the executing thread was not created with the POSIX API, then this
322   *  API do not get to define its exit behavior.
323   */
324  if ( _Objects_Get_API( executing->Object.id ) == OBJECTS_POSIX_API )
325    pthread_exit( executing->Wait.return_argument );
326}
327
328/*
329 *  _POSIX_Threads_Initialize_user_threads
330 *
331 *  This routine creates and starts all configured user
332 *  initialization threads.
333 */
334static void _POSIX_Threads_Initialize_user_threads( void )
335{
336  if ( _POSIX_Threads_Initialize_user_threads_p )
337    (*_POSIX_Threads_Initialize_user_threads_p)();
338}
339
340/*
341 *  API Extension control structures
342 */
343API_extensions_Control _POSIX_Threads_API_extensions = {
344  #if defined(FUNCTIONALITY_NOT_CURRENTLY_USED_BY_ANY_API)
345    .predriver_hook = NULL,
346  #endif
347  .postdriver_hook = _POSIX_Threads_Initialize_user_threads
348};
349
350User_extensions_Control _POSIX_Threads_User_extensions = {
351  { NULL, NULL },
352  { { NULL, NULL }, NULL },
353  { _POSIX_Threads_Create_extension,          /* create */
354    NULL,                                     /* start */
355    _POSIX_Threads_Restart_extension,         /* restart */
356    _POSIX_Threads_Delete_extension,          /* delete */
357    NULL,                                     /* switch */
358    NULL,                                     /* begin */
359    _POSIX_Threads_Exitted_extension,         /* exitted */
360    NULL,                                     /* fatal */
361    _POSIX_Threads_Terminate_extension        /* terminate */
362  }
363};
364
365/*
366 *  _POSIX_Threads_Manager_initialization
367 *
368 *  This routine initializes all threads manager related data structures.
369 */
370void _POSIX_Threads_Manager_initialization(void)
371{
372  #if defined(__RTEMS_HAVE_SYS_CPUSET_H__)
373    pthread_attr_t *attr;
374    int i;
375    int max_cpus = 1;
376
377    /* Initialize default attribute. */
378    attr = &_POSIX_Threads_Default_attributes;
379
380    /* We do not support a cpu count over CPU_SETSIZE  */
381    max_cpus = _SMP_Get_processor_count();
382    assert( max_cpus <= CPU_SETSIZE );
383
384    /*  Initialize the affinity to be the set of all available CPU's   */
385    attr->affinityset             = &attr->affinitysetpreallocated;
386    attr->affinitysetsize         = sizeof( *attr->affinityset );
387    CPU_ZERO_S( attr->affinitysetsize, &attr->affinitysetpreallocated );
388
389    for (i=0; i<max_cpus; i++)
390      CPU_SET_S(i, attr->affinitysetsize, attr->affinityset );
391  #endif
392
393  _Objects_Initialize_information(
394    &_POSIX_Threads_Information, /* object information table */
395    OBJECTS_POSIX_API,           /* object API */
396    OBJECTS_POSIX_THREADS,       /* object class */
397    Configuration_POSIX_API.maximum_threads,
398                                 /* maximum objects of this class */
399    sizeof( Thread_Control ),
400                                 /* size of this object's control block */
401    true,                        /* true if names for this object are strings */
402    _POSIX_PATH_MAX              /* maximum length of each object's name */
403#if defined(RTEMS_MULTIPROCESSING)
404    ,
405    false,                       /* true if this is a global object class */
406    NULL                         /* Proxy extraction support callout */
407#endif
408  );
409
410  /*
411   *  Add all the extensions for this API
412   */
413  _User_extensions_Add_API_set( &_POSIX_Threads_User_extensions );
414
415  _API_extensions_Add( &_POSIX_Threads_API_extensions );
416
417  /*
418   *  If we supported MP, then here we would ...
419   *       Register the MP Process Packet routine.
420   */
421}
Note: See TracBrowser for help on using the repository browser.