/* * $Id$ */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include /*PAGE * * The default pthreads attributes structure. * * NOTE: Be careful .. if the default attribute set changes, * _POSIX_Threads_Initialize_user_threads will need to be examined. * */ const pthread_attr_t _POSIX_Threads_Default_attributes = { TRUE, /* is_initialized */ NULL, /* stackaddr */ PTHREAD_MINIMUM_STACK_SIZE, /* stacksize */ PTHREAD_SCOPE_PROCESS, /* contentionscope */ PTHREAD_INHERIT_SCHED, /* inheritsched */ SCHED_FIFO, /* schedpolicy */ { /* schedparam */ 2, /* sched_priority */ 0, /* ss_low_priority */ { 0L, 0 }, /* ss_replenish_period */ { 0L, 0 } /* ss_initial_budget */ }, PTHREAD_CREATE_JOINABLE, /* detachstate */ 1 /* cputime_clock_allowed */ }; /*PAGE * * _POSIX_Threads_Sporadic_budget_TSR */ void _POSIX_Threads_Sporadic_budget_TSR( Objects_Id id, void *argument ) { unsigned32 ticks; unsigned32 new_priority; Thread_Control *the_thread; POSIX_API_Control *api; the_thread = argument; api = the_thread->API_Extensions[ THREAD_API_POSIX ]; ticks = _POSIX_Timespec_to_interval( &api->schedparam.ss_initial_budget ); if ( !ticks ) ticks = 1; the_thread->cpu_time_budget = ticks; new_priority = _POSIX_Priority_To_core( api->ss_high_priority ); the_thread->real_priority = new_priority; if ( the_thread->resource_count == 0 || the_thread->current_priority > new_priority ) _Thread_Change_priority( the_thread, new_priority, TRUE ); ticks = _POSIX_Timespec_to_interval( &api->schedparam.ss_replenish_period ); if ( !ticks ) ticks = 1; _Watchdog_Insert_ticks( &api->Sporadic_timer, ticks ); } /*PAGE * * _POSIX_Threads_Sporadic_budget_callout */ void _POSIX_Threads_Sporadic_budget_callout( Thread_Control *the_thread ) { POSIX_API_Control *api; unsigned32 new_priority; api = the_thread->API_Extensions[ THREAD_API_POSIX ]; /* * This will prevent the thread from consuming its entire "budget" * while at low priority. */ the_thread->cpu_time_budget = 0xFFFFFFFF; /* XXX should be based on MAX_U32 */ new_priority = _POSIX_Priority_To_core( api->schedparam.ss_low_priority ); the_thread->real_priority = new_priority; if ( the_thread->resource_count == 0 || the_thread->current_priority > new_priority ) _Thread_Change_priority( the_thread, new_priority, TRUE ); } /*PAGE * * _POSIX_Threads_Create_extension * * XXX */ boolean _POSIX_Threads_Create_extension( Thread_Control *executing, Thread_Control *created ) { POSIX_API_Control *api; POSIX_API_Control *executing_api; api = _Workspace_Allocate( sizeof( POSIX_API_Control ) ); if ( !api ) return FALSE; created->API_Extensions[ THREAD_API_POSIX ] = api; /* XXX check all fields are touched */ api->Attributes = _POSIX_Threads_Default_attributes; api->detachstate = _POSIX_Threads_Default_attributes.detachstate; api->schedpolicy = _POSIX_Threads_Default_attributes.schedpolicy; api->schedparam = _POSIX_Threads_Default_attributes.schedparam; api->schedparam.sched_priority = _POSIX_Priority_From_core( created->current_priority ); /* * If the thread is not a posix thread, then all posix signals are blocked * by default. */ /* XXX use signal constants */ api->signals_pending = 0; if ( _Objects_Get_class( created->Object.id ) == OBJECTS_POSIX_THREADS ) { executing_api = _Thread_Executing->API_Extensions[ THREAD_API_POSIX ]; api->signals_blocked = api->signals_blocked; } else api->signals_blocked = 0xffffffff; /* XXX set signal parameters -- block all signals for non-posix threads */ _Thread_queue_Initialize( &api->Join_List, OBJECTS_NO_CLASS, /* only used for proxy operations */ THREAD_QUEUE_DISCIPLINE_FIFO, STATES_WAITING_FOR_JOIN_AT_EXIT, NULL, /* no extract proxy handler */ 0 ); _Watchdog_Initialize( &api->Sporadic_timer, _POSIX_Threads_Sporadic_budget_TSR, created->Object.id, created ); return TRUE; } /*PAGE * * _POSIX_Threads_Delete_extension */ User_extensions_routine _POSIX_Threads_Delete_extension( Thread_Control *executing, Thread_Control *deleted ) { Thread_Control *the_thread; POSIX_API_Control *api; void **value_ptr; api = deleted->API_Extensions[ THREAD_API_POSIX ]; /* XXX run cancellation handlers */ _POSIX_Keys_Run_destructors( deleted ); /* * Wakeup all the tasks which joined with this one */ value_ptr = (void **) deleted->Wait.return_argument; while ( (the_thread = _Thread_queue_Dequeue( &api->Join_List )) ) *(void **)the_thread->Wait.return_argument = value_ptr; if ( api->schedpolicy == SCHED_SPORADIC ) (void) _Watchdog_Remove( &api->Sporadic_timer ); deleted->API_Extensions[ THREAD_API_POSIX ] = NULL; (void) _Workspace_Free( api ); } /*PAGE * * _POSIX_Threads_Initialize_user_threads * * This routine creates and starts all configured user * initialzation threads. * * Input parameters: NONE * * Output parameters: NONE */ void _POSIX_Threads_Initialize_user_threads( void ) { int status; unsigned32 index; unsigned32 maximum; posix_initialization_threads_table *user_threads; pthread_t thread_id; pthread_attr_t attr; user_threads = _POSIX_Threads_User_initialization_threads; maximum = _POSIX_Threads_Number_of_initialization_threads; if ( !user_threads || maximum == 0 ) return; /* * Be careful .. if the default attribute set changes, this may need to. * * Setting the attributes explicitly is critical, since we don't want * to inherit the idle tasks attributes. */ for ( index=0 ; index < maximum ; index++ ) { status = pthread_attr_init( &attr ); assert( !status ); status = pthread_attr_setinheritsched( &attr, PTHREAD_EXPLICIT_SCHED ); assert( !status ); status = pthread_attr_setstacksize( &attr, PTHREAD_MINIMUM_STACK_SIZE * 2 ); assert( !status ); status = pthread_create( &thread_id, &attr, user_threads[ index ].entry, NULL ); assert( !status ); } } /*PAGE * * API Extension control structures */ API_extensions_Control _POSIX_Threads_API_extensions = { { NULL, NULL }, NULL, /* predriver */ _POSIX_Threads_Initialize_user_threads, /* postdriver */ _POSIX_signals_Post_switch_extension, /* post switch */ }; User_extensions_Control _POSIX_Threads_User_extensions = { { NULL, NULL }, { _POSIX_Threads_Create_extension, /* create */ NULL, /* start */ NULL, /* restart */ _POSIX_Threads_Delete_extension, /* delete */ NULL, /* switch */ NULL, /* begin */ NULL, /* exitted */ NULL /* fatal */ } }; /*PAGE * * _POSIX_Threads_Manager_initialization * * This routine initializes all threads manager related data structures. * * Input parameters: * maximum_pthreads - maximum configured pthreads * * Output parameters: NONE */ void _POSIX_Threads_Manager_initialization( unsigned32 maximum_pthreads, unsigned32 number_of_initialization_threads, posix_initialization_threads_table *user_threads ) { _POSIX_Threads_Number_of_initialization_threads = number_of_initialization_threads; _POSIX_Threads_User_initialization_threads = user_threads; /* * There may not be any POSIX initialization threads configured. */ #if 0 if ( user_threads == NULL || number_of_initialization_threads == 0 ) _Internal_error_Occurred( INTERNAL_ERROR_POSIX_API, TRUE, EINVAL ); #endif _Objects_Initialize_information( &_POSIX_Threads_Information, OBJECTS_POSIX_THREADS, FALSE, /* does not support global */ maximum_pthreads, sizeof( Thread_Control ), TRUE, 5, /* length is arbitrary for now */ TRUE /* this class is threads */ ); /* * Add all the extensions for this API */ _User_extensions_Add_API_set( &_POSIX_Threads_User_extensions ); _API_extensions_Add( &_POSIX_Threads_API_extensions ); /* * If we supported MP, then here we would ... * Register the MP Process Packet routine. */ } /*PAGE * * 3.1.3 Register Fork Handlers, P1003.1c/Draft 10, P1003.1c/Draft 10, p. 27 * * RTEMS does not support processes, so we fall under this and do not * provide this routine: * * "Either the implementation shall support the pthread_atfork() function * as described above or the pthread_atfork() funciton shall not be * provided." */ /*PAGE * * 13.5.1 Thread Creation Scheduling Attributes, P1003.1c/Draft 10, p. 120 */ int pthread_attr_setscope( pthread_attr_t *attr, int contentionscope ) { if ( !attr || !attr->is_initialized ) return EINVAL; switch ( contentionscope ) { case PTHREAD_SCOPE_PROCESS: attr->contentionscope = contentionscope; return 0; case PTHREAD_SCOPE_SYSTEM: return ENOTSUP; default: return EINVAL; } } /*PAGE * * 13.5.1 Thread Creation Scheduling Attributes, P1003.1c/Draft 10, p. 120 */ int pthread_attr_getscope( const pthread_attr_t *attr, int *contentionscope ) { if ( !attr || !attr->is_initialized || !contentionscope ) return EINVAL; *contentionscope = attr->contentionscope; return 0; } /*PAGE * * 13.5.1 Thread Creation Scheduling Attributes, P1003.1c/Draft 10, p. 120 */ int pthread_attr_setinheritsched( pthread_attr_t *attr, int inheritsched ) { if ( !attr || !attr->is_initialized ) return EINVAL; switch ( inheritsched ) { case PTHREAD_INHERIT_SCHED: case PTHREAD_EXPLICIT_SCHED: attr->inheritsched = inheritsched; return 0; default: return ENOTSUP; } } /*PAGE * * 13.5.1 Thread Creation Scheduling Attributes, P1003.1c/Draft 10, p. 120 */ int pthread_attr_getinheritsched( const pthread_attr_t *attr, int *inheritsched ) { if ( !attr || !attr->is_initialized || !inheritsched ) return EINVAL; *inheritsched = attr->inheritsched; return 0; } /*PAGE * * 13.5.1 Thread Creation Scheduling Attributes, P1003.1c/Draft 10, p. 120 */ int pthread_attr_setschedpolicy( pthread_attr_t *attr, int policy ) { if ( !attr || !attr->is_initialized ) return EINVAL; switch ( policy ) { case SCHED_OTHER: case SCHED_FIFO: case SCHED_RR: case SCHED_SPORADIC: attr->schedpolicy = policy; return 0; default: return ENOTSUP; } } /*PAGE * * 13.5.1 Thread Creation Scheduling Parameters, P1003.1c/Draft 10, p. 120 */ int pthread_attr_getschedpolicy( const pthread_attr_t *attr, int *policy ) { if ( !attr || !attr->is_initialized || !policy ) return EINVAL; *policy = attr->schedpolicy; return 0; } /*PAGE * * 13.5.1 Thread Creation Scheduling Parameters, P1003.1c/Draft 10, p. 120 */ int pthread_attr_setschedparam( pthread_attr_t *attr, const struct sched_param *param ) { if ( !attr || !attr->is_initialized || !param ) return EINVAL; attr->schedparam = *param; return 0; } /*PAGE * * 13.5.1 Thread Creation Scheduling Attributes, P1003.1c/Draft 10, p. 120 */ int pthread_attr_getschedparam( const pthread_attr_t *attr, struct sched_param *param ) { if ( !attr || !attr->is_initialized || !param ) return EINVAL; *param = attr->schedparam; return 0; } /*PAGE * * 13.5.2 Dynamic Thread Scheduling Parameters Access, * P1003.1c/Draft 10, p. 124 */ int pthread_getschedparam( pthread_t thread, int *policy, struct sched_param *param ) { Objects_Locations location; POSIX_API_Control *api; register Thread_Control *the_thread; if ( !policy || !param ) return EINVAL; the_thread = _POSIX_Threads_Get( thread, &location ); switch ( location ) { case OBJECTS_ERROR: case OBJECTS_REMOTE: return ESRCH; case OBJECTS_LOCAL: api = the_thread->API_Extensions[ THREAD_API_POSIX ]; *policy = api->schedpolicy; *param = api->schedparam; param->sched_priority = _POSIX_Priority_From_core( the_thread->current_priority ); _Thread_Enable_dispatch(); return 0; } return POSIX_BOTTOM_REACHED(); } /*PAGE * * 13.5.2 Dynamic Thread Scheduling Parameters Access, * P1003.1c/Draft 10, p. 124 */ int pthread_setschedparam( pthread_t thread, int policy, struct sched_param *param ) { register Thread_Control *the_thread; POSIX_API_Control *api; Thread_CPU_budget_algorithms budget_algorithm; Thread_CPU_budget_algorithm_callout budget_callout; Objects_Locations location; /* * Check all the parameters */ if ( !param ) return EINVAL; if ( !_POSIX_Priority_Is_valid( param->sched_priority ) ) return EINVAL; budget_algorithm = THREAD_CPU_BUDGET_ALGORITHM_NONE; budget_callout = NULL; switch ( policy ) { case SCHED_OTHER: budget_algorithm = THREAD_CPU_BUDGET_ALGORITHM_RESET_TIMESLICE; break; case SCHED_FIFO: budget_algorithm = THREAD_CPU_BUDGET_ALGORITHM_NONE; break; case SCHED_RR: budget_algorithm = THREAD_CPU_BUDGET_ALGORITHM_EXHAUST_TIMESLICE; break; case SCHED_SPORADIC: budget_algorithm = THREAD_CPU_BUDGET_ALGORITHM_CALLOUT; budget_callout = _POSIX_Threads_Sporadic_budget_callout; if ( _POSIX_Timespec_to_interval( ¶m->ss_replenish_period ) < _POSIX_Timespec_to_interval( ¶m->ss_initial_budget ) ) return EINVAL; if ( !_POSIX_Priority_Is_valid( param->ss_low_priority ) ) return EINVAL; break; default: return EINVAL; } /* * Actually change the scheduling policy and parameters */ the_thread = _POSIX_Threads_Get( thread, &location ); switch ( location ) { case OBJECTS_ERROR: case OBJECTS_REMOTE: return ESRCH; case OBJECTS_LOCAL: api = the_thread->API_Extensions[ THREAD_API_POSIX ]; if ( api->schedpolicy == SCHED_SPORADIC ) (void) _Watchdog_Remove( &api->Sporadic_timer ); api->schedpolicy = policy; api->schedparam = *param; the_thread->budget_algorithm = budget_algorithm; the_thread->budget_callout = budget_callout; switch ( api->schedpolicy ) { case SCHED_OTHER: case SCHED_FIFO: case SCHED_RR: the_thread->cpu_time_budget = _Thread_Ticks_per_timeslice; the_thread->real_priority = _POSIX_Priority_To_core( api->schedparam.sched_priority ); _Thread_Change_priority( the_thread, the_thread->real_priority, TRUE ); break; case SCHED_SPORADIC: api->ss_high_priority = api->schedparam.sched_priority; _POSIX_Threads_Sporadic_budget_TSR( 0, the_thread ); break; } _Thread_Enable_dispatch(); return 0; } return POSIX_BOTTOM_REACHED(); } /*PAGE * * 16.1.1 Thread Creation Attributes, P1003.1c/Draft 10, p, 140 */ int pthread_attr_init( pthread_attr_t *attr ) { if ( !attr ) return EINVAL; *attr = _POSIX_Threads_Default_attributes; return 0; } /*PAGE * * 16.1.1 Thread Creation Attributes, P1003.1c/Draft 10, p, 140 */ int pthread_attr_destroy( pthread_attr_t *attr ) { if ( !attr || !attr->is_initialized ) return EINVAL; attr->is_initialized = FALSE; return 0; } /*PAGE * * 16.1.1 Thread Creation Attributes, P1003.1c/Draft 10, p, 140 */ int pthread_attr_getstacksize( const pthread_attr_t *attr, size_t *stacksize ) { if ( !attr || !attr->is_initialized || !stacksize ) return EINVAL; *stacksize = attr->stacksize; return 0; } /*PAGE * * 16.1.1 Thread Creation Attributes, P1003.1c/Draft 10, p, 140 */ int pthread_attr_setstacksize( pthread_attr_t *attr, size_t stacksize ) { if ( !attr || !attr->is_initialized ) return EINVAL; if (stacksize < PTHREAD_MINIMUM_STACK_SIZE) attr->stacksize = PTHREAD_MINIMUM_STACK_SIZE; else attr->stacksize = stacksize; return 0; } /*PAGE * * 16.1.1 Thread Creation Attributes, P1003.1c/Draft 10, p, 140 */ int pthread_attr_getstackaddr( const pthread_attr_t *attr, void **stackaddr ) { if ( !attr || !attr->is_initialized || !stackaddr ) return EINVAL; *stackaddr = attr->stackaddr; return 0; } /*PAGE * * 16.1.1 Thread Creation Attributes, P1003.1c/Draft 10, p, 140 */ int pthread_attr_setstackaddr( pthread_attr_t *attr, void *stackaddr ) { if ( !attr || !attr->is_initialized ) return EINVAL; attr->stackaddr = stackaddr; return 0; } /*PAGE * * 16.1.1 Thread Creation Attributes, P1003.1c/Draft 10, p, 140 */ int pthread_attr_getdetachstate( const pthread_attr_t *attr, int *detachstate ) { if ( !attr || !attr->is_initialized || !detachstate ) return EINVAL; *detachstate = attr->detachstate; return 0; } /*PAGE * * 16.1.1 Thread Creation Attributes, P1003.1c/Draft 10, p, 140 */ int pthread_attr_setdetachstate( pthread_attr_t *attr, int detachstate ) { if ( !attr || !attr->is_initialized ) return EINVAL; switch ( detachstate ) { case PTHREAD_CREATE_DETACHED: case PTHREAD_CREATE_JOINABLE: attr->detachstate = detachstate; return 0; default: return EINVAL; } } /*PAGE * * 16.1.2 Thread Creation, P1003.1c/Draft 10, p. 144 */ int pthread_create( pthread_t *thread, const pthread_attr_t *attr, void *(*start_routine)( void * ), void *arg ) { const pthread_attr_t *the_attr; Priority_Control core_priority; Thread_CPU_budget_algorithms budget_algorithm; Thread_CPU_budget_algorithm_callout budget_callout; boolean is_fp; boolean status; Thread_Control *the_thread; char *default_name = "psx"; POSIX_API_Control *api; int schedpolicy = SCHED_RR; struct sched_param schedparam; the_attr = (attr) ? attr : &_POSIX_Threads_Default_attributes; if ( !the_attr->is_initialized ) return EINVAL; /* * Core Thread Initialize insures we get the minimum amount of * stack space if it is allowed to allocate it itself. */ if ( the_attr->stackaddr && !_Stack_Is_enough( the_attr->stacksize ) ) return EINVAL; #if 0 int cputime_clock_allowed; /* see time.h */ POSIX_NOT_IMPLEMENTED(); #endif /* * P1003.1c/Draft 10, p. 121. * * If inheritsched is set to PTHREAD_INHERIT_SCHED, then this thread * inherits scheduling attributes from the creating thread. If it is * PTHREAD_EXPLICIT_SCHED, then scheduling parameters come from the * attributes structure. */ switch ( the_attr->inheritsched ) { case PTHREAD_INHERIT_SCHED: api = _Thread_Executing->API_Extensions[ THREAD_API_POSIX ]; schedpolicy = api->schedpolicy; schedparam = api->schedparam; break; case PTHREAD_EXPLICIT_SCHED: schedpolicy = the_attr->schedpolicy; schedparam = the_attr->schedparam; break; default: return EINVAL; } /* * Check the contentionscope since rtems only supports PROCESS wide * contention (i.e. no system wide contention). */ if ( the_attr->contentionscope != PTHREAD_SCOPE_PROCESS ) return ENOTSUP; /* * Interpret the scheduling parameters. */ if ( !_POSIX_Priority_Is_valid( schedparam.sched_priority ) ) return EINVAL; core_priority = _POSIX_Priority_To_core( schedparam.sched_priority ); /* * Set the core scheduling policy information. */ budget_callout = NULL; budget_algorithm = THREAD_CPU_BUDGET_ALGORITHM_NONE; switch ( schedpolicy ) { case SCHED_OTHER: budget_algorithm = THREAD_CPU_BUDGET_ALGORITHM_RESET_TIMESLICE; break; case SCHED_FIFO: budget_algorithm = THREAD_CPU_BUDGET_ALGORITHM_NONE; break; case SCHED_RR: budget_algorithm = THREAD_CPU_BUDGET_ALGORITHM_EXHAUST_TIMESLICE; break; case SCHED_SPORADIC: budget_algorithm = THREAD_CPU_BUDGET_ALGORITHM_CALLOUT; budget_callout = _POSIX_Threads_Sporadic_budget_callout; if ( _POSIX_Timespec_to_interval( &schedparam.ss_replenish_period ) < _POSIX_Timespec_to_interval( &schedparam.ss_initial_budget ) ) return EINVAL; if ( !_POSIX_Priority_Is_valid( schedparam.ss_low_priority ) ) return EINVAL; break; default: return EINVAL; } /* * Currently all POSIX threads are floating point if the hardware * supports it. */ is_fp = CPU_HARDWARE_FP; /* * Disable dispatch for protection */ _Thread_Disable_dispatch(); /* * Allocate the thread control block. * * NOTE: Global threads are not currently supported. */ the_thread = _POSIX_Threads_Allocate(); if ( !the_thread ) { _Thread_Enable_dispatch(); return EAGAIN; } /* * Initialize the core thread for this task. */ status = _Thread_Initialize( &_POSIX_Threads_Information, the_thread, the_attr->stackaddr, the_attr->stacksize, is_fp, core_priority, TRUE, /* preemptible */ budget_algorithm, budget_callout, 0, /* isr level */ &default_name /* posix threads don't have a name */ ); if ( !status ) { _POSIX_Threads_Free( the_thread ); _Thread_Enable_dispatch(); return EAGAIN; } /* * finish initializing the per API structure */ api = the_thread->API_Extensions[ THREAD_API_POSIX ]; api->Attributes = *the_attr; api->detachstate = the_attr->detachstate; api->schedpolicy = schedpolicy; api->schedparam = schedparam; /* * This insures we evaluate the process-wide signals pending when we * first run. * * NOTE: Since the thread starts with all unblocked, this is necessary. */ the_thread->do_post_task_switch_extension = TRUE; /* * POSIX threads are allocated and started in one operation. */ status = _Thread_Start( the_thread, THREAD_START_POINTER, start_routine, arg, 0 /* unused */ ); if ( schedpolicy == SCHED_SPORADIC ) { _Watchdog_Insert_ticks( &api->Sporadic_timer, _POSIX_Timespec_to_interval( &api->schedparam.ss_replenish_period ) ); } /* * _Thread_Start only fails if the thread was in the incorrect state */ if ( !status ) { _POSIX_Threads_Free( the_thread ); _Thread_Enable_dispatch(); return EINVAL; } /* * Return the id and indicate we successfully created the thread */ *thread = the_thread->Object.id; _Thread_Enable_dispatch(); return 0; } /*PAGE * * 16.1.3 Wait for Thread Termination, P1003.1c/Draft 10, p. 147 */ int pthread_join( pthread_t thread, void **value_ptr ) { register Thread_Control *the_thread; POSIX_API_Control *api; Objects_Locations location; void *return_pointer; the_thread = _POSIX_Threads_Get( thread, &location ); switch ( location ) { case OBJECTS_ERROR: case OBJECTS_REMOTE: return ESRCH; case OBJECTS_LOCAL: api = the_thread->API_Extensions[ THREAD_API_POSIX ]; if ( api->detachstate == PTHREAD_CREATE_DETACHED ) { _Thread_Enable_dispatch(); return EINVAL; } if ( _Thread_Is_executing( the_thread ) ) { _Thread_Enable_dispatch(); return EDEADLK; } /* * Put ourself on the threads join list */ _Thread_Executing->Wait.return_argument = (unsigned32 *) &return_pointer; _Thread_queue_Enter_critical_section( &api->Join_List ); _Thread_queue_Enqueue( &api->Join_List, WATCHDOG_NO_TIMEOUT ); _Thread_Enable_dispatch(); if ( value_ptr ) *value_ptr = return_pointer; return 0; } return POSIX_BOTTOM_REACHED(); } /*PAGE * * 16.1.4 Detaching a Thread, P1003.1c/Draft 10, p. 149 */ int pthread_detach( pthread_t thread ) { register Thread_Control *the_thread; POSIX_API_Control *api; Objects_Locations location; the_thread = _POSIX_Threads_Get( thread, &location ); switch ( location ) { case OBJECTS_ERROR: case OBJECTS_REMOTE: return ESRCH; case OBJECTS_LOCAL: api = the_thread->API_Extensions[ THREAD_API_POSIX ]; api->detachstate = PTHREAD_CREATE_DETACHED; _Thread_Enable_dispatch(); return 0; } return POSIX_BOTTOM_REACHED(); } /*PAGE * * 16.1.5.1 Thread Termination, p1003.1c/Draft 10, p. 150 * * NOTE: Key destructors are executed in the POSIX api delete extension. */ void pthread_exit( void *value_ptr ) { _Thread_Disable_dispatch(); _Thread_Executing->Wait.return_argument = (unsigned32 *)value_ptr; _Thread_Close( &_POSIX_Threads_Information, _Thread_Executing ); _POSIX_Threads_Free( _Thread_Executing ); _Thread_Enable_dispatch(); } /*PAGE * * 16.1.6 Get Calling Thread's ID, p1003.1c/Draft 10, p. 152 */ pthread_t pthread_self( void ) { return _Thread_Executing->Object.id; } /*PAGE * * 16.1.7 Compare Thread IDs, p1003.1c/Draft 10, p. 153 * * NOTE: POSIX does not define the behavior when either thread id is invalid. */ int pthread_equal( pthread_t t1, pthread_t t2 ) { /* * If the system is configured for debug, then we will do everything we * can to insure that both ids are valid. Otherwise, we will do the * cheapest possible thing to determine if they are equal. */ #ifndef RTEMS_DEBUG return _Objects_Are_ids_equal( t1, t2 ); #else int status; Objects_Locations location; /* * By default this is not a match. */ status = 0; /* * Validate the first id and return 0 if it is not valid */ (void) _POSIX_Threads_Get( t1, &location ); switch ( location ) { case OBJECTS_ERROR: case OBJECTS_REMOTE: break; case OBJECTS_LOCAL: /* * Validate the second id and return 0 if it is not valid */ (void) _POSIX_Threads_Get( t2, &location ); switch ( location ) { case OBJECTS_ERROR: case OBJECTS_REMOTE: break; case OBJECTS_LOCAL: status = _Objects_Are_ids_equal( t1, t2 ); break; } _Thread_Unnest_dispatch(); break; } _Thread_Enable_dispatch(); return status; #endif } /*PAGE * * 16.1.8 Dynamic Package Initialization, P1003.1c/Draft 10, p. 154 */ int pthread_once( pthread_once_t *once_control, void (*init_routine)(void) ) { if ( !once_control || !init_routine ) return EINVAL; _Thread_Disable_dispatch(); if ( !once_control->init_executed ) { once_control->is_initialized = TRUE; once_control->init_executed = TRUE; (*init_routine)(); } _Thread_Enable_dispatch(); return 0; } /*PAGE * * 20.1.6 Accessing a Thread CPU-time Clock, P1003.4b/Draft 8, p. 58 */ int pthread_getcpuclockid( pthread_t pid, clockid_t *clock_id ) { return POSIX_NOT_IMPLEMENTED(); } /*PAGE * * 20.1.7 CPU-time Clock Thread Creation Attribute, P1003.4b/Draft 8, p. 59 */ int pthread_attr_setcputime( pthread_attr_t *attr, int clock_allowed ) { if ( !attr || !attr->is_initialized ) return EINVAL; switch ( clock_allowed ) { case CLOCK_ENABLED: case CLOCK_DISABLED: attr->cputime_clock_allowed = clock_allowed; return 0; default: return EINVAL; } } /*PAGE * * 20.1.7 CPU-time Clock Thread Creation Attribute, P1003.4b/Draft 8, p. 59 */ int pthread_attr_getcputime( pthread_attr_t *attr, int *clock_allowed ) { if ( !attr || !attr->is_initialized || !clock_allowed ) return EINVAL; *clock_allowed = attr->cputime_clock_allowed; return 0; }