source: rtems/cpukit/posix/src/pthread.c @ 7d5566e

4.104.114.84.95
Last change on this file since 7d5566e was a14d2af, checked in by Joel Sherrill <joel.sherrill@…>, on 07/09/97 at 23:52:08

Changed name from entry to thread_entry to be more compatible with
Ada interface where entry is a keyword.

  • Property mode set to 100644
File size: 29.0 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 ].thread_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 = the_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.