source: rtems/c/src/exec/posix/src/pthread.c @ 3335420

4.104.114.84.95
Last change on this file since 3335420 was 3335420, checked in by Joel Sherrill <joel.sherrill@…>, on 09/08/96 at 16:22:05

moved PTHREAD_MINIMUM_STACK_SIZE from pthread.c to pthread.h so it would be
visible to other files.

  • Property mode set to 100644
File size: 28.8 KB
Line 
1/*
2 *  $Id$
3 */
4
5#include <assert.h>
6#include <errno.h>
7#include <pthread.h>
8#include <limits.h>
9
10#include <rtems/system.h>
11#include <rtems/score/apiext.h>
12#include <rtems/score/stack.h>
13#include <rtems/score/thread.h>
14#include <rtems/score/userext.h>
15#include <rtems/score/wkspace.h>
16#include <rtems/posix/pthread.h>
17#include <rtems/posix/priority.h>
18#include <rtems/posix/psignal.h>
19#include <rtems/posix/config.h>
20#include <rtems/posix/key.h>
21#include <rtems/posix/time.h>
22
23/*PAGE
24 *
25 *  The default pthreads attributes structure.
26 *
27 *  NOTE: Be careful .. if the default attribute set changes,
28 *        _POSIX_Threads_Initialize_user_threads will need to be examined.
29 *
30 */
31 
32const pthread_attr_t _POSIX_Threads_Default_attributes = {
33  TRUE,                       /* is_initialized */
34  NULL,                       /* stackaddr */
35  PTHREAD_MINIMUM_STACK_SIZE, /* stacksize */
36  PTHREAD_SCOPE_PROCESS,      /* contentionscope */
37  PTHREAD_INHERIT_SCHED,      /* inheritsched */
38  SCHED_FIFO,                 /* schedpolicy */
39  {                           /* schedparam */
40    2,                        /* sched_priority */
41    0,                        /* ss_low_priority */
42    { 0L, 0 },                /* ss_replenish_period */
43    { 0L, 0 }                 /* ss_initial_budget */
44  },
45  PTHREAD_CREATE_JOINABLE,    /* detachstate */
46  1                           /* cputime_clock_allowed */
47};
48
49/*PAGE
50 *
51 *  _POSIX_Threads_Sporadic_budget_TSR
52 */
53
54void _POSIX_Threads_Sporadic_budget_TSR(
55  Objects_Id      id,
56  void           *argument
57)
58{
59  unsigned32          ticks;
60  unsigned32          new_priority;
61  Thread_Control     *the_thread;
62  POSIX_API_Control  *api;
63
64  the_thread = argument;
65
66  api = the_thread->API_Extensions[ THREAD_API_POSIX ];
67
68  ticks = _POSIX_Timespec_to_interval( &api->schedparam.ss_initial_budget );
69
70  if ( !ticks )
71    ticks = 1;
72
73  the_thread->cpu_time_budget = ticks;
74 
75  new_priority = _POSIX_Priority_To_core( api->ss_high_priority );
76  the_thread->real_priority = new_priority;
77
78  if ( the_thread->resource_count == 0 ||
79       the_thread->current_priority > new_priority )
80    _Thread_Change_priority( the_thread, new_priority );
81
82  ticks = _POSIX_Timespec_to_interval( &api->schedparam.ss_replenish_period );
83
84  if ( !ticks )
85    ticks = 1;
86
87  _Watchdog_Insert_ticks( &api->Sporadic_timer, ticks );
88}
89
90/*PAGE
91 *
92 *  _POSIX_Threads_Sporadic_budget_callout
93 */
94
95void _POSIX_Threads_Sporadic_budget_callout(
96  Thread_Control *the_thread
97)
98{
99  POSIX_API_Control *api;
100  unsigned32         new_priority;
101
102  api = the_thread->API_Extensions[ THREAD_API_POSIX ];
103
104  /*
105   *  This will prevent the thread from consuming its entire "budget"
106   *  while at low priority.
107   */
108
109
110  the_thread->cpu_time_budget = 0xFFFFFFFF; /* XXX should be based on MAX_U32 */
111
112  new_priority = _POSIX_Priority_To_core( api->schedparam.ss_low_priority );
113  the_thread->real_priority = new_priority;
114
115 if ( the_thread->resource_count == 0 ||
116      the_thread->current_priority > new_priority )
117    _Thread_Change_priority( the_thread, new_priority );
118}
119
120/*PAGE
121 *
122 *  _POSIX_Threads_Create_extension
123 *
124 *  XXX
125 */
126 
127boolean _POSIX_Threads_Create_extension(
128  Thread_Control *executing,
129  Thread_Control *created
130)
131{
132  POSIX_API_Control *api;
133  POSIX_API_Control *executing_api;
134 
135  api = _Workspace_Allocate( sizeof( POSIX_API_Control ) );
136 
137  if ( !api )
138    return FALSE;
139 
140  created->API_Extensions[ THREAD_API_POSIX ] = api;
141 
142  /* XXX check all fields are touched */
143  api->Attributes  = _POSIX_Threads_Default_attributes;
144  api->detachstate = _POSIX_Threads_Default_attributes.detachstate;
145  api->schedpolicy = _POSIX_Threads_Default_attributes.schedpolicy;
146  api->schedparam  = _POSIX_Threads_Default_attributes.schedparam;
147  api->schedparam.sched_priority =
148     _POSIX_Priority_From_core( created->current_priority );
149 
150  /*
151   *  If the thread is not a posix thread, then all posix signals are blocked
152   *  by default.
153   */
154
155  /* XXX use signal constants */
156  api->signals_pending = 0;
157  if ( _Objects_Get_class( created->Object.id ) == OBJECTS_POSIX_THREADS ) {
158    executing_api = _Thread_Executing->API_Extensions[ THREAD_API_POSIX ];
159    api->signals_blocked = api->signals_blocked;
160  } else
161    api->signals_blocked = 0xffffffff;
162
163/* XXX set signal parameters -- block all signals for non-posix threads */
164
165  _Thread_queue_Initialize(
166    &api->Join_List,
167    OBJECTS_NO_CLASS,                 /* only used for proxy operations */
168    THREAD_QUEUE_DISCIPLINE_FIFO,
169    STATES_WAITING_FOR_JOIN_AT_EXIT,
170    NULL,                             /* no extract proxy handler */
171    0
172  );
173 
174  _Watchdog_Initialize(
175    &api->Sporadic_timer,
176    _POSIX_Threads_Sporadic_budget_TSR,
177    created->Object.id,
178    created
179  );
180
181  return TRUE;
182}
183
184/*PAGE
185 *
186 *  _POSIX_Threads_Delete_extension
187 */
188 
189User_extensions_routine _POSIX_Threads_Delete_extension(
190  Thread_Control *executing,
191  Thread_Control *deleted
192)
193{
194  Thread_Control     *the_thread;
195  POSIX_API_Control  *api;
196  void              **value_ptr;
197
198  api = deleted->API_Extensions[ THREAD_API_POSIX ];
199 
200  /* XXX run cancellation handlers */
201
202  _POSIX_Keys_Run_destructors( deleted );
203
204  /*
205   *  Wakeup all the tasks which joined with this one
206   */
207 
208  value_ptr = (void **) deleted->Wait.return_argument;
209
210  while ( (the_thread = _Thread_queue_Dequeue( &api->Join_List )) )
211      *(void **)the_thread->Wait.return_argument = value_ptr;
212 
213  if ( api->schedpolicy == SCHED_SPORADIC )
214    (void) _Watchdog_Remove( &api->Sporadic_timer );
215
216  deleted->API_Extensions[ THREAD_API_POSIX ] = NULL;
217
218  (void) _Workspace_Free( api );
219}
220
221/*PAGE
222 *
223 *  _POSIX_Threads_Initialize_user_threads
224 *
225 *  This routine creates and starts all configured user
226 *  initialzation threads.
227 *
228 *  Input parameters: NONE
229 *
230 *  Output parameters:  NONE
231 */
232 
233void _POSIX_Threads_Initialize_user_threads( void )
234{
235  int                                 status;
236  unsigned32                          index;
237  unsigned32                          maximum;
238  posix_initialization_threads_table *user_threads;
239  pthread_t                           thread_id;
240  pthread_attr_t                      attr;
241 
242  user_threads = _POSIX_Threads_User_initialization_threads;
243  maximum      = _POSIX_Threads_Number_of_initialization_threads;
244
245  if ( !user_threads || maximum == 0 )
246    return;
247 
248  /*
249   *  Be careful .. if the default attribute set changes, this may need to.
250   *
251   *  Setting the attributes explicitly is critical, since we don't want
252   *  to inherit the idle tasks attributes.
253   */
254
255  for ( index=0 ; index < maximum ; index++ ) {
256    status = pthread_attr_init( &attr );
257    assert( !status );
258     
259    status = pthread_attr_setinheritsched( &attr, PTHREAD_EXPLICIT_SCHED );
260    assert( !status );
261
262    status = pthread_create(
263      &thread_id,
264      &attr,
265      user_threads[ index ].entry,
266      NULL
267    );
268    assert( !status );
269  }
270}
271
272/*PAGE
273 *
274 *  API Extension control structures
275 */
276
277API_extensions_Control _POSIX_Threads_API_extensions = {
278  { NULL, NULL },
279  NULL,                                     /* predriver */
280  _POSIX_Threads_Initialize_user_threads,   /* postdriver */
281  _POSIX_signals_Post_switch_extension,     /* post switch */
282};
283 
284User_extensions_Control _POSIX_Threads_User_extensions = {
285  { NULL, NULL },
286  { _POSIX_Threads_Create_extension,          /* create */
287    NULL,                                     /* start */
288    NULL,                                     /* restart */
289    _POSIX_Threads_Delete_extension,          /* delete */
290    NULL,                                     /* switch */
291    NULL,                                     /* begin */
292    NULL,                                     /* exitted */
293    NULL                                      /* fatal */
294  }
295};
296 
297/*PAGE
298 *
299 *  _POSIX_Threads_Manager_initialization
300 *
301 *  This routine initializes all threads manager related data structures.
302 *
303 *  Input parameters:
304 *    maximum_pthreads - maximum configured pthreads
305 *
306 *  Output parameters:  NONE
307 */
308 
309void _POSIX_Threads_Manager_initialization(
310  unsigned32                          maximum_pthreads,
311  unsigned32                          number_of_initialization_threads,
312  posix_initialization_threads_table *user_threads
313 
314)
315{
316  _POSIX_Threads_Number_of_initialization_threads =
317                                           number_of_initialization_threads;
318  _POSIX_Threads_User_initialization_threads = user_threads;
319
320  /*
321   *  There may not be any POSIX initialization threads configured.
322   */
323
324#if 0
325  if ( user_threads == NULL || number_of_initialization_threads == 0 )
326    _Internal_error_Occurred( INTERNAL_ERROR_POSIX_API, TRUE, EINVAL );
327#endif
328
329  _Objects_Initialize_information(
330    &_POSIX_Threads_Information,
331    OBJECTS_POSIX_THREADS,
332    FALSE,                               /* does not support global */
333    maximum_pthreads,
334    sizeof( Thread_Control ),
335    TRUE,
336    5,                                   /* length is arbitrary for now */
337    TRUE                                 /* this class is threads */
338  );
339
340  /*
341   *  Add all the extensions for this API
342   */
343 
344  _User_extensions_Add_API_set( &_POSIX_Threads_User_extensions );
345 
346  _API_extensions_Add( &_POSIX_Threads_API_extensions );
347 
348  /*
349   *  If we supported MP, then here we would ...
350   *       Register the MP Process Packet routine.
351   */
352 
353}
354
355/*PAGE
356 *
357 *  3.1.3 Register Fork Handlers, P1003.1c/Draft 10, P1003.1c/Draft 10, p. 27
358 *
359 *  RTEMS does not support processes, so we fall under this and do not
360 *  provide this routine:
361 *
362 *  "Either the implementation shall support the pthread_atfork() function
363 *   as described above or the pthread_atfork() funciton shall not be
364 *   provided."
365 */
366
367/*PAGE
368 *
369 *  13.5.1 Thread Creation Scheduling Attributes, P1003.1c/Draft 10, p. 120
370 */
371
372int pthread_attr_setscope(
373  pthread_attr_t  *attr,
374  int              contentionscope
375)
376{
377  if ( !attr || !attr->is_initialized )
378    return EINVAL;
379
380  switch ( contentionscope ) {
381    case PTHREAD_SCOPE_PROCESS:
382      attr->contentionscope = contentionscope;
383      return 0;
384
385    case PTHREAD_SCOPE_SYSTEM:
386      return ENOTSUP;
387
388    default:
389      return EINVAL;
390  }
391}
392
393/*PAGE
394 *
395 *  13.5.1 Thread Creation Scheduling Attributes, P1003.1c/Draft 10, p. 120
396 */
397
398int pthread_attr_getscope(
399  const pthread_attr_t  *attr,
400  int                   *contentionscope
401)
402{
403  if ( !attr || !attr->is_initialized || !contentionscope )
404    return EINVAL;
405
406  *contentionscope = attr->contentionscope;
407  return 0;
408}
409
410/*PAGE
411 *
412 *  13.5.1 Thread Creation Scheduling Attributes, P1003.1c/Draft 10, p. 120
413 */
414
415int pthread_attr_setinheritsched(
416  pthread_attr_t  *attr,
417  int              inheritsched
418)
419{
420  if ( !attr || !attr->is_initialized )
421    return EINVAL;
422
423  switch ( inheritsched ) {
424    case PTHREAD_INHERIT_SCHED:
425    case PTHREAD_EXPLICIT_SCHED:
426      attr->inheritsched = inheritsched;
427      return 0;
428
429    default:
430      return ENOTSUP;
431  }
432}
433
434/*PAGE
435 *
436 *  13.5.1 Thread Creation Scheduling Attributes, P1003.1c/Draft 10, p. 120
437 */
438
439int pthread_attr_getinheritsched(
440  const pthread_attr_t  *attr,
441  int                   *inheritsched
442)
443{
444  if ( !attr || !attr->is_initialized || !inheritsched )
445    return EINVAL;
446
447  *inheritsched = attr->inheritsched;
448  return 0;
449}
450
451/*PAGE
452 *
453 *  13.5.1 Thread Creation Scheduling Attributes, P1003.1c/Draft 10, p. 120
454 */
455
456int pthread_attr_setschedpolicy(
457  pthread_attr_t  *attr,
458  int              policy
459)
460{
461  if ( !attr || !attr->is_initialized )
462    return EINVAL;
463
464  switch ( policy ) {
465    case SCHED_OTHER:
466    case SCHED_FIFO:
467    case SCHED_RR:
468    case SCHED_SPORADIC:
469      attr->schedpolicy = policy;
470      return 0;
471 
472    default:
473      return ENOTSUP;
474  }
475}
476
477/*PAGE
478 *
479 *  13.5.1 Thread Creation Scheduling Parameters, P1003.1c/Draft 10, p. 120
480 */
481
482int pthread_attr_getschedpolicy(
483  const pthread_attr_t  *attr,
484  int                   *policy
485)
486{
487  if ( !attr || !attr->is_initialized || !policy )
488    return EINVAL;
489
490  *policy = attr->schedpolicy;
491  return 0;
492}
493
494/*PAGE
495 *
496 *  13.5.1 Thread Creation Scheduling Parameters, P1003.1c/Draft 10, p. 120
497 */
498
499int pthread_attr_setschedparam(
500  pthread_attr_t           *attr,
501  const struct sched_param *param
502)
503{
504  if ( !attr || !attr->is_initialized || !param )
505    return EINVAL;
506
507  attr->schedparam = *param;
508  return 0;
509}
510
511/*PAGE
512 *
513 *  13.5.1 Thread Creation Scheduling Attributes, P1003.1c/Draft 10, p. 120
514 */
515
516int pthread_attr_getschedparam(
517  const pthread_attr_t   *attr,
518  struct sched_param     *param
519)
520{
521  if ( !attr || !attr->is_initialized || !param )
522    return EINVAL;
523
524  *param = attr->schedparam;
525  return 0;
526}
527
528/*PAGE
529 *
530 *  13.5.2 Dynamic Thread Scheduling Parameters Access,
531 *         P1003.1c/Draft 10, p. 124
532 */
533
534int pthread_getschedparam(
535  pthread_t           thread,
536  int                *policy,
537  struct sched_param *param
538)
539{
540  Objects_Locations        location;
541  POSIX_API_Control       *api;
542  register Thread_Control *the_thread;
543
544  if ( !policy || !param  )
545    return EINVAL;
546
547  the_thread = _POSIX_Threads_Get( thread, &location );
548  switch ( location ) {
549    case OBJECTS_ERROR:
550    case OBJECTS_REMOTE:
551      return ESRCH;
552    case OBJECTS_LOCAL:
553      api = the_thread->API_Extensions[ THREAD_API_POSIX ];
554      *policy = api->schedpolicy;
555      *param  = api->schedparam;
556      param->sched_priority =
557        _POSIX_Priority_From_core( the_thread->current_priority );
558      _Thread_Enable_dispatch();
559      return 0;
560  }
561 
562  return POSIX_BOTTOM_REACHED();
563
564}
565
566/*PAGE
567 *
568 *  13.5.2 Dynamic Thread Scheduling Parameters Access,
569 *         P1003.1c/Draft 10, p. 124
570 */
571
572int pthread_setschedparam(
573  pthread_t           thread,
574  int                 policy,
575  struct sched_param *param
576)
577{
578  register Thread_Control             *the_thread;
579  POSIX_API_Control                   *api;
580  Thread_CPU_budget_algorithms         budget_algorithm;
581  Thread_CPU_budget_algorithm_callout  budget_callout;
582  Objects_Locations                    location;
583 
584  /*
585   *  Check all the parameters
586   */
587
588  if ( !param )
589    return EINVAL;
590
591  if ( !_POSIX_Priority_Is_valid( param->sched_priority ) )
592    return EINVAL;
593
594  budget_algorithm = THREAD_CPU_BUDGET_ALGORITHM_NONE;
595  budget_callout = NULL;
596
597  switch ( policy ) {
598    case SCHED_OTHER:
599      budget_algorithm = THREAD_CPU_BUDGET_ALGORITHM_RESET_TIMESLICE;
600      break;
601 
602    case SCHED_FIFO:
603      budget_algorithm = THREAD_CPU_BUDGET_ALGORITHM_NONE;
604      break;
605 
606    case SCHED_RR:
607      budget_algorithm = THREAD_CPU_BUDGET_ALGORITHM_EXHAUST_TIMESLICE;
608      break;
609 
610    case SCHED_SPORADIC:
611      budget_algorithm  = THREAD_CPU_BUDGET_ALGORITHM_CALLOUT;
612      budget_callout = _POSIX_Threads_Sporadic_budget_callout;
613 
614      if ( _POSIX_Timespec_to_interval( &param->ss_replenish_period ) <
615           _POSIX_Timespec_to_interval( &param->ss_initial_budget ) )
616        return EINVAL;
617 
618      if ( !_POSIX_Priority_Is_valid( param->ss_low_priority ) )
619        return EINVAL;
620 
621      break;
622 
623    default:
624      return EINVAL;
625  }
626
627  /*
628   *  Actually change the scheduling policy and parameters
629   */
630
631  the_thread = _POSIX_Threads_Get( thread, &location );
632  switch ( location ) {
633    case OBJECTS_ERROR:
634    case OBJECTS_REMOTE:
635      return ESRCH;
636    case OBJECTS_LOCAL:
637      api = the_thread->API_Extensions[ THREAD_API_POSIX ];
638
639      if ( api->schedpolicy == SCHED_SPORADIC )
640        (void) _Watchdog_Remove( &api->Sporadic_timer );
641
642      api->schedpolicy = policy;
643      api->schedparam  = *param;
644      the_thread->budget_algorithm = budget_algorithm;
645      the_thread->budget_callout   = budget_callout;
646
647      switch ( api->schedpolicy ) {
648        case SCHED_OTHER:
649        case SCHED_FIFO:
650        case SCHED_RR:
651          the_thread->cpu_time_budget = _Thread_Ticks_per_timeslice;
652
653          the_thread->real_priority =
654            _POSIX_Priority_To_core( api->schedparam.sched_priority );
655
656          _Thread_Change_priority( the_thread, the_thread->real_priority );
657          break;
658 
659        case SCHED_SPORADIC:
660          api->ss_high_priority = api->schedparam.sched_priority;
661          _POSIX_Threads_Sporadic_budget_TSR( 0, the_thread );
662          break;
663      }
664
665      _Thread_Enable_dispatch();
666      return 0;
667  }
668  return POSIX_BOTTOM_REACHED();
669}
670
671/*PAGE
672 *
673 *  16.1.1 Thread Creation Attributes, P1003.1c/Draft 10, p, 140
674 */
675
676int pthread_attr_init(
677  pthread_attr_t  *attr
678)
679{
680  if ( !attr )
681    return EINVAL;
682 
683  *attr = _POSIX_Threads_Default_attributes;
684  return 0;
685}
686
687/*PAGE
688 *
689 *  16.1.1 Thread Creation Attributes, P1003.1c/Draft 10, p, 140
690 */
691
692int pthread_attr_destroy(
693  pthread_attr_t  *attr
694)
695{
696  if ( !attr || !attr->is_initialized )
697    return EINVAL;
698 
699  attr->is_initialized = FALSE;
700  return 0;
701}
702 
703/*PAGE
704 *
705 *  16.1.1 Thread Creation Attributes, P1003.1c/Draft 10, p, 140
706 */
707
708int pthread_attr_getstacksize(
709  const pthread_attr_t  *attr,
710  size_t                *stacksize
711)
712{
713  if ( !attr || !attr->is_initialized || !stacksize )
714    return EINVAL;
715
716  *stacksize = attr->stacksize;
717  return 0;
718}
719 
720/*PAGE
721 *
722 *  16.1.1 Thread Creation Attributes, P1003.1c/Draft 10, p, 140
723 */
724
725int pthread_attr_setstacksize(
726  pthread_attr_t  *attr,
727  size_t           stacksize
728)
729{
730  if ( !attr || !attr->is_initialized )
731    return EINVAL;
732
733  if (stacksize < PTHREAD_MINIMUM_STACK_SIZE)
734    attr->stacksize = PTHREAD_MINIMUM_STACK_SIZE;
735  else
736    attr->stacksize = stacksize;
737  return 0;
738}
739 
740/*PAGE
741 *
742 *  16.1.1 Thread Creation Attributes, P1003.1c/Draft 10, p, 140
743 */
744
745int pthread_attr_getstackaddr(
746  const pthread_attr_t   *attr,
747  void                  **stackaddr
748)
749{
750  if ( !attr || !attr->is_initialized || !stackaddr )
751    return EINVAL;
752
753  *stackaddr = attr->stackaddr;
754  return 0;
755}
756 
757/*PAGE
758 *
759 *  16.1.1 Thread Creation Attributes, P1003.1c/Draft 10, p, 140
760 */
761
762int pthread_attr_setstackaddr(
763  pthread_attr_t  *attr,
764  void            *stackaddr
765)
766{
767  if ( !attr || !attr->is_initialized )
768    return EINVAL;
769
770  attr->stackaddr = stackaddr;
771  return 0;
772}
773 
774/*PAGE
775 *
776 *  16.1.1 Thread Creation Attributes, P1003.1c/Draft 10, p, 140
777 */
778
779int pthread_attr_getdetachstate(
780  const pthread_attr_t  *attr,
781  int                   *detachstate
782)
783{
784  if ( !attr || !attr->is_initialized || !detachstate )
785    return EINVAL;
786
787  *detachstate = attr->detachstate;
788  return 0;
789}
790 
791/*PAGE
792 *
793 *  16.1.1 Thread Creation Attributes, P1003.1c/Draft 10, p, 140
794 */
795
796int pthread_attr_setdetachstate(
797  pthread_attr_t  *attr,
798  int              detachstate
799)
800{
801  if ( !attr || !attr->is_initialized )
802    return EINVAL;
803
804  switch ( detachstate ) {
805    case PTHREAD_CREATE_DETACHED:
806    case PTHREAD_CREATE_JOINABLE:
807      attr->detachstate = detachstate;
808      return 0;
809 
810    default:
811      return EINVAL;
812  }
813}
814
815/*PAGE
816 *
817 *  16.1.2 Thread Creation, P1003.1c/Draft 10, p. 144
818 */
819
820int pthread_create(
821  pthread_t              *thread,
822  const pthread_attr_t   *attr,
823  void                 *(*start_routine)( void * ),
824  void                   *arg
825)
826{
827  const pthread_attr_t               *the_attr;
828  Priority_Control                    core_priority;
829  Thread_CPU_budget_algorithms        budget_algorithm;
830  Thread_CPU_budget_algorithm_callout budget_callout;
831  boolean                             is_fp;
832  boolean                             status;
833  Thread_Control                     *the_thread;
834  char                               *default_name = "psx";
835  POSIX_API_Control                  *api;
836  int                                 schedpolicy = SCHED_RR;
837  struct sched_param                  schedparam;
838
839  the_attr = (attr) ? attr : &_POSIX_Threads_Default_attributes;
840
841  if ( !the_attr->is_initialized )
842    return EINVAL;
843
844  /*
845   *  Core Thread Initialize insures we get the minimum amount of
846   *  stack space if it is allowed to allocate it itself.
847   */
848
849  if ( the_attr->stackaddr && !_Stack_Is_enough( the_attr->stacksize ) )
850    return EINVAL;
851
852#if 0
853  int  cputime_clock_allowed;  /* see time.h */
854  POSIX_NOT_IMPLEMENTED();
855#endif
856
857  /*
858   *  P1003.1c/Draft 10, p. 121.
859   *
860   *  If inheritsched is set to PTHREAD_INHERIT_SCHED, then this thread
861   *  inherits scheduling attributes from the creating thread.   If it is
862   *  PTHREAD_EXPLICIT_SCHED, then scheduling parameters come from the
863   *  attributes structure.
864   */
865
866  switch ( the_attr->inheritsched ) {
867    case PTHREAD_INHERIT_SCHED:
868      api = _Thread_Executing->API_Extensions[ THREAD_API_POSIX ];
869      schedpolicy = api->schedpolicy;
870      schedparam  = api->schedparam;
871      break;
872
873    case PTHREAD_EXPLICIT_SCHED:
874      schedpolicy = the_attr->schedpolicy;
875      schedparam  = the_attr->schedparam;
876      break;
877
878    default:
879      return EINVAL;
880  }
881
882  /*
883   *  Check the contentionscope since rtems only supports PROCESS wide
884   *  contention (i.e. no system wide contention).
885   */
886
887  if ( the_attr->contentionscope != PTHREAD_SCOPE_PROCESS )
888    return ENOTSUP;
889
890  /*
891   *  Interpret the scheduling parameters.
892   */
893
894  if ( !_POSIX_Priority_Is_valid( schedparam.sched_priority ) )
895    return EINVAL;
896 
897  core_priority = _POSIX_Priority_To_core( schedparam.sched_priority );
898 
899  /*
900   *  Set the core scheduling policy information.
901   */
902
903  budget_callout = NULL;
904  budget_algorithm = THREAD_CPU_BUDGET_ALGORITHM_NONE;
905
906  switch ( schedpolicy ) {
907    case SCHED_OTHER:
908      budget_algorithm = THREAD_CPU_BUDGET_ALGORITHM_RESET_TIMESLICE;
909      break;
910     
911    case SCHED_FIFO:
912      budget_algorithm = THREAD_CPU_BUDGET_ALGORITHM_NONE;
913      break;
914
915    case SCHED_RR:
916      budget_algorithm = THREAD_CPU_BUDGET_ALGORITHM_EXHAUST_TIMESLICE;
917      break;
918
919    case SCHED_SPORADIC:
920      budget_algorithm  = THREAD_CPU_BUDGET_ALGORITHM_CALLOUT;
921      budget_callout = _POSIX_Threads_Sporadic_budget_callout;
922 
923      if ( _POSIX_Timespec_to_interval( &schedparam.ss_replenish_period ) <
924           _POSIX_Timespec_to_interval( &schedparam.ss_initial_budget ) )
925        return EINVAL;
926
927      if ( !_POSIX_Priority_Is_valid( schedparam.ss_low_priority ) )
928        return EINVAL;
929
930      break;
931
932    default:
933      return EINVAL;
934  }
935
936  /*
937   *  Currently all POSIX threads are floating point if the hardware
938   *  supports it.
939   */
940
941  is_fp = CPU_HARDWARE_FP;
942
943  /*
944   *  Disable dispatch for protection
945   */
946 
947  _Thread_Disable_dispatch();
948 
949  /*
950   *  Allocate the thread control block.
951   *
952   *  NOTE:  Global threads are not currently supported.
953   */
954
955  the_thread = _POSIX_Threads_Allocate();
956
957  if ( !the_thread ) {
958    _Thread_Enable_dispatch();
959    return EAGAIN;
960  }
961
962  /*
963   *  Initialize the core thread for this task.
964   */
965 
966  status = _Thread_Initialize(
967    &_POSIX_Threads_Information,
968    the_thread,
969    the_attr->stackaddr,
970    the_attr->stacksize,
971    is_fp,
972    core_priority,
973    TRUE,                 /* preemptible */
974    budget_algorithm,
975    budget_callout,
976    0,                    /* isr level */
977    &default_name         /* posix threads don't have a name */
978  );
979 
980  if ( !status ) {
981    _POSIX_Threads_Free( the_thread );
982    _Thread_Enable_dispatch();
983    return EAGAIN;
984  }
985
986  /*
987   *  finish initializing the per API structure
988   */
989
990 
991  api = the_thread->API_Extensions[ THREAD_API_POSIX ];
992
993  api->Attributes  = *the_attr;
994  api->detachstate = attr->detachstate;
995  api->schedpolicy = schedpolicy;
996  api->schedparam  = schedparam;
997
998  /*
999   *  This insures we evaluate the process-wide signals pending when we
1000   *  first run.
1001   *
1002   *  NOTE:  Since the thread starts with all unblocked, this is necessary.
1003   */
1004
1005  the_thread->do_post_task_switch_extension = TRUE;
1006
1007  /*
1008   *  POSIX threads are allocated and started in one operation.
1009   */
1010
1011  status = _Thread_Start(
1012    the_thread,
1013    THREAD_START_POINTER,
1014    start_routine,
1015    arg,
1016    0                     /* unused */
1017  );
1018
1019  if ( schedpolicy == SCHED_SPORADIC ) {
1020    _Watchdog_Insert_ticks(
1021      &api->Sporadic_timer,
1022      _POSIX_Timespec_to_interval( &api->schedparam.ss_replenish_period )
1023    );
1024  }
1025
1026  /*
1027   *  _Thread_Start only fails if the thread was in the incorrect state
1028   */
1029
1030  if ( !status ) {
1031    _POSIX_Threads_Free( the_thread );
1032    _Thread_Enable_dispatch();
1033    return EINVAL;
1034  }
1035
1036  /*
1037   *  Return the id and indicate we successfully created the thread
1038   */
1039
1040  *thread = the_thread->Object.id;
1041
1042 _Thread_Enable_dispatch();
1043
1044 return 0;
1045}
1046
1047/*PAGE
1048 *
1049 *  16.1.3 Wait for Thread Termination, P1003.1c/Draft 10, p. 147
1050 */
1051
1052int pthread_join(
1053  pthread_t   thread,
1054  void      **value_ptr
1055)
1056{
1057  register Thread_Control *the_thread;
1058  POSIX_API_Control       *api;
1059  Objects_Locations        location;
1060  void                    *return_pointer;
1061
1062  the_thread = _POSIX_Threads_Get( thread, &location );
1063  switch ( location ) {
1064    case OBJECTS_ERROR:
1065    case OBJECTS_REMOTE:
1066      return ESRCH;
1067    case OBJECTS_LOCAL:
1068      api = the_thread->API_Extensions[ THREAD_API_POSIX ];
1069
1070      if ( api->detachstate == PTHREAD_CREATE_DETACHED ) {
1071        _Thread_Enable_dispatch();
1072        return EINVAL;
1073      }
1074
1075      if ( _Thread_Is_executing( the_thread ) ) {
1076        _Thread_Enable_dispatch();
1077        return EDEADLK;
1078      }
1079
1080      /*
1081       *  Put ourself on the threads join list
1082       */
1083
1084      _Thread_Executing->Wait.return_argument = (unsigned32 *) &return_pointer;
1085
1086      _Thread_queue_Enter_critical_section( &api->Join_List );
1087
1088      _Thread_queue_Enqueue( &api->Join_List, WATCHDOG_NO_TIMEOUT );
1089
1090      _Thread_Enable_dispatch();
1091
1092      if ( value_ptr )
1093        *value_ptr = return_pointer;
1094      return 0;
1095  }
1096
1097  return POSIX_BOTTOM_REACHED();
1098}
1099
1100/*PAGE
1101 *
1102 *  16.1.4 Detaching a Thread, P1003.1c/Draft 10, p. 149
1103 */
1104
1105int pthread_detach(
1106  pthread_t   thread
1107)
1108{
1109  register Thread_Control *the_thread;
1110  POSIX_API_Control       *api;
1111  Objects_Locations        location;
1112 
1113  the_thread = _POSIX_Threads_Get( thread, &location );
1114  switch ( location ) {
1115    case OBJECTS_ERROR:
1116    case OBJECTS_REMOTE:
1117      return ESRCH;
1118    case OBJECTS_LOCAL:
1119
1120      api = the_thread->API_Extensions[ THREAD_API_POSIX ];
1121      api->detachstate = PTHREAD_CREATE_DETACHED;
1122      _Thread_Enable_dispatch();
1123      return 0;
1124  }
1125 
1126  return POSIX_BOTTOM_REACHED();
1127}
1128
1129/*PAGE
1130 *
1131 *  16.1.5.1 Thread Termination, p1003.1c/Draft 10, p. 150
1132 *
1133 *  NOTE: Key destructors are executed in the POSIX api delete extension.
1134 */
1135 
1136void pthread_exit(
1137  void  *value_ptr
1138)
1139{
1140  _Thread_Disable_dispatch();
1141
1142  _Thread_Executing->Wait.return_argument = (unsigned32 *)value_ptr;
1143
1144  _Thread_Close( &_POSIX_Threads_Information, _Thread_Executing );
1145
1146  _POSIX_Threads_Free( _Thread_Executing );
1147
1148  _Thread_Enable_dispatch();
1149}
1150
1151/*PAGE
1152 *
1153 *  16.1.6 Get Calling Thread's ID, p1003.1c/Draft 10, p. 152
1154 */
1155
1156pthread_t pthread_self( void )
1157{
1158  return _Thread_Executing->Object.id;
1159}
1160
1161/*PAGE
1162 *
1163 *  16.1.7 Compare Thread IDs, p1003.1c/Draft 10, p. 153
1164 *
1165 *  NOTE:  POSIX does not define the behavior when either thread id is invalid.
1166 */
1167
1168int pthread_equal(
1169  pthread_t  t1,
1170  pthread_t  t2
1171)
1172{
1173  /*
1174   *  If the system is configured for debug, then we will do everything we
1175   *  can to insure that both ids are valid.  Otherwise, we will do the
1176   *  cheapest possible thing to determine if they are equal.
1177   */
1178
1179#ifndef RTEMS_DEBUG
1180  return _Objects_Are_ids_equal( t1, t2 );
1181#else
1182  int               status;
1183  Objects_Locations location;
1184
1185  /*
1186   *  By default this is not a match.
1187   */
1188
1189  status = 0;
1190
1191  /*
1192   *  Validate the first id and return 0 if it is not valid
1193   */
1194
1195  (void) _POSIX_Threads_Get( t1, &location );
1196  switch ( location ) {
1197    case OBJECTS_ERROR:
1198    case OBJECTS_REMOTE:
1199      break;
1200
1201    case OBJECTS_LOCAL:
1202
1203      /*
1204       *  Validate the second id and return 0 if it is not valid
1205       */
1206
1207      (void) _POSIX_Threads_Get( t2, &location );
1208      switch ( location ) {
1209        case OBJECTS_ERROR:
1210        case OBJECTS_REMOTE:
1211          break;
1212        case OBJECTS_LOCAL:
1213          status = _Objects_Are_ids_equal( t1, t2 );
1214          break;
1215      }
1216      _Thread_Unnest_dispatch();
1217      break;
1218  }
1219
1220  _Thread_Enable_dispatch();
1221  return status;
1222#endif
1223}
1224
1225/*PAGE
1226 *
1227 *  16.1.8 Dynamic Package Initialization, P1003.1c/Draft 10, p. 154
1228 */
1229
1230int pthread_once(
1231  pthread_once_t  *once_control,
1232  void           (*init_routine)(void)
1233)
1234{
1235  if ( !once_control || !init_routine )
1236    return EINVAL;
1237
1238  _Thread_Disable_dispatch();
1239
1240  if ( !once_control->init_executed ) {
1241    once_control->is_initialized = TRUE;
1242    once_control->init_executed = TRUE;
1243    (*init_routine)();
1244  }
1245 
1246  _Thread_Enable_dispatch();
1247  return 0;
1248}
1249
1250/*PAGE
1251 *
1252 *  20.1.6 Accessing a Thread CPU-time Clock, P1003.4b/Draft 8, p. 58
1253 */
1254 
1255int pthread_getcpuclockid(
1256  pthread_t    pid,
1257  clockid_t   *clock_id
1258)
1259{
1260  return POSIX_NOT_IMPLEMENTED();
1261}
1262
1263/*PAGE
1264 *
1265 *  20.1.7 CPU-time Clock Thread Creation Attribute, P1003.4b/Draft 8, p. 59
1266 */
1267
1268int pthread_attr_setcputime(
1269  pthread_attr_t  *attr,
1270  int              clock_allowed
1271)
1272{
1273  if ( !attr || !attr->is_initialized )
1274    return EINVAL;
1275
1276  switch ( clock_allowed ) {
1277    case CLOCK_ENABLED:
1278    case CLOCK_DISABLED:
1279      attr->cputime_clock_allowed = clock_allowed;
1280      return 0;
1281 
1282    default:
1283      return EINVAL;
1284  }
1285}
1286
1287/*PAGE
1288 *
1289 *  20.1.7 CPU-time Clock Thread Creation Attribute, P1003.4b/Draft 8, p. 59
1290 */
1291
1292int pthread_attr_getcputime(
1293  pthread_attr_t  *attr,
1294  int             *clock_allowed
1295)
1296{
1297  if ( !attr || !attr->is_initialized || !clock_allowed )
1298    return EINVAL;
1299
1300  *clock_allowed = attr->cputime_clock_allowed;
1301  return 0;
1302}
Note: See TracBrowser for help on using the repository browser.