/* * _POSIX_Threads_Sporadic_budget_TSR */ void _POSIX_Threads_Sporadic_budget_TSR( Objects_Id id RTEMS_UNUSED, void *argument ) { uint32_t ticks; 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; _Thread_Change_priority( the_thread, _POSIX_Priority_To_core( api->schedparam.sched_priority ), NULL, _POSIX_Threads_Sporadic_budget_TSR_filter, true ); /* 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 ); }
int pthread_mutex_setprioceiling( pthread_mutex_t *mutex, int prioceiling, int *old_ceiling ) { register POSIX_Mutex_Control *the_mutex; Objects_Locations location; Priority_Control the_priority; int status; if ( !old_ceiling ) return EINVAL; if ( !_POSIX_Priority_Is_valid( prioceiling ) ) return EINVAL; the_priority = _POSIX_Priority_To_core( prioceiling ); /* * Must acquire the mutex before we can change it's ceiling */ status = pthread_mutex_lock( mutex ); if ( status ) return status; the_mutex = _POSIX_Mutex_Get( mutex, &location ); switch ( location ) { case OBJECTS_REMOTE: #if defined(RTEMS_MULTIPROCESSING) /* XXX It feels questionable to set the ceiling on a remote mutex. */ return EINVAL; #endif case OBJECTS_ERROR: return EINVAL; /* impossible to get here */ case OBJECTS_LOCAL: *old_ceiling = _POSIX_Priority_From_core( the_mutex->Mutex.Attributes.priority_ceiling ); the_mutex->Mutex.Attributes.priority_ceiling = the_priority; _CORE_mutex_Surrender( &the_mutex->Mutex, the_mutex->Object.id, #if defined(RTEMS_MULTIPROCESSING) _POSIX_Threads_mutex_MP_support #else NULL #endif ); _Thread_Enable_dispatch(); return 0; } return POSIX_BOTTOM_REACHED(); }
int pthread_mutex_setprioceiling( pthread_mutex_t *mutex, int prioceiling, int *old_ceiling ) { register POSIX_Mutex_Control *the_mutex; Priority_Control the_priority; ISR_lock_Context lock_context; if ( !old_ceiling ) return EINVAL; if ( !_POSIX_Priority_Is_valid( prioceiling ) ) return EINVAL; the_priority = _POSIX_Priority_To_core( prioceiling ); /* * Must acquire the mutex before we can change it's ceiling. * POSIX says block until we acquire it. */ (void) pthread_mutex_lock( mutex ); /* * Do not worry about the return code from this. The Get operation * will also fail if it is a bad id or was deleted between the two * operations. * * NOTE: This makes it easier to get 100% binary coverage since the * bad Id case is handled by the switch. */ the_mutex = _POSIX_Mutex_Get_interrupt_disable( mutex, &lock_context ); if ( the_mutex == NULL ) { return EINVAL; } *old_ceiling = _POSIX_Priority_From_core( the_mutex->Mutex.Attributes.priority_ceiling ); the_mutex->Mutex.Attributes.priority_ceiling = the_priority; /* * We are required to unlock the mutex before we return. */ _CORE_mutex_Surrender( &the_mutex->Mutex, NULL, 0, &lock_context ); return 0; }
/* * _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 ); }
int pthread_setschedprio( pthread_t thread, int prio ) { Thread_Control *the_thread; Per_CPU_Control *cpu_self; Thread_queue_Context queue_context; const Scheduler_Control *scheduler; Priority_Control new_priority; bool valid; the_thread = _Thread_Get( thread, &queue_context.Lock_context.Lock_context ); if ( the_thread == NULL ) { return ESRCH; } _Thread_queue_Context_clear_priority_updates( &queue_context ); _Thread_Wait_acquire_critical( the_thread, &queue_context ); scheduler = _Scheduler_Get_own( the_thread ); new_priority = _POSIX_Priority_To_core( scheduler, prio, &valid ); if ( !valid ) { _Thread_Wait_release( the_thread, &queue_context ); return EINVAL; } _Thread_Priority_change( the_thread, &the_thread->Real_priority, new_priority, true, &queue_context ); cpu_self = _Thread_Dispatch_disable_critical( &queue_context.Lock_context.Lock_context ); _Thread_Wait_release( the_thread, &queue_context ); _Thread_Priority_update( &queue_context ); _Thread_Dispatch_enable( cpu_self ); return 0; }
/* * _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_Sporadic_budget_callout */ void _POSIX_Threads_Sporadic_budget_callout( Thread_Control *the_thread ) { POSIX_API_Control *api; 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 = UINT32_MAX; _Thread_Change_priority( the_thread, _POSIX_Priority_To_core( api->schedparam.sched_ss_low_priority ), NULL, _POSIX_Threads_Sporadic_budget_callout_filter, true ); }
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; }
int pthread_mutex_setprioceiling( pthread_mutex_t *mutex, int prioceiling, int *old_ceiling ) { register POSIX_Mutex_Control *the_mutex; Objects_Locations location; Priority_Control the_priority; ISR_lock_Context lock_context; if ( !old_ceiling ) return EINVAL; if ( !_POSIX_Priority_Is_valid( prioceiling ) ) return EINVAL; the_priority = _POSIX_Priority_To_core( prioceiling ); /* * Must acquire the mutex before we can change it's ceiling. * POSIX says block until we acquire it. */ (void) pthread_mutex_lock( mutex ); /* * Do not worry about the return code from this. The Get operation * will also fail if it is a bad id or was deleted between the two * operations. * * NOTE: This makes it easier to get 100% binary coverage since the * bad Id case is handled by the switch. */ the_mutex = _POSIX_Mutex_Get_interrupt_disable( mutex, &location, &lock_context ); switch ( location ) { case OBJECTS_LOCAL: *old_ceiling = _POSIX_Priority_From_core( the_mutex->Mutex.Attributes.priority_ceiling ); the_mutex->Mutex.Attributes.priority_ceiling = the_priority; /* * We are required to unlock the mutex before we return. */ _CORE_mutex_Surrender( &the_mutex->Mutex, the_mutex->Object.id, NULL, &lock_context ); return 0; #if defined(RTEMS_MULTIPROCESSING) case OBJECTS_REMOTE: /* impossible to get here */ #endif case OBJECTS_ERROR: break; } return EINVAL; }
int pthread_mutex_init( pthread_mutex_t *mutex, const pthread_mutexattr_t *attr ) { POSIX_Mutex_Control *the_mutex; CORE_mutex_Attributes *the_mutex_attr; const pthread_mutexattr_t *the_attr; CORE_mutex_Disciplines the_discipline; if ( attr ) the_attr = attr; else the_attr = &_POSIX_Mutex_Default_attributes; /* Check for NULL mutex */ if ( !mutex ) return EINVAL; /* * This code should eventually be removed. * * Although the POSIX specification says: * * "Attempting to initialize an already initialized mutex results * in undefined behavior." * * Trying to keep the caller from doing the create when *mutex * is actually a valid ID causes grief. All it takes is the wrong * value in an uninitialized variable to make this fail. As best * I can tell, RTEMS was the only pthread implementation to choose * this option for "undefined behavior" and doing so has created * portability problems. In particular, Rosimildo DaSilva * <*****@*****.**> saw seemingly random failures in the * RTEMS port of omniORB2 when this code was enabled. * * Joel Sherrill <*****@*****.**> 14 May 1999 * NOTE: Be careful to avoid infinite recursion on call to this * routine in _POSIX_Mutex_Get. */ #if 0 { POSIX_Mutex_Control *mutex_in_use; Objects_Locations location; if ( *mutex != PTHREAD_MUTEX_INITIALIZER ) { /* EBUSY if *mutex is a valid id */ mutex_in_use = _POSIX_Mutex_Get( mutex, &location ); switch ( location ) { case OBJECTS_LOCAL: _Objects_Put( &mutex_in_use->Object ); return EBUSY; #if defined(RTEMS_MULTIPROCESSING) case OBJECTS_REMOTE: #endif case OBJECTS_ERROR: break; } } } #endif if ( !the_attr->is_initialized ) return EINVAL; /* * We only support process private mutexes. */ if ( the_attr->process_shared == PTHREAD_PROCESS_SHARED ) return ENOSYS; if ( the_attr->process_shared != PTHREAD_PROCESS_PRIVATE ) return EINVAL; /* * Determine the discipline of the mutex */ switch ( the_attr->protocol ) { case PTHREAD_PRIO_NONE: the_discipline = CORE_MUTEX_DISCIPLINES_FIFO; break; case PTHREAD_PRIO_INHERIT: the_discipline = CORE_MUTEX_DISCIPLINES_PRIORITY_INHERIT; break; case PTHREAD_PRIO_PROTECT: the_discipline = CORE_MUTEX_DISCIPLINES_PRIORITY_CEILING; break; default: return EINVAL; } /* * Validate the priority ceiling field -- should always be valid. */ if ( !_POSIX_Priority_Is_valid( the_attr->prio_ceiling ) ) return EINVAL; #if defined(_UNIX98_THREAD_MUTEX_ATTRIBUTES) /* * Validate the mutex type and set appropriate SuperCore mutex * attributes. */ switch ( the_attr->type ) { case PTHREAD_MUTEX_NORMAL: case PTHREAD_MUTEX_RECURSIVE: case PTHREAD_MUTEX_ERRORCHECK: case PTHREAD_MUTEX_DEFAULT: break; default: return EINVAL; } #endif the_mutex = _POSIX_Mutex_Allocate(); if ( !the_mutex ) { _Objects_Allocator_unlock(); return EAGAIN; } the_mutex->process_shared = the_attr->process_shared; the_mutex_attr = &the_mutex->Mutex.Attributes; if ( the_attr->type == PTHREAD_MUTEX_RECURSIVE ) the_mutex_attr->lock_nesting_behavior = CORE_MUTEX_NESTING_ACQUIRES; else the_mutex_attr->lock_nesting_behavior = CORE_MUTEX_NESTING_IS_ERROR; the_mutex_attr->only_owner_release = true; the_mutex_attr->priority_ceiling = _POSIX_Priority_To_core( the_attr->prio_ceiling ); the_mutex_attr->discipline = the_discipline; /* * Must be initialized to unlocked. */ _CORE_mutex_Initialize( &the_mutex->Mutex, NULL, the_mutex_attr, false ); _Objects_Open_u32( &_POSIX_Mutex_Information, &the_mutex->Object, 0 ); *mutex = the_mutex->Object.id; _Objects_Allocator_unlock(); return 0; }
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; int rc; /* * Check all the parameters */ if ( !param ) return EINVAL; rc = _POSIX_Thread_Translate_sched_param( policy, param, &budget_algorithm, &budget_callout ); if ( rc ) return rc; /* * Actually change the scheduling policy and parameters */ the_thread = _Thread_Get( thread, &location ); switch ( location ) { 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; _Watchdog_Remove( &api->Sporadic_timer ); _POSIX_Threads_Sporadic_budget_TSR( 0, the_thread ); break; } _Thread_Enable_dispatch(); return 0; #if defined(RTEMS_MULTIPROCESSING) case OBJECTS_REMOTE: #endif case OBJECTS_ERROR: break; } return ESRCH; }
int pthread_setschedparam( pthread_t thread, int policy, struct sched_param *param ) { Thread_Control *the_thread; Per_CPU_Control *cpu_self; POSIX_API_Control *api; Thread_CPU_budget_algorithms budget_algorithm; Thread_CPU_budget_algorithm_callout budget_callout; int eno; Priority_Control unused; ISR_lock_Context lock_context; Priority_Control new_priority; /* * Check all the parameters */ if ( param == NULL ) { return EINVAL; } eno = _POSIX_Thread_Translate_sched_param( policy, param, &budget_algorithm, &budget_callout ); if ( eno != 0 ) { return eno; } the_thread = _Thread_Get_interrupt_disable( thread, &lock_context ); if ( the_thread == NULL ) { return ESRCH; } /* * Actually change the scheduling policy and parameters */ cpu_self = _Thread_Dispatch_disable_critical( &lock_context ); _Thread_State_acquire_critical( the_thread, &lock_context ); api = the_thread->API_Extensions[ THREAD_API_POSIX ]; if ( api->schedpolicy == SCHED_SPORADIC ) { _Watchdog_Per_CPU_remove_relative( &api->Sporadic_timer ); } api->schedpolicy = policy; api->schedparam = *param; api->Attributes.schedpolicy = policy; api->Attributes.schedparam = *param; the_thread->budget_algorithm = budget_algorithm; the_thread->budget_callout = budget_callout; switch ( policy ) { case SCHED_OTHER: case SCHED_FIFO: case SCHED_RR: the_thread->cpu_time_budget = rtems_configuration_get_ticks_per_timeslice(); new_priority = _POSIX_Priority_To_core( api->schedparam.sched_priority ); break; case SCHED_SPORADIC: api->ss_high_priority = api->schedparam.sched_priority; break; } _Thread_State_release( the_thread, &lock_context ); switch ( policy ) { case SCHED_OTHER: case SCHED_FIFO: case SCHED_RR: _Thread_Set_priority( the_thread, new_priority, &unused, true ); break; case SCHED_SPORADIC: _POSIX_Threads_Sporadic_budget_TSR( &api->Sporadic_timer ); break; } _Thread_Dispatch_enable( cpu_self ); return 0; }
static int _POSIX_Set_sched_param( Thread_Control *the_thread, int policy, struct sched_param *param, Thread_CPU_budget_algorithms budget_algorithm, Thread_CPU_budget_algorithm_callout budget_callout, Thread_queue_Context *queue_context ) { const Scheduler_Control *scheduler; POSIX_API_Control *api; int normal_prio; int low_prio; bool valid; Priority_Control core_normal_prio; Priority_Control core_low_prio; normal_prio = param->sched_priority; scheduler = _Thread_Scheduler_get_home( the_thread ); core_normal_prio = _POSIX_Priority_To_core( scheduler, normal_prio, &valid ); if ( !valid ) { return EINVAL; } if ( policy == SCHED_SPORADIC ) { low_prio = param->sched_ss_low_priority; } else { low_prio = normal_prio; } core_low_prio = _POSIX_Priority_To_core( scheduler, low_prio, &valid ); if ( !valid ) { return EINVAL; } api = the_thread->API_Extensions[ THREAD_API_POSIX ]; _Watchdog_Per_CPU_remove_monotonic( &api->Sporadic.Timer ); _Priority_Node_set_priority( &the_thread->Real_priority, core_normal_prio ); if ( _Priority_Node_is_active( &api->Sporadic.Low_priority ) ) { _Thread_Priority_add( the_thread, &the_thread->Real_priority, queue_context ); _Thread_Priority_remove( the_thread, &api->Sporadic.Low_priority, queue_context ); _Priority_Node_set_inactive( &api->Sporadic.Low_priority ); } else { _Thread_Priority_changed( the_thread, &the_thread->Real_priority, false, queue_context ); } the_thread->budget_algorithm = budget_algorithm; the_thread->budget_callout = budget_callout; _Priority_Node_set_priority( &api->Sporadic.Low_priority, core_low_prio ); api->Sporadic.sched_ss_repl_period = param->sched_ss_repl_period; api->Sporadic.sched_ss_init_budget = param->sched_ss_init_budget; api->Sporadic.sched_ss_max_repl = param->sched_ss_max_repl; if ( policy == SCHED_SPORADIC ) { _POSIX_Threads_Sporadic_timer_insert( the_thread, api ); } else { the_thread->cpu_time_budget = rtems_configuration_get_ticks_per_timeslice(); } return 0; }