/* * _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 _POSIX_Thread_Translate_sched_param( int policy, struct sched_param *param, Thread_CPU_budget_algorithms *budget_algorithm, Thread_CPU_budget_algorithm_callout *budget_callout ) { if ( !_POSIX_Priority_Is_valid( param->sched_priority ) ) return EINVAL; *budget_algorithm = THREAD_CPU_BUDGET_ALGORITHM_NONE; *budget_callout = NULL; if ( policy == SCHED_OTHER ) { *budget_algorithm = THREAD_CPU_BUDGET_ALGORITHM_RESET_TIMESLICE; return 0; } if ( policy == SCHED_FIFO ) { *budget_algorithm = THREAD_CPU_BUDGET_ALGORITHM_NONE; return 0; } if ( policy == SCHED_RR ) { *budget_algorithm = THREAD_CPU_BUDGET_ALGORITHM_EXHAUST_TIMESLICE; return 0; } if ( policy == SCHED_SPORADIC ) { if ( (param->sched_ss_repl_period.tv_sec == 0) && (param->sched_ss_repl_period.tv_nsec == 0) ) return EINVAL; if ( (param->sched_ss_init_budget.tv_sec == 0) && (param->sched_ss_init_budget.tv_nsec == 0) ) return EINVAL; if ( _Timespec_To_ticks( ¶m->sched_ss_repl_period ) < _Timespec_To_ticks( ¶m->sched_ss_init_budget ) ) return EINVAL; if ( !_POSIX_Priority_Is_valid( param->sched_ss_low_priority ) ) return EINVAL; *budget_algorithm = THREAD_CPU_BUDGET_ALGORITHM_CALLOUT; *budget_callout = _POSIX_Threads_Sporadic_budget_callout; return 0; } return EINVAL; }
/* * _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 ); }
/* * Compute number of ticks in the specified amount of time. */ int tvtohz(struct timeval *tv) { struct timespec ts; ts.tv_sec = tv->tv_sec; ts.tv_nsec = tv->tv_usec * 1000; return (int) _Timespec_To_ticks( &ts ); }
/* * The abstime is a walltime. We turn it into an interval. */ TOD_Absolute_timeout_conversion_results _TOD_Absolute_timeout_to_ticks( const struct timespec *abstime, Watchdog_Interval *ticks_out ) { struct timespec current_time; struct timespec difference; /* * Make sure there is always a value returned. */ *ticks_out = 0; /* * Is the absolute time even valid? */ if ( !_Timespec_Is_valid(abstime) ) return TOD_ABSOLUTE_TIMEOUT_INVALID; /* * Is the absolute time in the past? */ _TOD_Get_as_timespec( ¤t_time ); if ( _Timespec_Less_than( abstime, ¤t_time ) ) return TOD_ABSOLUTE_TIMEOUT_IS_IN_PAST; /* * How long until the requested absolute time? */ _Timespec_Subtract( ¤t_time, abstime, &difference ); /* * Internally the SuperCore uses ticks, so convert to them. */ *ticks_out = _Timespec_To_ticks( &difference ); /* * If the difference was 0, then the future is now. It is so bright * we better wear shades. */ if ( !*ticks_out ) return TOD_ABSOLUTE_TIMEOUT_IS_NOW; /* * This is the case we were expecting and it took this long to * get here. */ return TOD_ABSOLUTE_TIMEOUT_IS_IN_FUTURE; }
int sigtimedwait( const sigset_t *set, siginfo_t *info, const struct timespec *timeout ) { Thread_Control *the_thread; POSIX_API_Control *api; Watchdog_Interval interval; siginfo_t signal_information; siginfo_t *the_info; int signo; ISR_Level level; /* * Error check parameters before disabling interrupts. */ if ( !set ) rtems_set_errno_and_return_minus_one( EINVAL ); /* NOTE: This is very specifically a RELATIVE not ABSOLUTE time * in the Open Group specification. */ interval = 0; if ( timeout ) { if ( !_Timespec_Is_valid( timeout ) ) rtems_set_errno_and_return_minus_one( EINVAL ); interval = _Timespec_To_ticks( timeout ); if ( !interval ) rtems_set_errno_and_return_minus_one( EINVAL ); } /* * Initialize local variables. */ the_info = ( info ) ? info : &signal_information; the_thread = _Thread_Executing; api = the_thread->API_Extensions[ THREAD_API_POSIX ]; /* * What if they are already pending? */ /* API signals pending? */ _ISR_Disable( level ); if ( *set & api->signals_pending ) { /* XXX real info later */ the_info->si_signo = _POSIX_signals_Get_highest( api->signals_pending ); _POSIX_signals_Clear_signals( api, the_info->si_signo, the_info, false, false ); _ISR_Enable( level ); the_info->si_code = SI_USER; the_info->si_value.sival_int = 0; return the_info->si_signo; } /* Process pending signals? */ if ( *set & _POSIX_signals_Pending ) { signo = _POSIX_signals_Get_highest( _POSIX_signals_Pending ); _POSIX_signals_Clear_signals( api, signo, the_info, true, false ); _ISR_Enable( level ); the_info->si_signo = signo; the_info->si_code = SI_USER; the_info->si_value.sival_int = 0; return signo; } the_info->si_signo = -1; _Thread_Disable_dispatch(); the_thread->Wait.queue = &_POSIX_signals_Wait_queue; the_thread->Wait.return_code = EINTR; the_thread->Wait.option = *set; the_thread->Wait.return_argument = the_info; _Thread_queue_Enter_critical_section( &_POSIX_signals_Wait_queue ); _ISR_Enable( level ); _Thread_queue_Enqueue( &_POSIX_signals_Wait_queue, interval ); _Thread_Enable_dispatch(); /* * When the thread is set free by a signal, it is need to eliminate * the signal. */ _POSIX_signals_Clear_signals( api, the_info->si_signo, the_info, false, false ); errno = _Thread_Executing->Wait.return_code; return the_info->si_signo; }
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; }
/* * 14.2.5 High Resolution Sleep, P1003.1b-1993, p. 269 */ int nanosleep( const struct timespec *rqtp, struct timespec *rmtp ) { /* * It is critical to obtain the executing thread after thread dispatching is * disabled on SMP configurations. */ Thread_Control *executing; Watchdog_Interval ticks; Watchdog_Interval elapsed; /* * Return EINVAL if the delay interval is negative. * * NOTE: This behavior is beyond the POSIX specification. * FSU and GNU/Linux pthreads shares this behavior. */ if ( !_Timespec_Is_valid( rqtp ) ) rtems_set_errno_and_return_minus_one( EINVAL ); /* * Convert the timespec delay into the appropriate number of clock ticks. */ ticks = _Timespec_To_ticks( rqtp ); /* * A nanosleep for zero time is implemented as a yield. * This behavior is also beyond the POSIX specification but is * consistent with the RTEMS API and yields desirable behavior. */ if ( !ticks ) { _Thread_Disable_dispatch(); executing = _Thread_Executing; _Thread_Yield( executing ); _Thread_Enable_dispatch(); if ( rmtp ) { rmtp->tv_sec = 0; rmtp->tv_nsec = 0; } return 0; } /* * Block for the desired amount of time */ _Thread_Disable_dispatch(); executing = _Thread_Executing; _Thread_Set_state( executing, STATES_DELAYING | STATES_INTERRUPTIBLE_BY_SIGNAL ); _Watchdog_Initialize( &executing->Timer, _Thread_Delay_ended, 0, executing ); _Watchdog_Insert_ticks( &executing->Timer, ticks ); _Thread_Enable_dispatch(); /* * Calculate the time that passed while we were sleeping and how * much remains from what we requested. */ elapsed = executing->Timer.stop_time - executing->Timer.start_time; if ( elapsed >= ticks ) ticks = 0; else ticks -= elapsed; /* * If the user wants the time remaining, do the conversion. */ if ( rmtp ) { _Timespec_From_ticks( ticks, rmtp ); } /* * Only when POSIX is enabled, can a sleep be interrupted. */ #if defined(RTEMS_POSIX_API) /* * If there is time remaining, then we were interrupted by a signal. */ if ( ticks ) rtems_set_errno_and_return_minus_one( EINTR ); #endif return 0; }
int timer_settime( timer_t timerid, int flags, const struct itimerspec *value, struct itimerspec *ovalue ) { POSIX_Timer_Control *ptimer; Objects_Locations location; boolean activated; if ( value == NULL ) { rtems_set_errno_and_return_minus_one( EINVAL ); } /* First, it verifies if the structure "value" is correct */ if ( ( value->it_value.tv_nsec > TOD_NANOSECONDS_PER_SECOND ) || ( value->it_value.tv_nsec < 0 ) ) { /* The number of nanoseconds is not correct */ rtems_set_errno_and_return_minus_one( EINVAL ); } /* XXX check for seconds in the past */ if ( flags != TIMER_ABSTIME && flags != POSIX_TIMER_RELATIVE ) { rtems_set_errno_and_return_minus_one( EINVAL ); } /* If the function reaches this point, then it will be necessary to do * something with the structure of times of the timer: to stop, start * or start it again */ ptimer = _POSIX_Timer_Get( timerid, &location ); switch ( location ) { case OBJECTS_REMOTE: #if defined(RTEMS_MULTIPROCESSING) _Thread_Dispatch(); return -1; rtems_set_errno_and_return_minus_one( EINVAL ); #endif case OBJECTS_ERROR: return -1; case OBJECTS_LOCAL: /* First, it verifies if the timer must be stopped */ if ( value->it_value.tv_sec == 0 && value->it_value.tv_nsec == 0 ) { /* Stop the timer */ (void) _Watchdog_Remove( &ptimer->Timer ); /* The old data of the timer are returned */ if ( ovalue ) *ovalue = ptimer->timer_data; /* The new data are set */ ptimer->timer_data = *value; /* Indicates that the timer is created and stopped */ ptimer->state = POSIX_TIMER_STATE_CREATE_STOP; /* Returns with success */ _Thread_Enable_dispatch(); return 0; } /* absolute or relative? */ switch (flags) { case TIMER_ABSTIME: /* The fire time is absolute: use "rtems_time_fire_when" */ /* First, it converts from struct itimerspec to rtems_time_of_day */ _Watchdog_Initialize( &ptimer->Timer, _POSIX_Timer_TSR, ptimer->Object.id, ptimer ); _Watchdog_Insert_seconds( &ptimer->Timer, value->it_value.tv_sec - _TOD_Seconds_since_epoch ); /* Returns the old ones in "ovalue" */ if ( ovalue ) *ovalue = ptimer->timer_data; ptimer->timer_data = *value; /* Indicate that the time is running */ ptimer->state = POSIX_TIMER_STATE_CREATE_RUN; /* Stores the time in which the timer was started again */ _TOD_Get( &ptimer->time ); _Thread_Enable_dispatch(); return 0; break; /* The fire time is relative: use "rtems_time_fire_after" */ case POSIX_TIMER_RELATIVE: /* First, convert from seconds and nanoseconds to ticks */ ptimer->ticks = _Timespec_To_ticks( &value->it_value ); activated = _Watchdog_Insert_ticks_helper( &ptimer->Timer, ptimer->ticks, ptimer->Object.id, _POSIX_Timer_TSR, ptimer ); if ( !activated ) { _Thread_Enable_dispatch(); return 0; } /* The timer has been started and is running */ /* return the old ones in "ovalue" */ if ( ovalue ) *ovalue = ptimer->timer_data; ptimer->timer_data = *value; /* Indicate that the time is running */ ptimer->state = POSIX_TIMER_STATE_CREATE_RUN; _TOD_Get( &ptimer->time ); _Thread_Enable_dispatch(); return 0; } _Thread_Enable_dispatch(); rtems_set_errno_and_return_minus_one( EINVAL ); } return -1; /* unreached - only to remove warnings */ }
int nanosleep( const struct timespec *rqtp, struct timespec *rmtp ) { Watchdog_Interval ticks; /* * Return EINVAL if the delay interval is negative. * * NOTE: This behavior is beyond the POSIX specification. * FSU and GNU/Linux pthreads shares this behavior. */ if ( !_Timespec_Is_valid( rqtp ) ) rtems_set_errno_and_return_minus_one( EINVAL ); ticks = _Timespec_To_ticks( rqtp ); /* * A nanosleep for zero time is implemented as a yield. * This behavior is also beyond the POSIX specification but is * consistent with the RTEMS API and yields desirable behavior. */ if ( !ticks ) { _Thread_Disable_dispatch(); _Scheduler_Yield(); _Thread_Enable_dispatch(); if ( rmtp ) { rmtp->tv_sec = 0; rmtp->tv_nsec = 0; } return 0; } /* * Block for the desired amount of time */ _Thread_Disable_dispatch(); _Thread_Set_state( _Thread_Executing, STATES_DELAYING | STATES_INTERRUPTIBLE_BY_SIGNAL ); _Watchdog_Initialize( &_Thread_Executing->Timer, _Thread_Delay_ended, _Thread_Executing->Object.id, NULL ); _Watchdog_Insert_ticks( &_Thread_Executing->Timer, ticks ); _Thread_Enable_dispatch(); /* calculate time remaining */ if ( rmtp ) { ticks -= _Thread_Executing->Timer.stop_time - _Thread_Executing->Timer.start_time; _Timespec_From_ticks( ticks, rmtp ); /* * Only when POSIX is enabled, can a sleep be interrupted. */ #if defined(RTEMS_POSIX_API) /* * If there is time remaining, then we were interrupted by a signal. */ if ( ticks ) rtems_set_errno_and_return_minus_one( EINTR ); #endif } return 0; }