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

4.104.114.84.95
Last change on this file since 1149658 was f926b34, checked in by Joel Sherrill <joel.sherrill@…>, on 03/08/97 at 03:51:55

Modified calls to _Thread_Change_priority to take a third argument. The new
argument indicates whether the task is to be placed at the head or tail of
its priority fifo when it is lowering its own priority. POSIX normally
follows the RTEMS API conventions but GNAT expects that all lowering of
a task's priority by the task itself will result in being placed at the
head of the priority FIFO. Normally, this would only occur as the result
of lose of inherited priority.

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