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

4.104.114.84.95
Last change on this file since 2014063 was 2014063, checked in by Joel Sherrill <joel.sherrill@…>, on 08/07/96 at 22:06:08

sporadic server debugged and working. This required minor changes in all
sporadic server related routines.

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