source: rtems/c/src/exec/posix/src/pthread.c @ 98ed15e

4.104.114.84.95
Last change on this file since 98ed15e was 98ed15e, checked in by Joel Sherrill <joel.sherrill@…>, on 06/11/96 at 16:01:37

Basic signal functionality appears to work. pthread_kill() can successfully
send signals to the current thread or to another blocked thread. nanosleep()
can be interrupted by a signal and return the time remaining.

Post switch extension added to dispatch posix signal handlers.

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