source: rtems/cpukit/posix/src/pthread.c @ 609e0582

4.104.115
Last change on this file since 609e0582 was a1f0ca28, checked in by Joel Sherrill <joel.sherrill@…>, on 08/19/09 at 15:18:19

2009-08-19 Joel Sherrill <joel.sherrill@…>

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