void _ISR_Handler_initialization( void ) { _ISR_Nest_level = 0; #if (CPU_SIMPLE_VECTORED_INTERRUPTS == TRUE) _ISR_Vector_table = _Workspace_Allocate_or_fatal_error( sizeof(ISR_Handler_entry) * ISR_NUMBER_OF_VECTORS ); _CPU_Initialize_vectors(); #endif #if ( CPU_ALLOCATE_INTERRUPT_STACK == TRUE ) { size_t stack_size = rtems_configuration_get_interrupt_stack_size(); uint32_t max_cpus = rtems_configuration_get_maximum_processors(); uint32_t cpu; if ( !_Stack_Is_enough( stack_size ) ) _Terminate( INTERNAL_ERROR_CORE, true, INTERNAL_ERROR_INTERRUPT_STACK_TOO_SMALL ); for ( cpu = 0 ; cpu < max_cpus; ++cpu ) { Per_CPU_Control *per_cpu = _Per_CPU_Get_by_index( cpu ); void *low = _Workspace_Allocate_or_fatal_error( stack_size ); void *high = _Addresses_Add_offset( low, stack_size ); #if (CPU_STACK_ALIGNMENT != 0) high = _Addresses_Align_down( high, CPU_STACK_ALIGNMENT ); #endif per_cpu->interrupt_stack_low = low; per_cpu->interrupt_stack_high = high; /* * Interrupt stack might have to be aligned and/or setup in a specific * way. Do not use the local low or high variables here since * _CPU_Interrupt_stack_setup() is a nasty macro that might want to play * with the real memory locations. */ #if defined(_CPU_Interrupt_stack_setup) _CPU_Interrupt_stack_setup( per_cpu->interrupt_stack_low, per_cpu->interrupt_stack_high ); #endif } } #endif #if ( CPU_HAS_HARDWARE_INTERRUPT_STACK == TRUE ) _CPU_Install_interrupt_stack(); #endif }
void _ISR_Handler_initialization( void ) { _ISR_Nest_level = 0; #if (CPU_SIMPLE_VECTORED_INTERRUPTS == TRUE) _ISR_Vector_table = _Workspace_Allocate_or_fatal_error( sizeof(ISR_Handler_entry) * ISR_NUMBER_OF_VECTORS ); _CPU_Initialize_vectors(); #endif #if ( CPU_ALLOCATE_INTERRUPT_STACK == TRUE ) { size_t stack_size = rtems_configuration_get_interrupt_stack_size(); if ( !_Stack_Is_enough( stack_size ) ) _Internal_error_Occurred( INTERNAL_ERROR_CORE, true, INTERNAL_ERROR_INTERRUPT_STACK_TOO_SMALL ); _CPU_Interrupt_stack_low = _Workspace_Allocate_or_fatal_error( stack_size ); _CPU_Interrupt_stack_high = _Addresses_Add_offset( _CPU_Interrupt_stack_low, stack_size ); } #if (CPU_STACK_ALIGNMENT != 0) _CPU_Interrupt_stack_high = (void *) ((uintptr_t) _CPU_Interrupt_stack_high & ~(CPU_STACK_ALIGNMENT - 1)); #endif /* Interrupt stack might have to be aligned and/or setup * in a specific way. */ #if defined(_CPU_Interrupt_stack_setup) _CPU_Interrupt_stack_setup(_CPU_Interrupt_stack_low, _CPU_Interrupt_stack_high); #endif #endif #if ( CPU_HAS_HARDWARE_INTERRUPT_STACK == TRUE ) _CPU_Install_interrupt_stack(); #endif }
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; /* * 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 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; }