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

5
Last change on this file since d07f582 was da826560, checked in by Sebastian Huber <sebastian.huber@…>, on 05/13/16 at 08:28:14

posix: Rework thread cancellation

Add Thread_Life_state::THREAD_LIFE_CHANGE_DEFERRED and rework the POSIX
thread cancellation to use the thread life states.

Update #2555.
Update #2626.

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