/* * $Id$ */ #include #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 ].thread_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. */ }