source: rtems/cpukit/posix/src/pthread.c @ 6b067c4

4.104.114.84.95
Last change on this file since 6b067c4 was 6b067c4, checked in by Joel Sherrill <joel.sherrill@…>, on 06/04/96 at 19:15:28

renamed the local variable attrp to the_attr in pthread_create

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