diff options
Diffstat (limited to 'cpukit/posix/src/pthreadcreate.c')
-rw-r--r-- | cpukit/posix/src/pthreadcreate.c | 232 |
1 files changed, 232 insertions, 0 deletions
diff --git a/cpukit/posix/src/pthreadcreate.c b/cpukit/posix/src/pthreadcreate.c new file mode 100644 index 0000000000..d7f08a5527 --- /dev/null +++ b/cpukit/posix/src/pthreadcreate.c @@ -0,0 +1,232 @@ +/* + * 16.1.2 Thread Creation, P1003.1c/Draft 10, p. 144 + */ + +/* COPYRIGHT (c) 1989-2008. + * 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 <pthread.h> +#include <errno.h> + +#include <rtems/system.h> +#include <rtems/score/thread.h> +#include <rtems/posix/pthread.h> +#include <rtems/posix/priority.h> +#include <rtems/posix/time.h> +#include <rtems/score/apimutex.h> + +static inline size_t _POSIX_Threads_Ensure_minimum_stack ( + size_t size +) +{ + if ( size >= PTHREAD_MINIMUM_STACK_SIZE ) + return size; + return PTHREAD_MINIMUM_STACK_SIZE; +} + + +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; + bool is_fp; + bool status; + Thread_Control *the_thread; + POSIX_API_Control *api; + int schedpolicy = SCHED_RR; + struct sched_param schedparam; + Objects_Name name; + int rc; + + if ( !start_routine ) + return EFAULT; + + the_attr = (attr) ? attr : &_POSIX_Threads_Default_attributes; + + if ( !the_attr->is_initialized ) + return EINVAL; + + /* + * Core Thread Initialize ensures we get the minimum amount of + * stack space if it is allowed to allocate it itself. + * + * NOTE: If the user provides the stack we will let it drop below + * twice the minimum. + */ + if ( the_attr->stackaddr && !_Stack_Is_enough(the_attr->stacksize) ) + return EINVAL; + + #if 0 + int cputime_clock_allowed; /* see time.h */ + rtems_set_errno_and_return_minus_one( ENOSYS ); + #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. + */ + rc = _POSIX_Thread_Translate_sched_param( + schedpolicy, + &schedparam, + &budget_algorithm, + &budget_callout + ); + if ( rc ) + return rc; + + /* + * Currently all POSIX threads are floating point if the hardware + * supports it. + */ + #if ( CPU_HARDWARE_FP == TRUE ) || ( CPU_SOFTWARE_FP == TRUE ) + is_fp = true; + #else + is_fp = false; + #endif + + /* + * Lock the allocator mutex for protection + */ + _RTEMS_Lock_allocator(); + + /* + * Allocate the thread control block. + * + * NOTE: Global threads are not currently supported. + */ + the_thread = _POSIX_Threads_Allocate(); + if ( !the_thread ) { + _RTEMS_Unlock_allocator(); + return EAGAIN; + } + + /* + * Initialize the core thread for this task. + */ + name.name_p = NULL; /* posix threads don't have a name by default */ + status = _Thread_Initialize( + &_POSIX_Threads_Information, + the_thread, + the_attr->stackaddr, + _POSIX_Threads_Ensure_minimum_stack(the_attr->stacksize), + is_fp, + core_priority, + true, /* preemptible */ + budget_algorithm, + budget_callout, + 0, /* isr level */ + name /* posix threads don't have a name */ + ); + + if ( !status ) { + _POSIX_Threads_Free( the_thread ); + _RTEMS_Unlock_allocator(); + 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; + + /* + * POSIX threads are allocated and started in one operation. + */ + status = _Thread_Start( + the_thread, + THREAD_START_POINTER, + start_routine, + arg, + 0 /* unused */ + ); + + #if defined(RTEMS_DEBUG) + /* + * _Thread_Start only fails if the thread was in the incorrect state + * + * NOTE: This can only happen if someone slips in and touches the + * thread while we are creating it. + */ + if ( !status ) { + _POSIX_Threads_Free( the_thread ); + _RTEMS_Unlock_allocator(); + return EINVAL; + } + #endif + + if ( schedpolicy == SCHED_SPORADIC ) { + _Watchdog_Insert_ticks( + &api->Sporadic_timer, + _Timespec_To_ticks( &api->schedparam.sched_ss_repl_period ) + ); + } + + /* + * Return the id and indicate we successfully created the thread + */ + *thread = the_thread->Object.id; + + _RTEMS_Unlock_allocator(); + return 0; +} |