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

5
Last change on this file since f97536d was f97536d, checked in by Sebastian Huber <sebastian.huber@…>, on 10/16/15 at 06:21:48

basdefs.h: Add and use RTEMS_UNUSED

  • Property mode set to 100644
File size: 11.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/score/apiext.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/cancel.h>
37#include <rtems/posix/pthreadimpl.h>
38#include <rtems/posix/priorityimpl.h>
39#include <rtems/posix/psignalimpl.h>
40#include <rtems/posix/config.h>
41#include <rtems/posix/keyimpl.h>
42#include <rtems/score/timespec.h>
43#include <rtems/score/cpusetimpl.h>
44#include <rtems/score/assert.h>
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
85static bool _POSIX_Threads_Sporadic_budget_TSR_filter(
86  Thread_Control   *the_thread,
87  Priority_Control *new_priority,
88  void             *arg
89)
90{
91  the_thread->real_priority = *new_priority;
92
93  /*
94   * If holding a resource, then do not change it.
95   *
96   * If this would make them less important, then do not change it.
97   */
98  return !_Thread_Owns_resources( the_thread ) &&
99    _Thread_Priority_less_than( the_thread->current_priority, *new_priority );
100}
101
102/*
103 *  _POSIX_Threads_Sporadic_budget_TSR
104 */
105void _POSIX_Threads_Sporadic_budget_TSR(
106  Objects_Id      id RTEMS_UNUSED,
107  void           *argument
108)
109{
110  uint32_t            ticks;
111  Thread_Control     *the_thread;
112  POSIX_API_Control  *api;
113
114  the_thread = argument;
115
116  api = the_thread->API_Extensions[ THREAD_API_POSIX ];
117
118  /* ticks is guaranteed to be at least one */
119  ticks = _Timespec_To_ticks( &api->schedparam.sched_ss_init_budget );
120
121  the_thread->cpu_time_budget = ticks;
122
123  _Thread_Change_priority(
124    the_thread,
125    _POSIX_Priority_To_core( api->schedparam.sched_priority ),
126    NULL,
127    _POSIX_Threads_Sporadic_budget_TSR_filter,
128    true
129  );
130
131  /* ticks is guaranteed to be at least one */
132  ticks = _Timespec_To_ticks( &api->schedparam.sched_ss_repl_period );
133
134  _Watchdog_Insert_ticks( &api->Sporadic_timer, ticks );
135}
136
137static bool _POSIX_Threads_Sporadic_budget_callout_filter(
138  Thread_Control   *the_thread,
139  Priority_Control *new_priority,
140  void             *arg
141)
142{
143  the_thread->real_priority = *new_priority;
144
145  /*
146   * If holding a resource, then do not change it.
147   *
148   * Make sure we are actually lowering it. If they have lowered it
149   * to logically lower than sched_ss_low_priority, then we do not want to
150   * change it.
151   */
152  return !_Thread_Owns_resources( the_thread ) &&
153    _Thread_Priority_less_than( *new_priority, the_thread->current_priority );
154}
155
156/*
157 *  _POSIX_Threads_Sporadic_budget_callout
158 */
159void _POSIX_Threads_Sporadic_budget_callout(
160  Thread_Control *the_thread
161)
162{
163  POSIX_API_Control *api;
164
165  api = the_thread->API_Extensions[ THREAD_API_POSIX ];
166
167  /*
168   *  This will prevent the thread from consuming its entire "budget"
169   *  while at low priority.
170   */
171  the_thread->cpu_time_budget = UINT32_MAX;
172
173  _Thread_Change_priority(
174    the_thread,
175    _POSIX_Priority_To_core( api->schedparam.sched_ss_low_priority ),
176    NULL,
177    _POSIX_Threads_Sporadic_budget_callout_filter,
178    true
179  );
180}
181
182/*
183 *  _POSIX_Threads_Create_extension
184 *
185 *  This method is invoked for each thread created.
186 */
187
188static bool _POSIX_Threads_Create_extension(
189  Thread_Control *executing RTEMS_UNUSED,
190  Thread_Control *created
191)
192{
193  POSIX_API_Control *api;
194  POSIX_API_Control *executing_api;
195
196  api = created->API_Extensions[ THREAD_API_POSIX ];
197
198  /* XXX check all fields are touched */
199  _POSIX_Threads_Initialize_attributes( &api->Attributes );
200  api->detachstate = _POSIX_Threads_Default_attributes.detachstate;
201  api->schedpolicy = _POSIX_Threads_Default_attributes.schedpolicy;
202  api->schedparam  = _POSIX_Threads_Default_attributes.schedparam;
203  api->schedparam.sched_priority =
204     _POSIX_Priority_From_core( created->current_priority );
205
206  /*
207   *  POSIX 1003.1 1996, 18.2.2.2
208   */
209  api->cancelation_requested = 0;
210  api->cancelability_state = PTHREAD_CANCEL_ENABLE;
211  api->cancelability_type = PTHREAD_CANCEL_DEFERRED;
212#ifndef HAVE_STRUCT__PTHREAD_CLEANUP_CONTEXT
213  _Chain_Initialize_empty (&api->Cancellation_Handlers);
214#else /* HAVE_STRUCT__PTHREAD_CLEANUP_CONTEXT */
215  api->last_cleanup_context = NULL;
216#endif /* HAVE_STRUCT__PTHREAD_CLEANUP_CONTEXT */
217
218  /*
219   *  If the thread is not a posix thread, then all posix signals are blocked
220   *  by default.
221   *
222   *  The check for class == 1 is debug.  Should never really happen.
223   */
224  api->signals_pending = SIGNAL_EMPTY_MASK;
225  if ( _Objects_Get_API( created->Object.id ) == OBJECTS_POSIX_API
226       #if defined(RTEMS_DEBUG)
227         && _Objects_Get_class( created->Object.id ) == 1
228       #endif
229  ) {
230    executing_api = _Thread_Get_executing()->API_Extensions[ THREAD_API_POSIX ];
231    api->signals_blocked = executing_api->signals_blocked;
232  } else {
233    api->signals_blocked = SIGNAL_ALL_MASK;
234  }
235
236  _Thread_Action_initialize(
237    &api->Signal_action,
238    _POSIX_signals_Action_handler
239  );
240
241  _Thread_queue_Initialize( &api->Join_List, THREAD_QUEUE_DISCIPLINE_FIFO );
242
243  _Watchdog_Preinitialize( &api->Sporadic_timer );
244  _Watchdog_Initialize(
245    &api->Sporadic_timer,
246    _POSIX_Threads_Sporadic_budget_TSR,
247    created->Object.id,
248    created
249  );
250
251  return true;
252}
253
254static void _POSIX_Threads_Restart_extension(
255  Thread_Control *executing,
256  Thread_Control *restarted
257)
258{
259  (void) executing;
260  _POSIX_Threads_cancel_run( restarted );
261}
262
263static void _POSIX_Threads_Terminate_extension(
264  Thread_Control *executing
265)
266{
267  Thread_Control     *the_thread;
268  POSIX_API_Control  *api;
269  void              **value_ptr;
270
271  api = executing->API_Extensions[ THREAD_API_POSIX ];
272
273  /*
274   *  Run the POSIX cancellation handlers
275   */
276  _POSIX_Threads_cancel_run( executing );
277
278  _Thread_Disable_dispatch();
279
280  /*
281   *  Wakeup all the tasks which joined with this one
282   */
283  value_ptr = (void **) executing->Wait.return_argument;
284
285  while ( (the_thread = _Thread_queue_Dequeue( &api->Join_List )) )
286      *(void **)the_thread->Wait.return_argument = value_ptr;
287
288  if ( api->schedpolicy == SCHED_SPORADIC )
289    _Watchdog_Remove_ticks( &api->Sporadic_timer );
290
291  _Thread_queue_Destroy( &api->Join_List );
292
293  _Thread_Enable_dispatch();
294}
295
296/*
297 *  _POSIX_Threads_Exitted_extension
298 *
299 *  This method is invoked each time a thread exits.
300 */
301static void _POSIX_Threads_Exitted_extension(
302  Thread_Control *executing
303)
304{
305  /*
306   *  If the executing thread was not created with the POSIX API, then this
307   *  API do not get to define its exit behavior.
308   */
309  if ( _Objects_Get_API( executing->Object.id ) == OBJECTS_POSIX_API )
310    pthread_exit( executing->Wait.return_argument );
311}
312
313/*
314 *  _POSIX_Threads_Initialize_user_threads
315 *
316 *  This routine creates and starts all configured user
317 *  initialization threads.
318 */
319static void _POSIX_Threads_Initialize_user_threads( void )
320{
321  if ( _POSIX_Threads_Initialize_user_threads_p )
322    (*_POSIX_Threads_Initialize_user_threads_p)();
323}
324
325/*
326 *  API Extension control structures
327 */
328API_extensions_Control _POSIX_Threads_API_extensions = {
329  #if defined(FUNCTIONALITY_NOT_CURRENTLY_USED_BY_ANY_API)
330    .predriver_hook = NULL,
331  #endif
332  .postdriver_hook = _POSIX_Threads_Initialize_user_threads
333};
334
335User_extensions_Control _POSIX_Threads_User_extensions = {
336  { NULL, NULL },
337  { { NULL, NULL }, NULL },
338  { _POSIX_Threads_Create_extension,          /* create */
339    NULL,                                     /* start */
340    _POSIX_Threads_Restart_extension,         /* restart */
341    NULL,                                     /* delete */
342    NULL,                                     /* switch */
343    NULL,                                     /* begin */
344    _POSIX_Threads_Exitted_extension,         /* exitted */
345    NULL,                                     /* fatal */
346    _POSIX_Threads_Terminate_extension        /* terminate */
347  }
348};
349
350/*
351 *  _POSIX_Threads_Manager_initialization
352 *
353 *  This routine initializes all threads manager related data structures.
354 */
355void _POSIX_Threads_Manager_initialization(void)
356{
357  #if defined(RTEMS_SMP) && defined(__RTEMS_HAVE_SYS_CPUSET_H__)
358    const CPU_set_Control *affinity;
359    pthread_attr_t *attr;
360
361    /* Initialize default attribute. */
362    attr = &_POSIX_Threads_Default_attributes;
363
364    /*  Initialize the affinity to be the default cpu set for the system */
365    affinity = _CPU_set_Default();
366    _Assert( affinity->setsize == sizeof( attr->affinitysetpreallocated ) );
367    attr->affinityset             = &attr->affinitysetpreallocated;
368    attr->affinitysetsize         = affinity->setsize;
369    CPU_COPY( attr->affinityset, affinity->set );
370  #endif
371
372  _Thread_Initialize_information(
373    &_POSIX_Threads_Information, /* object information table */
374    OBJECTS_POSIX_API,           /* object API */
375    OBJECTS_POSIX_THREADS,       /* object class */
376    Configuration_POSIX_API.maximum_threads,
377                                 /* maximum objects of this class */
378    true,                        /* true if names for this object are strings */
379    _POSIX_PATH_MAX              /* maximum length of each object's name */
380#if defined(RTEMS_MULTIPROCESSING)
381    ,
382    false                        /* true if this is a global object class */
383#endif
384  );
385
386  /*
387   *  Add all the extensions for this API
388   */
389  _User_extensions_Add_API_set( &_POSIX_Threads_User_extensions );
390
391  _API_extensions_Add( &_POSIX_Threads_API_extensions );
392
393  /*
394   *  If we supported MP, then here we would ...
395   *       Register the MP Process Packet routine.
396   */
397}
Note: See TracBrowser for help on using the repository browser.