source: rtems/cpukit/posix/src/pthread.c @ eec08ef

5
Last change on this file since eec08ef was eec08ef, checked in by Sebastian Huber <sebastian.huber@…>, on 06/15/16 at 04:59:57

posix: Rework sporadic server scheduling policy

Instead of lowering the priority in case the initial budget is consumed
raise the priority for each new period. Restore the normal priority
once the initial budget is consumed. This makes it later easier to
combine the high priority phase with temporary priority boosts (e.g. via
priority ceiling and inheritance).

Use the thread lock to protect the POSIX thread attributes instead of
the thread state lock. This makes it easier to change the thread
priority and keep the POSIX attributes consistent.

Fixes a false positive use of uninitialized variable warning.

  • 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/cpusetimpl.h>
41#include <rtems/score/assert.h>
42
43Thread_Information _POSIX_Threads_Information;
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
84static bool _POSIX_Threads_Sporadic_timer_filter(
85  Thread_Control   *the_thread,
86  Priority_Control *new_priority_p,
87  void             *arg
88)
89{
90  POSIX_API_Control *api;
91  Priority_Control   current_priority;
92  Priority_Control   new_priority;
93
94  api = arg;
95
96  new_priority = api->Sporadic.high_priority;
97  *new_priority_p = new_priority;
98
99  current_priority = the_thread->current_priority;
100  the_thread->real_priority = new_priority;
101
102  _Watchdog_Per_CPU_remove_relative( &api->Sporadic.Timer );
103  _POSIX_Threads_Sporadic_timer_insert( the_thread, api );
104
105  return _Thread_Priority_less_than( current_priority, new_priority )
106    || !_Thread_Owns_resources( the_thread );
107}
108
109static void _POSIX_Threads_Sporadic_timer( Watchdog_Control *watchdog )
110{
111  POSIX_API_Control *api;
112  Thread_Control    *the_thread;
113
114  api = RTEMS_CONTAINER_OF( watchdog, POSIX_API_Control, Sporadic.Timer );
115  the_thread = api->thread;
116
117  _Thread_Change_priority(
118    the_thread,
119    0,
120    api,
121    _POSIX_Threads_Sporadic_timer_filter,
122    true
123  );
124}
125
126static bool _POSIX_Threads_Sporadic_budget_callout_filter(
127  Thread_Control   *the_thread,
128  Priority_Control *new_priority_p,
129  void             *arg
130)
131{
132  POSIX_API_Control *api;
133  Priority_Control   current_priority;
134  Priority_Control   new_priority;
135
136  api = the_thread->API_Extensions[ THREAD_API_POSIX ];
137
138  /*
139   *  This will prevent the thread from consuming its entire "budget"
140   *  while at low priority.
141   */
142  the_thread->cpu_time_budget = UINT32_MAX;
143
144  new_priority = api->Sporadic.low_priority;
145  *new_priority_p = new_priority;
146
147  current_priority = the_thread->current_priority;
148  the_thread->real_priority = new_priority;
149
150  return _Thread_Priority_less_than( current_priority, new_priority )
151    || !_Thread_Owns_resources( the_thread );
152}
153
154void _POSIX_Threads_Sporadic_budget_callout( Thread_Control *the_thread )
155{
156  _Thread_Change_priority(
157    the_thread,
158    0,
159    NULL,
160    _POSIX_Threads_Sporadic_budget_callout_filter,
161    true
162  );
163}
164
165/*
166 *  _POSIX_Threads_Create_extension
167 *
168 *  This method is invoked for each thread created.
169 */
170
171static bool _POSIX_Threads_Create_extension(
172  Thread_Control *executing RTEMS_UNUSED,
173  Thread_Control *created
174)
175{
176  POSIX_API_Control *api;
177  POSIX_API_Control *executing_api;
178
179  api = created->API_Extensions[ THREAD_API_POSIX ];
180
181  /* XXX check all fields are touched */
182  api->thread = created;
183  _POSIX_Threads_Initialize_attributes( &api->Attributes );
184  api->Attributes.schedparam.sched_priority = _POSIX_Priority_From_core(
185    created->current_priority
186  );
187
188  /*
189   *  If the thread is not a posix thread, then all posix signals are blocked
190   *  by default.
191   *
192   *  The check for class == 1 is debug.  Should never really happen.
193   */
194  RTEMS_STATIC_ASSERT( SIGNAL_EMPTY_MASK == 0, signals_pending );
195  if ( _Objects_Get_API( created->Object.id ) == OBJECTS_POSIX_API
196       #if defined(RTEMS_DEBUG)
197         && _Objects_Get_class( created->Object.id ) == 1
198       #endif
199  ) {
200    executing_api = _Thread_Get_executing()->API_Extensions[ THREAD_API_POSIX ];
201    api->signals_unblocked = executing_api->signals_unblocked;
202  }
203
204  _Watchdog_Preinitialize( &api->Sporadic.Timer, _Per_CPU_Get_by_index( 0 ) );
205  _Watchdog_Initialize( &api->Sporadic.Timer, _POSIX_Threads_Sporadic_timer );
206
207  return true;
208}
209
210static void _POSIX_Threads_Terminate_extension( Thread_Control *executing )
211{
212  POSIX_API_Control *api;
213  ISR_lock_Context   lock_context;
214
215  api = executing->API_Extensions[ THREAD_API_POSIX ];
216
217  _Thread_State_acquire( executing, &lock_context );
218
219  if ( api->Attributes.schedpolicy == SCHED_SPORADIC ) {
220    _Watchdog_Per_CPU_remove_relative( &api->Sporadic.Timer );
221  }
222
223  _Thread_State_release( executing, &lock_context );
224}
225
226/*
227 *  _POSIX_Threads_Exitted_extension
228 *
229 *  This method is invoked each time a thread exits.
230 */
231static void _POSIX_Threads_Exitted_extension(
232  Thread_Control *executing
233)
234{
235  /*
236   *  If the executing thread was not created with the POSIX API, then this
237   *  API do not get to define its exit behavior.
238   */
239  if ( _Objects_Get_API( executing->Object.id ) == OBJECTS_POSIX_API )
240    pthread_exit( executing->Wait.return_argument );
241}
242
243User_extensions_Control _POSIX_Threads_User_extensions = {
244  .Callouts = {
245    .thread_create    = _POSIX_Threads_Create_extension,
246    .thread_exitted   = _POSIX_Threads_Exitted_extension,
247    .thread_terminate = _POSIX_Threads_Terminate_extension
248  }
249};
250
251/*
252 *  _POSIX_Threads_Manager_initialization
253 *
254 *  This routine initializes all threads manager related data structures.
255 */
256static void _POSIX_Threads_Manager_initialization(void)
257{
258  #if defined(RTEMS_SMP) && defined(__RTEMS_HAVE_SYS_CPUSET_H__)
259    const CPU_set_Control *affinity;
260    pthread_attr_t *attr;
261
262    /* Initialize default attribute. */
263    attr = &_POSIX_Threads_Default_attributes;
264
265    /*  Initialize the affinity to be the default cpu set for the system */
266    affinity = _CPU_set_Default();
267    _Assert( affinity->setsize == sizeof( attr->affinitysetpreallocated ) );
268    attr->affinityset             = &attr->affinitysetpreallocated;
269    attr->affinitysetsize         = affinity->setsize;
270    CPU_COPY( attr->affinityset, affinity->set );
271  #endif
272
273  _Thread_Initialize_information(
274    &_POSIX_Threads_Information, /* object information table */
275    OBJECTS_POSIX_API,           /* object API */
276    OBJECTS_POSIX_THREADS,       /* object class */
277    Configuration_POSIX_API.maximum_threads,
278                                 /* maximum objects of this class */
279    true,                        /* true if names for this object are strings */
280    _POSIX_PATH_MAX              /* maximum length of each object's name */
281  );
282
283  /*
284   *  Add all the extensions for this API
285   */
286  _User_extensions_Add_API_set( &_POSIX_Threads_User_extensions );
287
288  /*
289   *  If we supported MP, then here we would ...
290   *       Register the MP Process Packet routine.
291   */
292}
293
294RTEMS_SYSINIT_ITEM(
295  _POSIX_Threads_Manager_initialization,
296  RTEMS_SYSINIT_POSIX_THREADS,
297  RTEMS_SYSINIT_ORDER_MIDDLE
298);
Note: See TracBrowser for help on using the repository browser.