source: rtems/cpukit/posix/src/pthread.c @ 927a0a1

4.115
Last change on this file since 927a0a1 was 927a0a1, checked in by Sebastian Huber <sebastian.huber@…>, on 12/02/13 at 07:33:35

posix: Use cleanup contexts on the stack

Provide support for latest Newlib <pthread.h> change. The cleanup
contexts are stored on the thread stack. This is conformant with the
POSIX requirements for the pthread_cleanup_push() and
pthread_cleanup_pop() statement pair.

Passing an invalid pointer as the routine to pthread_cleanup_push() is
now a usage error and the behaviour is undefined.

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