summaryrefslogblamecommitdiffstats
path: root/cpukit/score/include/rtems/score/schedulersmpimpl.h
blob: df2a85b6f644b25c3e77c4154c4c6bdc37f79791 (plain) (tree)
1
2
3
4
5
6
7
8
9








                                      
                                                                      








                                                          
                                        





                                       

                                            
                                  










                                


















                                                             


                                             
 
                                              

 




                                                     

                                                                   


















                                                             
                                           














                                                                               




                                                                  
                                              







                                                               





























































































































                                                                                   
                     










                                                        
                     




                                                










                                                                      






                                            
/**
 * @file
 *
 * @brief SMP Scheduler Implementation
 *
 * @ingroup ScoreSchedulerSMP
 */

/*
 * Copyright (c) 2013-2014 embedded brains GmbH.  All rights reserved.
 *
 *  embedded brains GmbH
 *  Dornierstr. 4
 *  82178 Puchheim
 *  Germany
 *  <rtems@embedded-brains.de>
 *
 * The license and distribution terms for this file may be
 * found in the file LICENSE in this distribution or at
 * http://www.rtems.org/license/LICENSE.
 */

#ifndef _RTEMS_SCORE_SCHEDULERSMPIMPL_H
#define _RTEMS_SCORE_SCHEDULERSMPIMPL_H

#include <rtems/score/schedulersmp.h>
#include <rtems/score/schedulersimpleimpl.h>
#include <rtems/score/chainimpl.h>
#include <rtems/score/scheduler.h>

#ifdef __cplusplus
extern "C" {
#endif /* __cplusplus */

/**
 * @addtogroup ScoreSchedulerSMP
 *
 * @{
 */

typedef Thread_Control *( *Scheduler_SMP_Get_highest_ready )(
  Scheduler_SMP_Control *self
);

typedef void ( *Scheduler_SMP_Extract )(
  Scheduler_SMP_Control *self,
  Thread_Control *thread
);

typedef void ( *Scheduler_SMP_Insert )(
  Scheduler_SMP_Control *self,
  Thread_Control *thread_to_insert
);

typedef void ( *Scheduler_SMP_Move )(
  Scheduler_SMP_Control *self,
  Thread_Control *thread_to_move
);

static inline void _Scheduler_SMP_Initialize(
  Scheduler_SMP_Control *self
)
{
  _Chain_Initialize_empty( &self->Scheduled );
}

static inline void _Scheduler_SMP_Allocate_processor(
  Thread_Control *scheduled,
  Thread_Control *victim
)
{
  Per_CPU_Control *cpu_of_scheduled = _Thread_Get_CPU( scheduled );
  Per_CPU_Control *cpu_of_victim = _Thread_Get_CPU( victim );
  Thread_Control *heir;

  scheduled->is_scheduled = true;
  victim->is_scheduled = false;

  _Per_CPU_Acquire( cpu_of_scheduled );

  if ( scheduled->is_executing ) {
    heir = cpu_of_scheduled->heir;
    cpu_of_scheduled->heir = scheduled;
  } else {
    heir = scheduled;
  }

  _Per_CPU_Release( cpu_of_scheduled );

  if ( heir != victim ) {
    const Per_CPU_Control *cpu_of_executing = _Per_CPU_Get();

    _Thread_Set_CPU( heir, cpu_of_victim );

    /*
     * FIXME: Here we need atomic store operations with a relaxed memory order.
     * The _CPU_SMP_Send_interrupt() will ensure that the change can be
     * observed consistently.
     */
    cpu_of_victim->heir = heir;
    cpu_of_victim->dispatch_necessary = true;

    if ( cpu_of_victim != cpu_of_executing ) {
      _Per_CPU_Send_interrupt( cpu_of_victim );
    }
  }
}

static inline Thread_Control *_Scheduler_SMP_Get_lowest_scheduled(
  Scheduler_SMP_Control *self
)
{
  Thread_Control *lowest_ready = NULL;
  Chain_Control *scheduled = &self->Scheduled;

  if ( !_Chain_Is_empty( scheduled ) ) {
    lowest_ready = (Thread_Control *) _Chain_Last( scheduled );
  }

  return lowest_ready;
}

static inline void _Scheduler_SMP_Enqueue_ordered(
  Scheduler_SMP_Control *self,
  Thread_Control *thread,
  Chain_Node_order order,
  Scheduler_SMP_Get_highest_ready get_highest_ready,
  Scheduler_SMP_Insert insert_ready,
  Scheduler_SMP_Insert insert_scheduled,
  Scheduler_SMP_Move move_from_ready_to_scheduled,
  Scheduler_SMP_Move move_from_scheduled_to_ready
)
{
  if ( thread->is_in_the_air ) {
    Thread_Control *highest_ready = ( *get_highest_ready )( self );

    thread->is_in_the_air = false;

    /*
     * The thread has been extracted from the scheduled chain.  We have to
     * place it now on the scheduled or ready chain.
     *
     * NOTE: Do not exchange parameters to do the negation of the order check.
     */
    if (
      highest_ready != NULL
        && !( *order )( &thread->Object.Node, &highest_ready->Object.Node )
    ) {
      _Scheduler_SMP_Allocate_processor( highest_ready, thread );

      ( *insert_ready )( self, thread );
      ( *move_from_ready_to_scheduled )( self, highest_ready );
    } else {
      thread->is_scheduled = true;

      ( *insert_scheduled )( self, thread );
    }
  } else {
    Thread_Control *lowest_scheduled = _Scheduler_SMP_Get_lowest_scheduled( self );

    /*
     * The scheduled chain is empty if nested interrupts change the priority of
     * all scheduled threads.  These threads are in the air.
     */
    if (
      lowest_scheduled != NULL
        && ( *order )( &thread->Object.Node, &lowest_scheduled->Object.Node )
    ) {
      _Scheduler_SMP_Allocate_processor( thread, lowest_scheduled );

      ( *insert_scheduled )( self, thread );
      ( *move_from_scheduled_to_ready )( self, lowest_scheduled );
    } else {
      ( *insert_ready )( self, thread );
    }
  }
}

static inline void _Scheduler_SMP_Schedule_highest_ready(
  Scheduler_SMP_Control *self,
  Thread_Control *victim,
  Scheduler_SMP_Get_highest_ready get_highest_ready,
  Scheduler_SMP_Move move_from_ready_to_scheduled
)
{
  Thread_Control *highest_ready = ( *get_highest_ready )( self );

  _Scheduler_SMP_Allocate_processor( highest_ready, victim );

  ( *move_from_ready_to_scheduled )( self, highest_ready );
}

static inline void _Scheduler_SMP_Block(
  Scheduler_SMP_Control *self,
  Thread_Control *thread,
  Scheduler_SMP_Extract extract,
  Scheduler_SMP_Get_highest_ready get_highest_ready,
  Scheduler_SMP_Move move_from_ready_to_scheduled
)
{
  ( *extract )( self, thread );

  if ( thread->is_in_the_air ) {
    thread->is_in_the_air = false;

    _Scheduler_SMP_Schedule_highest_ready(
      self,
      thread,
      get_highest_ready,
      move_from_ready_to_scheduled
    );
  }
}

static inline void _Scheduler_SMP_Extract(
  Scheduler_SMP_Control *self,
  Thread_Control *thread,
  Scheduler_SMP_Extract extract
)
{
  ( *extract )( self, thread );
}

static inline void _Scheduler_SMP_Schedule(
  Scheduler_SMP_Control *self,
  Thread_Control *thread,
  Scheduler_SMP_Get_highest_ready get_highest_ready,
  Scheduler_SMP_Move move_from_ready_to_scheduled
)
{
  if ( thread->is_in_the_air ) {
    thread->is_in_the_air = false;

    _Scheduler_SMP_Schedule_highest_ready(
      self,
      thread,
      get_highest_ready,
      move_from_ready_to_scheduled
    );
  }
}

static inline void _Scheduler_SMP_Insert_scheduled_lifo(
  Scheduler_SMP_Control *self,
  Thread_Control *thread
)
{
  _Chain_Insert_ordered_unprotected(
    &self->Scheduled,
    &thread->Object.Node,
    _Scheduler_simple_Insert_priority_lifo_order
  );
}

static inline void _Scheduler_SMP_Insert_scheduled_fifo(
  Scheduler_SMP_Control *self,
  Thread_Control *thread
)
{
  _Chain_Insert_ordered_unprotected(
    &self->Scheduled,
    &thread->Object.Node,
    _Scheduler_simple_Insert_priority_fifo_order
  );
}

static inline void _Scheduler_SMP_Start_idle(
  Scheduler_SMP_Control *self,
  Thread_Control *thread,
  Per_CPU_Control *cpu
)
{
  thread->is_scheduled = true;
  _Thread_Set_CPU( thread, cpu );
  _Chain_Append_unprotected( &self->Scheduled, &thread->Object.Node );
}

/** @} */

#ifdef __cplusplus
}
#endif /* __cplusplus */

#endif /* _RTEMS_SCORE_SCHEDULERSMPIMPL_H */