diff options
Diffstat (limited to 'cpukit/posix/src/pthread.c')
-rw-r--r-- | cpukit/posix/src/pthread.c | 366 |
1 files changed, 366 insertions, 0 deletions
diff --git a/cpukit/posix/src/pthread.c b/cpukit/posix/src/pthread.c new file mode 100644 index 0000000000..3890144aa5 --- /dev/null +++ b/cpukit/posix/src/pthread.c @@ -0,0 +1,366 @@ +/* + * COPYRIGHT (c) 1989-2010. + * On-Line Applications Research Corporation (OAR). + * + * The license and distribution terms for this file may be + * found in the file LICENSE in this distribution or at + * http://www.rtems.com/license/LICENSE. + * + * $Id$ + */ + +#if HAVE_CONFIG_H +#include "config.h" +#endif + +#include <errno.h> +#include <pthread.h> +#include <limits.h> + +#include <rtems/system.h> +#include <rtems/config.h> +#include <rtems/score/apiext.h> +#include <rtems/score/stack.h> +#include <rtems/score/thread.h> +#include <rtems/score/userext.h> +#include <rtems/score/wkspace.h> +#include <rtems/posix/cancel.h> +#include <rtems/posix/pthread.h> +#include <rtems/posix/priority.h> +#include <rtems/posix/psignal.h> +#include <rtems/posix/config.h> +#include <rtems/posix/key.h> +#include <rtems/posix/time.h> +#include <rtems/score/timespec.h> + +/* + * 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 */ + 0, /* stacksize -- will be adjusted to minimum */ + PTHREAD_SCOPE_PROCESS, /* contentionscope */ + PTHREAD_INHERIT_SCHED, /* inheritsched */ + SCHED_FIFO, /* schedpolicy */ + { /* schedparam */ + 2, /* sched_priority */ + #if defined(_POSIX_SPORADIC_SERVER) || \ + defined(_POSIX_THREAD_SPORADIC_SERVER) + 0, /* sched_ss_low_priority */ + { 0L, 0 }, /* sched_ss_repl_period */ + { 0L, 0 } /* sched_ss_init_budget */ + #endif + }, + #if HAVE_DECL_PTHREAD_ATTR_SETGUARDSIZE + 0, /* guardsize */ + #endif + #if defined(_POSIX_THREAD_CPUTIME) + 1, /* cputime_clock_allowed */ + #endif + PTHREAD_CREATE_JOINABLE, /* detachstate */ +}; + +/* + * _POSIX_Threads_Sporadic_budget_TSR + */ +void _POSIX_Threads_Sporadic_budget_TSR( + Objects_Id id __attribute__((unused)), + void *argument +) +{ + uint32_t ticks; + uint32_t new_priority; + Thread_Control *the_thread; + POSIX_API_Control *api; + + the_thread = argument; + + api = the_thread->API_Extensions[ THREAD_API_POSIX ]; + + /* ticks is guaranteed to be at least one */ + ticks = _Timespec_To_ticks( &api->schedparam.sched_ss_init_budget ); + + the_thread->cpu_time_budget = ticks; + + new_priority = _POSIX_Priority_To_core( api->schedparam.sched_priority ); + the_thread->real_priority = new_priority; + + /* + * If holding a resource, then do not change it. + */ + #if 0 + printk( "TSR %d %d %d\n", the_thread->resource_count, + the_thread->current_priority, new_priority ); + #endif + if ( the_thread->resource_count == 0 ) { + /* + * If this would make them less important, then do not change it. + */ + if ( the_thread->current_priority > new_priority ) { + _Thread_Change_priority( the_thread, new_priority, true ); + #if 0 + printk( "raise priority\n" ); + #endif + } + } + + /* ticks is guaranteed to be at least one */ + ticks = _Timespec_To_ticks( &api->schedparam.sched_ss_repl_period ); + + _Watchdog_Insert_ticks( &api->Sporadic_timer, ticks ); +} + +/* + * _POSIX_Threads_Sporadic_budget_callout + */ +void _POSIX_Threads_Sporadic_budget_callout( + Thread_Control *the_thread +) +{ + POSIX_API_Control *api; + uint32_t 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.sched_ss_low_priority); + the_thread->real_priority = new_priority; + + /* + * If holding a resource, then do not change it. + */ + #if 0 + printk( "callout %d %d %d\n", the_thread->resource_count, + the_thread->current_priority, new_priority ); + #endif + if ( the_thread->resource_count == 0 ) { + /* + * Make sure we are actually lowering it. If they have lowered it + * to logically lower than sched_ss_low_priority, then we do not want to + * change it. + */ + if ( the_thread->current_priority < new_priority ) { + _Thread_Change_priority( the_thread, new_priority, true ); + #if 0 + printk( "lower priority\n" ); + #endif + } + } +} + +/* + * _POSIX_Threads_Create_extension + * + * This method is invoked for each thread created. + */ + +bool _POSIX_Threads_Create_extension( + Thread_Control *executing __attribute__((unused)), + 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 ); + + /* + * POSIX 1003.1 1996, 18.2.2.2 + */ + api->cancelation_requested = 0; + api->cancelability_state = PTHREAD_CANCEL_ENABLE; + api->cancelability_type = PTHREAD_CANCEL_DEFERRED; + _Chain_Initialize_empty (&api->Cancellation_Handlers); + + /* + * If the thread is not a posix thread, then all posix signals are blocked + * by default. + * + * The check for class == 1 is debug. Should never really happen. + */ + + /* XXX use signal constants */ + api->signals_pending = 0; + if ( _Objects_Get_API( created->Object.id ) == OBJECTS_POSIX_API + #if defined(RTEMS_DEBUG) + && _Objects_Get_class( created->Object.id ) == 1 + #endif + ) { + executing_api = _Thread_Executing->API_Extensions[ THREAD_API_POSIX ]; + api->signals_blocked = executing_api->signals_blocked; + } else { + api->signals_blocked = 0xffffffff; + } + + _Thread_queue_Initialize( + &api->Join_List, + THREAD_QUEUE_DISCIPLINE_FIFO, + STATES_WAITING_FOR_JOIN_AT_EXIT, + 0 + ); + + _Watchdog_Initialize( + &api->Sporadic_timer, + _POSIX_Threads_Sporadic_budget_TSR, + created->Object.id, + created + ); + + return true; +} + +/* + * _POSIX_Threads_Delete_extension + * + * This method is invoked for each thread deleted. + */ +void _POSIX_Threads_Delete_extension( + Thread_Control *executing __attribute__((unused)), + Thread_Control *deleted +) +{ + Thread_Control *the_thread; + POSIX_API_Control *api; + void **value_ptr; + + api = deleted->API_Extensions[ THREAD_API_POSIX ]; + + /* + * Run the POSIX cancellation handlers + */ + _POSIX_Threads_cancel_run( deleted ); + + /* + * Run all the key destructors + */ + _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; + + _Workspace_Free( api ); +} + +/* + * _POSIX_Threads_Exitted_extension + * + * This method is invoked each time a thread exits. + */ +void _POSIX_Threads_Exitted_extension( + Thread_Control *executing +) +{ + /* + * If the executing thread was not created with the POSIX API, then this + * API do not get to define its exit behavior. + */ + if ( _Objects_Get_API( executing->Object.id ) == OBJECTS_POSIX_API ) + pthread_exit( executing->Wait.return_argument ); +} + +/* + * _POSIX_Threads_Initialize_user_threads + * + * This routine creates and starts all configured user + * initialzation threads. + */ +void _POSIX_Threads_Initialize_user_threads( void ) +{ + if ( _POSIX_Threads_Initialize_user_threads_p ) + (*_POSIX_Threads_Initialize_user_threads_p)(); +} + +/* + * API Extension control structures + */ +API_extensions_Control _POSIX_Threads_API_extensions = { + { NULL, NULL }, + #if defined(FUNCTIONALITY_NOT_CURRENTLY_USED_BY_ANY_API) + NULL, /* predriver */ + #endif + _POSIX_Threads_Initialize_user_threads, /* postdriver */ + _POSIX_signals_Post_switch_extension, /* post switch */ +}; + +User_extensions_Control _POSIX_Threads_User_extensions = { + { NULL, NULL }, + { { NULL, NULL }, NULL }, + { _POSIX_Threads_Create_extension, /* create */ + NULL, /* start */ + NULL, /* restart */ + _POSIX_Threads_Delete_extension, /* delete */ + NULL, /* switch */ + NULL, /* begin */ + _POSIX_Threads_Exitted_extension, /* exitted */ + NULL /* fatal */ + } +}; + +/* + * _POSIX_Threads_Manager_initialization + * + * This routine initializes all threads manager related data structures. + */ +void _POSIX_Threads_Manager_initialization(void) +{ + _Objects_Initialize_information( + &_POSIX_Threads_Information, /* object information table */ + OBJECTS_POSIX_API, /* object API */ + OBJECTS_POSIX_THREADS, /* object class */ + Configuration_POSIX_API.maximum_threads, + /* maximum objects of this class */ + sizeof( Thread_Control ), + /* size of this object's control block */ + true, /* true if names for this object are strings */ + _POSIX_PATH_MAX /* maximum length of each object's name */ +#if defined(RTEMS_MULTIPROCESSING) + , + false, /* true if this is a global object class */ + NULL /* Proxy extraction support callout */ +#endif + ); + + /* + * 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. + */ +} |