summaryrefslogtreecommitdiffstats
path: root/c/src/exec/posix/src/pthread.c
diff options
context:
space:
mode:
Diffstat (limited to 'c/src/exec/posix/src/pthread.c')
-rw-r--r--c/src/exec/posix/src/pthread.c1309
1 files changed, 1309 insertions, 0 deletions
diff --git a/c/src/exec/posix/src/pthread.c b/c/src/exec/posix/src/pthread.c
new file mode 100644
index 0000000000..95213389cb
--- /dev/null
+++ b/c/src/exec/posix/src/pthread.c
@@ -0,0 +1,1309 @@
+/*
+ * $Id$
+ */
+
+#include <assert.h>
+#include <errno.h>
+#include <pthread.h>
+#include <limits.h>
+
+#include <rtems/system.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/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>
+
+/*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( &param->ss_replenish_period ) <
+ _POSIX_Timespec_to_interval( &param->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;
+}