Example #1
0
/*
 *  _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( &param->sched_ss_repl_period ) <
	 _Timespec_To_ticks( &param->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;
}
Example #3
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 );
}
/*
 * 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 );
}
Example #5
0
/*
 *  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( &current_time );

  if ( _Timespec_Less_than( abstime, &current_time ) )
    return TOD_ABSOLUTE_TIMEOUT_IS_IN_PAST;

  /*
   *  How long until the requested absolute time?
   */
  _Timespec_Subtract( &current_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;
}
Example #7
0
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;
}
Example #8
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 */
}
Example #10
0
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;
}