Example #1
0
States_Control _Thread_Set_state(
  Thread_Control *the_thread,
  States_Control  state
)
{
  ISR_lock_Context lock_context;
  States_Control   previous_state;
  States_Control   next_state;

  _Assert( state != 0 );

  _Thread_State_acquire( the_thread, &lock_context );

  previous_state = the_thread->current_state;
  next_state = _States_Set( state, previous_state);
  the_thread->current_state = next_state;

  if ( _States_Is_ready( previous_state ) ) {
    _Scheduler_Block( the_thread );
  }

  _Thread_State_release( the_thread, &lock_context );

  return previous_state;
}
void _Thread_Set_transient(
  Thread_Control *the_thread
)
{
  ISR_Level             level;
  uint32_t              old_state;
  Chain_Control *ready;

  ready = the_thread->ready;
  _ISR_Disable( level );

  old_state = the_thread->current_state;
  the_thread->current_state = _States_Set( STATES_TRANSIENT, old_state );

  if ( _States_Is_ready( old_state ) ) {
    if ( _Chain_Has_only_one_node( ready ) ) {

      _Chain_Initialize_empty( ready );
      _Priority_Remove_from_bit_map( &the_thread->Priority_map );

    } else
      _Chain_Extract_unprotected( &the_thread->Object.Node );
  }

  _ISR_Enable( level );

}
Example #3
0
void _Scheduler_priority_Tick( void )
{
  Thread_Control *executing;

  executing = _Thread_Executing;

  #ifdef __RTEMS_USE_TICKS_FOR_STATISTICS__
    /*
     *  Increment the number of ticks this thread has been executing
     */
    executing->cpu_time_used++;
  #endif

  /*
   *  If the thread is not preemptible or is not ready, then
   *  just return.
   */

  if ( !executing->is_preemptible )
    return;

  if ( !_States_Is_ready( executing->current_state ) )
    return;

  /*
   *  The cpu budget algorithm determines what happens next.
   */

  switch ( executing->budget_algorithm ) {
    case THREAD_CPU_BUDGET_ALGORITHM_NONE:
      break;

    case THREAD_CPU_BUDGET_ALGORITHM_RESET_TIMESLICE:
    #if defined(RTEMS_SCORE_THREAD_ENABLE_EXHAUST_TIMESLICE)
      case THREAD_CPU_BUDGET_ALGORITHM_EXHAUST_TIMESLICE:
    #endif
      if ( (int)(--executing->cpu_time_budget) <= 0 ) {

        /*
         *  A yield performs the ready chain mechanics needed when
         *  resetting a timeslice.  If no other thread's are ready
         *  at the priority of the currently executing thread, then the
         *  executing thread's timeslice is reset.  Otherwise, the
         *  currently executing thread is placed at the rear of the
         *  FIFO for this priority and a new heir is selected.
         */
        _Scheduler_Yield();
        executing->cpu_time_budget = _Thread_Ticks_per_timeslice;
      }
      break;

    #if defined(RTEMS_SCORE_THREAD_ENABLE_SCHEDULER_CALLOUT)
      case THREAD_CPU_BUDGET_ALGORITHM_CALLOUT:
	if ( --executing->cpu_time_budget == 0 )
	  (*executing->budget_callout)( executing );
	break;
    #endif
  }
}
bool _Scheduler_priority_affinity_SMP_Set_affinity(
  const Scheduler_Control *scheduler,
  Thread_Control          *thread,
  size_t                   cpusetsize,
  const cpu_set_t         *cpuset
)
{
  Scheduler_priority_affinity_SMP_Node *node;
  States_Control                        current_state;

  /*
   * Validate that the cpset meets basic requirements.
   */
  if ( !_CPU_set_Is_valid( cpuset, cpusetsize ) ) {
    return false;
  }

  node = _Scheduler_priority_affinity_SMP_Thread_get_node( thread );

  /*
   * The old and new set are the same, there is no point in
   * doing anything.
   */
  if ( CPU_EQUAL_S( cpusetsize, cpuset, node->Affinity.set ) )
    return true;

  current_state = thread->current_state;

  if ( _States_Is_ready( current_state ) ) {
    _Scheduler_priority_affinity_SMP_Block( scheduler, thread );
  }

  CPU_COPY( node->Affinity.set, cpuset );

  if ( _States_Is_ready( current_state ) ) {
    /*
     * FIXME: Do not ignore threads in need for help.
     */
    (void) _Scheduler_priority_affinity_SMP_Unblock( scheduler, thread );
  }

  return true;
}
void _Thread_Tickle_timeslice( void )
{
  Thread_Control *executing;

  executing = _Thread_Executing;

  #ifdef __RTEMS_USE_TICKS_FOR_STATISTICS__
    /*
     *  Increment the number of ticks this thread has been executing
     */
    executing->cpu_time_used++;
  #endif

  /*
   *  If the thread is not preemptible or is not ready, then
   *  just return.
   */

  if ( !executing->is_preemptible )
    return;

  if ( !_States_Is_ready( executing->current_state ) )
    return;

  /*
   *  The cpu budget algorithm determines what happens next.
   */

  switch ( executing->budget_algorithm ) {
    case THREAD_CPU_BUDGET_ALGORITHM_NONE:
      break;

    case THREAD_CPU_BUDGET_ALGORITHM_RESET_TIMESLICE:
    #if defined(RTEMS_SCORE_THREAD_ENABLE_EXHAUST_TIMESLICE)
      case THREAD_CPU_BUDGET_ALGORITHM_EXHAUST_TIMESLICE:
    #endif
      if ( (int)(--executing->cpu_time_budget) <= 0 ) {
        _Thread_Reset_timeslice();
        executing->cpu_time_budget = _Thread_Ticks_per_timeslice;
      }
      break;

    #if defined(RTEMS_SCORE_THREAD_ENABLE_SCHEDULER_CALLOUT)
      case THREAD_CPU_BUDGET_ALGORITHM_CALLOUT:
	if ( --executing->cpu_time_budget == 0 )
	  (*executing->budget_callout)( executing );
	break;
    #endif
  }
}
bool _Thread_Evaluate_mode( void )
{
  Thread_Control     *executing;

  executing = _Thread_Executing;

  if ( !_States_Is_ready( executing->current_state ) ||
       ( !_Thread_Is_heir( executing ) && executing->is_preemptible ) ) {
    _Context_Switch_necessary = true;
    return true;
  }

  return false;
}
Example #7
0
void _Thread_Resume(
  Thread_Control   *the_thread,
  bool              force
)
{

  ISR_Level       level;
  States_Control  current_state;

  _ISR_Disable( level );

  #if defined(RTEMS_ITRON_API)
    if ( force == true )
      the_thread->suspend_count = 0;
    else
      the_thread->suspend_count--;

    if ( the_thread->suspend_count > 0 ) {
      _ISR_Enable( level );
      return;
    }
  #endif

  current_state = the_thread->current_state;
  if ( current_state & STATES_SUSPENDED ) {
    current_state =
    the_thread->current_state = _States_Clear(STATES_SUSPENDED, current_state);

    if ( _States_Is_ready( current_state ) ) {

      _Priority_Add_to_bit_map( &the_thread->Priority_map );

      _Chain_Append_unprotected(the_thread->ready, &the_thread->Object.Node);

      _ISR_Flash( level );

      if ( the_thread->current_priority < _Thread_Heir->current_priority ) {
        _Thread_Heir = the_thread;
        if ( _Thread_Executing->is_preemptible ||
             the_thread->current_priority == 0 )
          _Context_Switch_necessary = true;
      }
    }
  }

  _ISR_Enable( level );
}
void _Thread_Clear_state(
  Thread_Control *the_thread,
  States_Control  state
)
{
  ISR_Level       level;
  States_Control  current_state;

  _ISR_Disable( level );
    current_state = the_thread->current_state;

    if ( current_state & state ) {
      current_state =
      the_thread->current_state = _States_Clear( state, current_state );

      if ( _States_Is_ready( current_state ) ) {

        _Priority_Add_to_bit_map( &the_thread->Priority_map );

        _Chain_Append_unprotected(the_thread->ready, &the_thread->Object.Node);

        _ISR_Flash( level );

        /*
         *  If the thread that was unblocked is more important than the heir,
         *  then we have a new heir.  This may or may not result in a
         *  context switch.
         *
         *  Normal case:
         *    If the current thread is preemptible, then we need to do
         *    a context switch.
         *  Pseudo-ISR case:
         *    Even if the thread isn't preemptible, if the new heir is
         *    a pseudo-ISR system task, we need to do a context switch.
         */
        if ( the_thread->current_priority < _Thread_Heir->current_priority ) {
          _Thread_Heir = the_thread;
          if ( _Thread_Executing->is_preemptible ||
               the_thread->current_priority == 0 )
            _Context_Switch_necessary = true;
        }
      }
  }
  _ISR_Enable( level );
}
void _Thread_Set_transient(
  Thread_Control *the_thread
)
{
  ISR_Level             level;
  uint32_t              old_state;

  _ISR_Disable( level );

  old_state = the_thread->current_state;
  the_thread->current_state = _States_Set( STATES_TRANSIENT, old_state );

  if ( _States_Is_ready( old_state ) ) {
    _Scheduler_Extract( the_thread );
  }

  _ISR_Enable( level );

}
Example #10
0
/*
 *  INTERRUPT LATENCY:
 *    priority map
 *    select heir
 */
void _Thread_Clear_state(
  Thread_Control *the_thread,
  States_Control  state
)
{
  ISR_Level       level;
  States_Control  current_state;

  _ISR_Disable( level );
    current_state = the_thread->current_state;

    if ( current_state & state ) {
      current_state =
      the_thread->current_state = _States_Clear( state, current_state );

      if ( _States_Is_ready( current_state ) ) {
        _Scheduler_Unblock( the_thread );
      }
  }
  _ISR_Enable( level );
}
Example #11
0
void _Thread_Set_state(
  Thread_Control *the_thread,
  States_Control  state
)
{
  ISR_Level      level;
  States_Control current_state;

  _ISR_Disable( level );

  current_state = the_thread->current_state;
  if ( _States_Is_ready( current_state ) ) {
    the_thread->current_state = state;

    _Scheduler_Block( _Scheduler_Get( the_thread ), the_thread );
  } else {
    the_thread->current_state = _States_Set( state, current_state);
  }

  _ISR_Enable( level );
}
Example #12
0
void _Thread_Set_state(
  Thread_Control *the_thread,
  States_Control  state
)
{
  ISR_Level      level;

  _ISR_Disable( level );
  if ( !_States_Is_ready( the_thread->current_state ) ) {
    the_thread->current_state =
       _States_Set( state, the_thread->current_state );
    _ISR_Enable( level );
    return;
  }

  the_thread->current_state = state;

  _Scheduler_Block( the_thread );

  _ISR_Enable( level );
}
void _Thread_Suspend(
  Thread_Control   *the_thread
)
{
  ISR_Level      level;
  Chain_Control *ready;

  ready = the_thread->ready;
  _ISR_Disable( level );
  #if defined(RTEMS_ITRON_API)
    the_thread->suspend_count++;
  #endif
  if ( !_States_Is_ready( the_thread->current_state ) ) {
    the_thread->current_state =
       _States_Set( STATES_SUSPENDED, the_thread->current_state );
    _ISR_Enable( level );
    return;
  }

  the_thread->current_state = STATES_SUSPENDED;

  if ( _Chain_Has_only_one_node( ready ) ) {

    _Chain_Initialize_empty( ready );
    _Priority_Remove_from_bit_map( &the_thread->Priority_map );

  } else
    _Chain_Extract_unprotected( &the_thread->Object.Node );

  _ISR_Flash( level );

  if ( _Thread_Is_heir( the_thread ) )
     _Thread_Calculate_heir();

  if ( _Thread_Is_executing( the_thread ) )
    _Context_Switch_necessary = true;

  _ISR_Enable( level );
}
void _Thread_Set_state(
  Thread_Control *the_thread,
  States_Control  state
)
{
  ISR_Level      level;
  Chain_Control *ready;

  ready = the_thread->ready;
  _ISR_Disable( level );
  if ( !_States_Is_ready( the_thread->current_state ) ) {
    the_thread->current_state =
       _States_Set( state, the_thread->current_state );
    _ISR_Enable( level );
    return;
  }

  the_thread->current_state = state;

  if ( _Chain_Has_only_one_node( ready ) ) {

    _Chain_Initialize_empty( ready );
    _Priority_Remove_from_bit_map( &the_thread->Priority_map );

  } else
    _Chain_Extract_unprotected( &the_thread->Object.Node );

  _ISR_Flash( level );

  if ( _Thread_Is_heir( the_thread ) )
     _Thread_Calculate_heir();

  if ( _Thread_Is_executing( the_thread ) )
    _Context_Switch_necessary = TRUE;

  _ISR_Enable( level );
}
Example #15
0
void _Thread_Change_priority(
  Thread_Control                *the_thread,
  Priority_Control               new_priority,
  void                          *arg,
  Thread_Change_priority_filter  filter,
  bool                           prepend_it
)
{
  ISR_lock_Context  lock_context;
  ISR_lock_Control *lock;

  lock = _Thread_Lock_acquire( the_thread, &lock_context );

  /*
   * For simplicity set the priority restore hint unconditionally since this is
   * an average case optimization.  Otherwise complicated atomic operations
   * would be necessary.  Synchronize with a potential read of the resource
   * count in the filter function.  See also _CORE_mutex_Surrender(),
   * _Thread_Set_priority_filter() and _Thread_Restore_priority_filter().
   */
  the_thread->priority_restore_hint = true;
  _Atomic_Fence( ATOMIC_ORDER_ACQ_REL );

  /*
   *  Do not bother recomputing all the priority related information if
   *  we are not REALLY changing priority.
   */
  if ( ( *filter )( the_thread, &new_priority, arg ) ) {
    uint32_t my_generation;

    my_generation = the_thread->priority_generation + 1;
    the_thread->current_priority = new_priority;
    the_thread->priority_generation = my_generation;

    ( *the_thread->Wait.operations->priority_change )(
      the_thread,
      new_priority,
      the_thread->Wait.queue
    );

    _Thread_Lock_release( lock, &lock_context );

    _Thread_State_acquire( the_thread, &lock_context );

    if ( the_thread->priority_generation == my_generation ) {
      if ( _States_Is_ready( the_thread->current_state ) ) {
        _Scheduler_Change_priority(
          the_thread,
          new_priority,
          prepend_it
        );
      } else {
        _Scheduler_Update_priority( the_thread, new_priority );
      }
    }

    _Thread_State_release( the_thread, &lock_context );
  } else {
    _Thread_Lock_release( lock, &lock_context );
  }
}
Example #16
0
int killinfo(
  pid_t               pid,
  int                 sig,
  const union sigval *value
)
{
  sigset_t                     mask;
  POSIX_API_Control           *api;
  uint32_t                     the_api;
  uint32_t                     index;
  uint32_t                     maximum;
  Objects_Information         *the_info;
  Objects_Control            **object_table;
  Thread_Control              *the_thread;
  Thread_Control              *interested;
  Priority_Control             interested_priority;
  Chain_Control               *the_chain;
  Chain_Node                  *the_node;
  siginfo_t                    siginfo_struct;
  siginfo_t                   *siginfo;
  POSIX_signals_Siginfo_node  *psiginfo;

  /*
   *  Only supported for the "calling process" (i.e. this node).
   */
  if ( pid != getpid() )
    rtems_set_errno_and_return_minus_one( ESRCH );

  /*
   *  Validate the signal passed.
   */
  if ( !sig )
    rtems_set_errno_and_return_minus_one( EINVAL );

  if ( !is_valid_signo(sig) )
    rtems_set_errno_and_return_minus_one( EINVAL );

  /*
   *  If the signal is being ignored, then we are out of here.
   */
  if ( _POSIX_signals_Vectors[ sig ].sa_handler == SIG_IGN )
    return 0;

  /*
   *  P1003.1c/Draft 10, p. 33 says that certain signals should always
   *  be directed to the executing thread such as those caused by hardware
   *  faults.
   */
  if ( (sig == SIGFPE) || (sig == SIGILL) || (sig == SIGSEGV ) )
      return pthread_kill( pthread_self(), sig );

  mask = signo_to_mask( sig );

  /*
   *  Build up a siginfo structure
   */
  siginfo = &siginfo_struct;
  siginfo->si_signo = sig;
  siginfo->si_code = SI_USER;
  if ( !value ) {
    siginfo->si_value.sival_int = 0;
  } else {
    siginfo->si_value = *value;
  }

  _Thread_Disable_dispatch();

  /*
   *  Is the currently executing thread interested?  If so then it will
   *  get it an execute it as soon as the dispatcher executes.
   */
  the_thread = _Thread_Executing;

  api = the_thread->API_Extensions[ THREAD_API_POSIX ];
  if ( _POSIX_signals_Is_interested( api, mask ) ) {
    goto process_it;
  }

  /*
   *  Is an interested thread waiting for this signal (sigwait())?
   *
   *  There is no requirement on the order of threads pending on a sigwait().
   */

  /* XXX violation of visibility -- need to define thread queue support */

  the_chain = &_POSIX_signals_Wait_queue.Queues.Fifo;

  for ( the_node = _Chain_First( the_chain );
        !_Chain_Is_tail( the_chain, the_node ) ;
        the_node = the_node->next ) {

    the_thread = THREAD_CHAIN_NODE_TO_THREAD( the_node );
    api = the_thread->API_Extensions[ THREAD_API_POSIX ];

    #if defined(DEBUG_SIGNAL_PROCESSING)
      printk( "Waiting Thread=%p option=0x%08x mask=0x%08x blocked=0x%08x\n",
        the_thread, the_thread->Wait.option, mask, api->signals_blocked);
    #endif

    /*
     * Is this thread is actually blocked waiting for the signal?
     */
    if (the_thread->Wait.option & mask)
      goto process_it;

    /*
     * Is this thread is blocked waiting for another signal but has
     * not blocked this one?
     */
    if (~api->signals_blocked & mask)
      goto process_it;
  }

  /*
   *  Is any other thread interested?  The highest priority interested
   *  thread is selected.  In the event of a tie, then the following
   *  additional criteria is used:
   *
   *    + ready thread over blocked
   *    + blocked on call interruptible by signal (can return EINTR)
   *    + blocked on call not interruptible by signal
   *
   *  This looks at every thread in the system regardless of the creating API.
   *
   *  NOTES:
   *
   *    + rtems internal threads do not receive signals.
   */
  interested = NULL;
  interested_priority = PRIORITY_MAXIMUM + 1;

  for (the_api = OBJECTS_CLASSIC_API; the_api <= OBJECTS_APIS_LAST; the_api++) {

    /*
     *  This can occur when no one is interested and an API is not configured.
     */
    if ( !_Objects_Information_table[ the_api ] )
      continue;

    the_info = _Objects_Information_table[ the_api ][ 1 ];

    #if defined(RTEMS_DEBUG)
      /*
       *  This cannot happen in the current (as of June 2009) implementation
       *  of initialization but at some point, the object information
       *  structure for a particular manager may not be installed.
       */
      if ( !the_info )
        continue;
    #endif

    maximum = the_info->maximum;
    object_table = the_info->local_table;

    for ( index = 1 ; index <= maximum ; index++ ) {
      the_thread = (Thread_Control *) object_table[ index ];

      if ( !the_thread )
        continue;

      #if defined(DEBUG_SIGNAL_PROCESSING)
        printk("\n 0x%08x/0x%08x %d/%d 0x%08x 1",
          the_thread->Object.id,
          ((interested) ? interested->Object.id : 0),
          the_thread->current_priority, interested_priority,
          the_thread->current_state
        );
      #endif

      /*
       *  If this thread is of lower priority than the interested thread,
       *  go on to the next thread.
       */
      if ( the_thread->current_priority > interested_priority )
        continue;
      DEBUG_STEP("2");

      /*
       *  If this thread is not interested, then go on to the next thread.
       */
      api = the_thread->API_Extensions[ THREAD_API_POSIX ];

      #if defined(RTEMS_DEBUG)
        if ( !api )
          continue;
      #endif

      if ( !_POSIX_signals_Is_interested( api, mask ) )
        continue;
      DEBUG_STEP("3");

      /*
       *  Now we know the thread under consideration is interested.
       *  If the thread under consideration is of higher priority, then
       *  it becomes the interested thread.
       *
       *  NOTE: We initialized interested_priority to PRIORITY_MAXIMUM + 1
       *        so we never have to worry about deferencing a NULL
       *        interested thread.
       */
      if ( the_thread->current_priority < interested_priority ) {
        interested   = the_thread;
        interested_priority = the_thread->current_priority;
        continue;
      }
      DEBUG_STEP("4");

      /*
       *  Now the thread and the interested thread have the same priority.
       *  We have to sort through the combinations of blocked/not blocked
       *  and blocking interruptibutable by signal.
       *
       *  If the interested thread is ready, don't think about changing.
       */

      if ( interested && !_States_Is_ready( interested->current_state ) ) {
        /* preferred ready over blocked */
        DEBUG_STEP("5");
        if ( _States_Is_ready( the_thread->current_state ) ) {
          interested          = the_thread;
          interested_priority = the_thread->current_priority;
          continue;
        }

        DEBUG_STEP("6");
        /* prefer blocked/interruptible over blocked/not interruptible */
        if ( !_States_Is_interruptible_by_signal(interested->current_state) ) {
          DEBUG_STEP("7");
          if ( _States_Is_interruptible_by_signal(the_thread->current_state) ) {
            DEBUG_STEP("8");
            interested          = the_thread;
            interested_priority = the_thread->current_priority;
            continue;
          }
        }
      }
    }
  }

  if ( interested ) {
    the_thread = interested;
    goto process_it;
  }

  /*
   *  OK so no threads were interested right now.  It will be left on the
   *  global pending until a thread receives it.  The global set of threads
   *  can change interest in this signal in one of the following ways:
   *
   *    + a thread is created with the signal unblocked,
   *    + pthread_sigmask() unblocks the signal,
   *    + sigprocmask() unblocks the signal, OR
   *    + sigaction() which changes the handler to SIG_IGN.
   */
  the_thread = NULL;
  goto post_process_signal;

  /*
   *  We found a thread which was interested, so now we mark that this
   *  thread needs to do the post context switch extension so it can
   *  evaluate the signals pending.
   */
process_it:

  /*
   *  Returns true if the signal was synchronously given to a thread
   *  blocked waiting for the signal.
   */
  if ( _POSIX_signals_Unblock_thread( the_thread, sig, siginfo ) ) {
    _Thread_Enable_dispatch();
    return 0;
  }

post_process_signal:

  /*
   *  We may have woken up a thread but we definitely need to post the
   *  signal to the process wide information set.
   */
  _POSIX_signals_Set_process_signals( mask );

  if ( _POSIX_signals_Vectors[ sig ].sa_flags == SA_SIGINFO ) {

    psiginfo = (POSIX_signals_Siginfo_node *)
               _Chain_Get( &_POSIX_signals_Inactive_siginfo );
    if ( !psiginfo ) {
      _Thread_Enable_dispatch();
      rtems_set_errno_and_return_minus_one( EAGAIN );
    }

    psiginfo->Info = *siginfo;

    _Chain_Append( &_POSIX_signals_Siginfo[ sig ], &psiginfo->Node );
  }

  DEBUG_STEP("\n");
  _Thread_Enable_dispatch();
  return 0;
}
bool _Scheduler_simple_smp_Assign(
  Thread_Control *consider
)
{
  bool            found;       /* have we found a cpu to place it on? */
  uint32_t        found_cpu;   /* CPU to place this thread */
  bool            blocked;     /* CPU has blocked thread? */
  Thread_Control *pheir;       /* heir on found cpu to potentially replace */
  Thread_Control *h;
  Thread_Control *e;
  uint32_t        cpu;

  /*
   *  Initialize various variables to indicate we have not found
   *  a potential core for the thread under consideration.
   */
  found     = false;
  blocked   = false;
  found_cpu = 0;
  pheir     = NULL;

  for ( cpu=0 ; cpu < _SMP_Processor_count ; cpu++ ) {
    D( "SCHED CPU=%d consider=0x%08x ASSIGN\n", cpu, consider->Object.id );

    /*
     *  If the thread under consideration is already executing or
     *  heir, then we don't have a better option for it.
     */
    e = _Per_CPU_Information[cpu].executing;
    if ( e == consider ) {
      D( "SCHED CPU=%d Executing=0x%08x considering=0x%08x ASSIGNED\n",
        cpu, e->Object.id, consider->Object.id );
      return true;
    }

    if ( !_States_Is_ready( e->current_state ) ) {
      pheir     = e;
      found_cpu = cpu;
      found     = true;
      blocked   = true;
      D( "SCHED CPU=%d PHeir=0x%08x considering=0x%08x BLOCKED\n",
        cpu, e->Object.id, consider->Object.id );
      continue;
    }

    h = _Per_CPU_Information[cpu].heir;
    if ( h == consider ) {
      D( "SCHED CPU=%d Heir=0x%08x considering=0x%08x ASSIGNED\n",
        cpu, h->Object.id, consider->Object.id );
      return true;
    }

    if ( blocked )
      continue;

    /*
     *  If we haven't found a potential CPU to locate the thread
     *  under consideration on, we need to consider if this is a
     *  more important threads first (e.g. priority <).
     *
     *  But when a thread changes its priority and ends up at the end of
     *  the priority group for the new heir, we also need to schedule
     *  a new heir.  This is the "=" part of the check.
     */
    if ( !found ) {
      if ( consider->current_priority <= h->current_priority ) {
        pheir     = h;
        found_cpu = cpu;
        found     = true;
        D( "SCHED CPU=%d PHeir=0x%08x considering=0x%08x MAYBE #1\n",
          cpu, h->Object.id, consider->Object.id );
      }

      continue;
    }

    /*
     *  Past this point, found is true.
     */

    /*
     *  If we have found a potential CPU on which to make the
     *  thread under consideration the heir, then we need to
     *  check if the current CPU is a more appropriate place
     *  for this thread to be placed.
     *
     *  Check 1: heir of potential CPU is more important
     *           then heir of current CPU.  We want to
     *           replace the least important thread possible.
     */
    if ( h->current_priority > pheir->current_priority ) {
      pheir = h;
      found_cpu = cpu;
      D( "SCHED CPU=%d PHeir=0x%08x considering=0x%08x MAYBE #2\n",
        cpu, h->Object.id, consider->Object.id );
      continue;
    }

    if ( h->current_priority > pheir->current_priority )
      continue;

    /*
     *  If heir of potential CPU and of the current CPU are of the SAME
     *  priority, then which has been running longer?
     *
     *           Which CPU has had its executing thread longer?
     */
    if ( _Timestamp_Less_than(
           &_Per_CPU_Information[cpu].time_of_last_context_switch,
           &_Per_CPU_Information[found_cpu].time_of_last_context_switch
         ) ) {
      pheir = h;
      found_cpu = cpu;
      D( "SCHED CPU=%d PHeir=0x%08x considering=0x%08x LONGER\n",
        cpu, h->Object.id, consider->Object.id );
      continue;
    }

    /*
     *  If we are looking at a core with a non-preemptible thread
     *  for potential placement, then favor a core with a preeemtible
     *  thread of the same priority.  This should help avoid priority
     *  inversions and let threads run earlier.
     */
    if ( !pheir->is_preemptible && h->is_preemptible ) {
      D( "SCHED CPU=%d PHeir==0x%08x is NOT PREEMPTIBLE\n", 
        cpu, pheir->Object.id );
      pheir = h;
      found_cpu = cpu;
      D( "SCHED CPU=%d PHeir=0x%08x considering=0x%08x PREEMPTIBLE\n",
        cpu, h->Object.id, consider->Object.id );
      continue;

    }
  }

  /*
   *  If we found a cpu to make this thread heir of, then we
   *  need to consider whether we need a dispatch on that CPU.
   */
  if ( found ) {
    e = _Per_CPU_Information[found_cpu].executing;
    D( "SCHED CPU=%d executing=0x%08x considering=0x%08x FOUND\n",
      found_cpu, e->Object.id, consider->Object.id );
    _Per_CPU_Information[found_cpu].heir = consider;
    if ( !_States_Is_ready( e->current_state ) ) {
       D( "SCHED CPU=%d executing not ready dispatch needed\n", found_cpu);
      _Per_CPU_Information[found_cpu].dispatch_necessary = true;
    } else if ( consider->current_priority < e->current_priority ) {
      if ( e->is_preemptible || consider->current_priority == 0 ) {
         D( "SCHED CPU=%d preempting\n", found_cpu);
        _Per_CPU_Information[found_cpu].dispatch_necessary = true;
      }
    }
  }

  /*
   *  Return true to indicate we changed an heir.  This indicates
   *  scheduling needs to examine more threads.
   */
  return found;
}
Example #18
0
ER ref_tsk(
    T_RTSK *pk_rtsk,
    ID      tskid
)
{
    register Thread_Control *the_thread;
    Objects_Locations        location;
    Priority_Control         core_priority;

    if (!pk_rtsk)
        return E_PAR;

    the_thread = _ITRON_Task_Get( tskid, &location );
    switch ( location ) {
#if defined(RTEMS_MULTIPROCESSING)
    case OBJECTS_REMOTE:
#endif
    case OBJECTS_ERROR:
        return _ITRON_Task_Clarify_get_id_error( tskid );

    case OBJECTS_LOCAL:

        if ( location != OBJECTS_LOCAL )
            return  _ITRON_Task_Clarify_get_id_error( tskid );

        /*
         * The following are extended functions [level X ].
         * XXX - tskwait, wid, wupcnt, and tskatr are presently not implemented.
         */

        pk_rtsk->tskwait = 0;
        pk_rtsk->wid     = 0;
        pk_rtsk->wupcnt  = 0;
        pk_rtsk->suscnt  = the_thread->suspend_count;
        pk_rtsk->tskatr  = 0;       /* XXX - Not correctly implemented */
        pk_rtsk->task    = (FP) the_thread->Start.entry_point;
        core_priority    = the_thread->Start.initial_priority;
        pk_rtsk->itskpri = _ITRON_Task_Core_to_Priority( core_priority );
        pk_rtsk->stksz   = the_thread->Start.Initial_stack.size;

        /*
         * The following are required.
         */

        pk_rtsk->exinf   = NULL;   /* extended information */
        pk_rtsk->tskpri  =
            _ITRON_Task_Core_to_Priority(the_thread->current_priority);

        /*
         * Mask in the tskstat information
         * Convert the task state XXX double check this
         */

        pk_rtsk->tskstat = 0;
        if ( the_thread == _Thread_Executing )
            pk_rtsk->tskstat |= TTS_RUN;
        if ( _States_Is_ready(the_thread->current_state) )
            pk_rtsk->tskstat |= TTS_RDY;
        if ( _States_Is_dormant( the_thread->current_state) )
            pk_rtsk->tskstat |= TTS_DMT;
        if ( _States_Is_suspended(the_thread->current_state) )
            pk_rtsk->tskstat |= TTS_SUS;
        if ( _States_Is_blocked(the_thread->current_state) )
            pk_rtsk->tskstat |= TTS_WAI;

        break;
    }

    _ITRON_return_errorno( E_OK );

}