source: rtems/cpukit/posix/src/pthread.c @ 300f6a48

5
Last change on this file since 300f6a48 was 300f6a48, checked in by Sebastian Huber <sebastian.huber@…>, on 06/22/16 at 15:09:23

score: Rework thread priority management

Add priority nodes which contribute to the overall thread priority.

The actual priority of a thread is now an aggregation of priority nodes.
The thread priority aggregation for the home scheduler instance of a
thread consists of at least one priority node, which is normally the
real priority of the thread. The locking protocols (e.g. priority
ceiling and priority inheritance), rate-monotonic period objects and the
POSIX sporadic server add, change and remove priority nodes.

A thread changes its priority now immediately, e.g. priority changes are
not deferred until the thread releases its last resource.

Replace the _Thread_Change_priority() function with

  • _Thread_Priority_perform_actions(),
  • _Thread_Priority_add(),
  • _Thread_Priority_remove(),
  • _Thread_Priority_change(), and
  • _Thread_Priority_update().

Update #2412.
Update #2556.

  • Property mode set to 100644
File size: 8.5 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/sysinit.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/wkspace.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/score/assert.h>
41#include <rtems/score/cpusetimpl.h>
42#include <rtems/score/schedulerimpl.h>
43
44Thread_Information _POSIX_Threads_Information;
45
46/*
47 *  The default pthreads attributes structure.
48 *
49 *  NOTE: Be careful .. if the default attribute set changes,
50 *        _POSIX_Threads_Initialize_user_threads will need to be examined.
51 */
52pthread_attr_t _POSIX_Threads_Default_attributes = {
53  .is_initialized  = true,                       /* is_initialized */
54  .stackaddr       = NULL,                       /* stackaddr */
55  .stacksize       = 0,                          /* stacksize -- will be adjusted to minimum */
56  .contentionscope = PTHREAD_SCOPE_PROCESS,      /* contentionscope */
57  .inheritsched    = PTHREAD_INHERIT_SCHED,      /* inheritsched */
58  .schedpolicy     = SCHED_FIFO,                 /* schedpolicy */
59  .schedparam      =
60  {                           /* schedparam */
61    2,                        /* sched_priority */
62    #if defined(_POSIX_SPORADIC_SERVER) || \
63        defined(_POSIX_THREAD_SPORADIC_SERVER)
64      0,                        /* sched_ss_low_priority */
65      { 0L, 0 },                /* sched_ss_repl_period */
66      { 0L, 0 },                /* sched_ss_init_budget */
67      0                         /* sched_ss_max_repl */
68    #endif
69  },
70
71  #if HAVE_DECL_PTHREAD_ATTR_SETGUARDSIZE
72    .guardsize = 0,                            /* guardsize */
73  #endif
74  #if defined(_POSIX_THREAD_CPUTIME)
75    .cputime_clock_allowed = 1,                        /* cputime_clock_allowed */
76  #endif
77  .detachstate             = PTHREAD_CREATE_JOINABLE,    /* detachstate */
78  #if defined(__RTEMS_HAVE_SYS_CPUSET_H__)
79    .affinitysetsize         = 0,
80    .affinityset             = NULL,
81    .affinitysetpreallocated = {{0x0}}
82  #endif
83};
84
85void _POSIX_Threads_Sporadic_timer( Watchdog_Control *watchdog )
86{
87  POSIX_API_Control    *api;
88  Thread_Control       *the_thread;
89  Thread_queue_Context  queue_context;
90
91  api = RTEMS_CONTAINER_OF( watchdog, POSIX_API_Control, Sporadic.Timer );
92  the_thread = api->thread;
93
94  _Thread_queue_Context_clear_priority_updates( &queue_context );
95  _Thread_Wait_acquire( the_thread, &queue_context );
96
97  if ( _Priority_Node_is_active( &api->Sporadic.Low_priority ) ) {
98    _Thread_Priority_add(
99      the_thread,
100      &the_thread->Real_priority,
101      &queue_context
102    );
103    _Thread_Priority_remove(
104      the_thread,
105      &api->Sporadic.Low_priority,
106      &queue_context
107    );
108    _Priority_Node_set_inactive( &api->Sporadic.Low_priority );
109  }
110
111  _Watchdog_Per_CPU_remove_relative( &api->Sporadic.Timer );
112  _POSIX_Threads_Sporadic_timer_insert( the_thread, api );
113
114  _Thread_Wait_release( the_thread, &queue_context );
115  _Thread_Priority_update( &queue_context );
116}
117
118void _POSIX_Threads_Sporadic_budget_callout( Thread_Control *the_thread )
119{
120  POSIX_API_Control    *api;
121  Thread_queue_Context  queue_context;
122
123  api = the_thread->API_Extensions[ THREAD_API_POSIX ];
124
125  _Thread_queue_Context_clear_priority_updates( &queue_context );
126  _Thread_Wait_acquire( the_thread, &queue_context );
127
128  /*
129   *  This will prevent the thread from consuming its entire "budget"
130   *  while at low priority.
131   */
132  the_thread->cpu_time_budget = UINT32_MAX;
133
134  if ( !_Priority_Node_is_active( &api->Sporadic.Low_priority ) ) {
135    _Thread_Priority_add(
136      the_thread,
137      &api->Sporadic.Low_priority,
138      &queue_context
139    );
140    _Thread_Priority_remove(
141      the_thread,
142      &the_thread->Real_priority,
143      &queue_context
144    );
145  }
146
147  _Thread_Wait_release( the_thread, &queue_context );
148  _Thread_Priority_update( &queue_context );
149}
150
151/*
152 *  _POSIX_Threads_Create_extension
153 *
154 *  This method is invoked for each thread created.
155 */
156
157static bool _POSIX_Threads_Create_extension(
158  Thread_Control *executing RTEMS_UNUSED,
159  Thread_Control *created
160)
161{
162  POSIX_API_Control *api;
163  POSIX_API_Control *executing_api;
164
165  api = created->API_Extensions[ THREAD_API_POSIX ];
166
167  /* XXX check all fields are touched */
168  api->thread = created;
169  _POSIX_Threads_Initialize_attributes( &api->Attributes );
170  api->Attributes.schedparam.sched_priority = _POSIX_Priority_From_core(
171    _Scheduler_Get_own( created ),
172    _Thread_Get_priority( created )
173  );
174
175  /*
176   *  If the thread is not a posix thread, then all posix signals are blocked
177   *  by default.
178   *
179   *  The check for class == 1 is debug.  Should never really happen.
180   */
181  RTEMS_STATIC_ASSERT( SIGNAL_EMPTY_MASK == 0, signals_pending );
182  if ( _Objects_Get_API( created->Object.id ) == OBJECTS_POSIX_API
183       #if defined(RTEMS_DEBUG)
184         && _Objects_Get_class( created->Object.id ) == 1
185       #endif
186  ) {
187    executing_api = _Thread_Get_executing()->API_Extensions[ THREAD_API_POSIX ];
188    api->signals_unblocked = executing_api->signals_unblocked;
189  }
190
191  _Watchdog_Preinitialize( &api->Sporadic.Timer, _Per_CPU_Get_by_index( 0 ) );
192  _Watchdog_Initialize( &api->Sporadic.Timer, _POSIX_Threads_Sporadic_timer );
193
194  return true;
195}
196
197static void _POSIX_Threads_Terminate_extension( Thread_Control *executing )
198{
199  POSIX_API_Control *api;
200  ISR_lock_Context   lock_context;
201
202  api = executing->API_Extensions[ THREAD_API_POSIX ];
203
204  _Thread_State_acquire( executing, &lock_context );
205
206  if ( api->Attributes.schedpolicy == SCHED_SPORADIC ) {
207    _Watchdog_Per_CPU_remove_relative( &api->Sporadic.Timer );
208  }
209
210  _Thread_State_release( executing, &lock_context );
211}
212
213/*
214 *  _POSIX_Threads_Exitted_extension
215 *
216 *  This method is invoked each time a thread exits.
217 */
218static void _POSIX_Threads_Exitted_extension(
219  Thread_Control *executing
220)
221{
222  /*
223   *  If the executing thread was not created with the POSIX API, then this
224   *  API do not get to define its exit behavior.
225   */
226  if ( _Objects_Get_API( executing->Object.id ) == OBJECTS_POSIX_API )
227    pthread_exit( executing->Wait.return_argument );
228}
229
230User_extensions_Control _POSIX_Threads_User_extensions = {
231  .Callouts = {
232    .thread_create    = _POSIX_Threads_Create_extension,
233    .thread_exitted   = _POSIX_Threads_Exitted_extension,
234    .thread_terminate = _POSIX_Threads_Terminate_extension
235  }
236};
237
238/*
239 *  _POSIX_Threads_Manager_initialization
240 *
241 *  This routine initializes all threads manager related data structures.
242 */
243static void _POSIX_Threads_Manager_initialization(void)
244{
245  #if defined(RTEMS_SMP) && defined(__RTEMS_HAVE_SYS_CPUSET_H__)
246    const CPU_set_Control *affinity;
247    pthread_attr_t *attr;
248
249    /* Initialize default attribute. */
250    attr = &_POSIX_Threads_Default_attributes;
251
252    /*  Initialize the affinity to be the default cpu set for the system */
253    affinity = _CPU_set_Default();
254    _Assert( affinity->setsize == sizeof( attr->affinitysetpreallocated ) );
255    attr->affinityset             = &attr->affinitysetpreallocated;
256    attr->affinitysetsize         = affinity->setsize;
257    CPU_COPY( attr->affinityset, affinity->set );
258  #endif
259
260  _Thread_Initialize_information(
261    &_POSIX_Threads_Information, /* object information table */
262    OBJECTS_POSIX_API,           /* object API */
263    OBJECTS_POSIX_THREADS,       /* object class */
264    Configuration_POSIX_API.maximum_threads,
265                                 /* maximum objects of this class */
266    true,                        /* true if names for this object are strings */
267    _POSIX_PATH_MAX              /* maximum length of each object's name */
268  );
269
270  /*
271   *  Add all the extensions for this API
272   */
273  _User_extensions_Add_API_set( &_POSIX_Threads_User_extensions );
274
275  /*
276   *  If we supported MP, then here we would ...
277   *       Register the MP Process Packet routine.
278   */
279}
280
281RTEMS_SYSINIT_ITEM(
282  _POSIX_Threads_Manager_initialization,
283  RTEMS_SYSINIT_POSIX_THREADS,
284  RTEMS_SYSINIT_ORDER_MIDDLE
285);
Note: See TracBrowser for help on using the repository browser.