source: rtems/cpukit/posix/src/pthread.c @ 2f200c7

4.104.114.84.95
Last change on this file since 2f200c7 was 624133c, checked in by Joel Sherrill <joel.sherrill@…>, on 06/06/96 at 14:53:12

added Sporadic Server support

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