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

4.104.114.84.95
Last change on this file since a61f1a46 was a61f1a46, checked in by Joel Sherrill <joel.sherrill@…>, on 08/06/96 at 16:24:41

_POSIX_Threads_Delete_extension: reorder to eliminate use of local pointer
variable before set.

pthread_join: using local variable so user can pass NULL pointer as argument

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