source: rtems/c/src/exec/posix/src/pthread.c @ 0b710dbb

4.104.114.84.95
Last change on this file since 0b710dbb was 0b710dbb, checked in by Mark Johannes <Mark.Johannes@…>, on 08/23/96 at 14:47:58

pthread_create: changed EINVAL for no more threads back to EAGAIN

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