<div dir="ltr">Hi,<br><div><br></div><div>Thanks a lot for this detailed review. I will work on each point that you mentioned.</div></div><br><div class="gmail_quote"><div dir="ltr" class="gmail_attr">On Mon, Aug 24, 2020 at 11:07 PM Gedare Bloom <<a href="mailto:gedare@rtems.org">gedare@rtems.org</a>> wrote:<br></div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex">On Mon, Aug 24, 2020 at 10:14 AM Richi Dubey <<a href="mailto:richidubey@gmail.com" target="_blank">richidubey@gmail.com</a>> wrote:<br>
><br>
> ---<br>
>  cpukit/include/rtems/scheduler.h              |   6 +-<br>
>  .../include/rtems/score/schedulerstrongapa.h  | 284 ++++--<br>
>  cpukit/score/src/schedulerstrongapa.c         | 913 ++++++++++++++----<br>
>  3 files changed, 901 insertions(+), 302 deletions(-)<br>
><br>
> diff --git a/cpukit/include/rtems/scheduler.h b/cpukit/include/rtems/scheduler.h<br>
> index 955a83cfb4..b101842ba7 100644<br>
> --- a/cpukit/include/rtems/scheduler.h<br>
> +++ b/cpukit/include/rtems/scheduler.h<br>
> @@ -257,16 +257,14 @@<br>
>    #define RTEMS_SCHEDULER_STRONG_APA( name, prio_count ) \<br>
>      static struct { \<br>
>        Scheduler_strong_APA_Context Base; \<br>
> -      Chain_Control                Ready[ ( prio_count ) ]; \<br>
> +      Scheduler_strong_APA_Struct Struct[ CONFIGURE_MAXIMUM_PROCESSORS ]; \<br>
<br>
I don't like this name at all either the type or the variable<br>
"Struct". Just like I wouldn't call a variable<br>
   int Int;<br>
<br>
>      } SCHEDULER_STRONG_APA_CONTEXT_NAME( name )<br>
><br>
>    #define RTEMS_SCHEDULER_TABLE_STRONG_APA( name, obj_name ) \<br>
>      { \<br>
>        &SCHEDULER_STRONG_APA_CONTEXT_NAME( name ).Base.Base.Base, \<br>
>        SCHEDULER_STRONG_APA_ENTRY_POINTS, \<br>
> -      RTEMS_ARRAY_SIZE( \<br>
> -        SCHEDULER_STRONG_APA_CONTEXT_NAME( name ).Ready \<br>
> -      ) - 1, \<br>
> +      SCHEDULER_STRONG_APA_MAXIMUM_PRIORITY, \<br>
>        ( obj_name ) \<br>
>        SCHEDULER_CONTROL_IS_NON_PREEMPT_MODE_SUPPORTED( false ) \<br>
>      }<br>
> diff --git a/cpukit/include/rtems/score/schedulerstrongapa.h b/cpukit/include/rtems/score/schedulerstrongapa.h<br>
> index 0ac28cb439..86d91688e8 100644<br>
> --- a/cpukit/include/rtems/score/schedulerstrongapa.h<br>
> +++ b/cpukit/include/rtems/score/schedulerstrongapa.h<br>
> @@ -6,31 +6,38 @@<br>
>   * @brief Strong APA Scheduler API<br>
>   */<br>
><br>
> -/*<br>
> - * Copyright (c) 2013, 2018 embedded brains GmbH.  All rights reserved.<br>
> +/*<br>
> + * Copyright (c) 2020 Richi Dubey<br>
>   *<br>
> - *  embedded brains GmbH<br>
> - *  Dornierstr. 4<br>
> - *  82178 Puchheim<br>
> - *  Germany<br>
> - *  <<a href="mailto:rtems@embedded-brains.de" target="_blank">rtems@embedded-brains.de</a>><br>
> + *  <<a href="mailto:richidubey@gmail.com" target="_blank">richidubey@gmail.com</a>><br>
>   *<br>
> - * The license and distribution terms for this file may be<br>
> - * found in the file LICENSE in this distribution or at<br>
> + * Copyright (c) 2013, 2018 embedded brains GmbH. All rights reserved.<br>
> + *<br>
> + *  embedded brains GmbH<br>
> + *  Dornierstr. 4<br>
> + *  82178 Puchheim<br>
> + *  Germany<br>
> + *  <<a href="mailto:rtems@embedded-brains.de" target="_blank">rtems@embedded-brains.de</a>><br>
> + *<br>
> + * The license and distribution terms for this file may be<br>
> + * found in the file LICENSE in this distribution or at<br>
>   * <a href="http://www.rtems.org/license/LICENSE" rel="noreferrer" target="_blank">http://www.rtems.org/license/LICENSE</a>.<br>
relicense 2-bsd -- EB allows it, and your new code should be put under it<br>
<br>
>   */<br>
> -<br>
> +<br>
>  #ifndef _RTEMS_SCORE_SCHEDULERSTRONGAPA_H<br>
>  #define _RTEMS_SCORE_SCHEDULERSTRONGAPA_H<br>
><br>
>  #include <rtems/score/scheduler.h><br>
> -#include <rtems/score/schedulerpriority.h><br>
>  #include <rtems/score/schedulersmp.h><br>
> +#include <rtems/score/percpu.h><br>
><br>
>  #ifdef __cplusplus<br>
>  extern "C" {<br>
>  #endif /* __cplusplus */<br>
><br>
> +#define STRONG_SCHEDULER_NODE_OF_CHAIN( node ) \<br>
> +  RTEMS_CONTAINER_OF( next, Scheduler_strong_APA_Node, Chain )<br>
somehow this is not using 'node' parameter?<br>
<br>
> +<br>
>  /**<br>
>   * @defgroup RTEMSScoreSchedulerStrongAPA Strong APA Scheduler<br>
>   *<br>
> @@ -38,43 +45,98 @@ extern "C" {<br>
>   *<br>
>   * @brief Strong APA Scheduler<br>
>   *<br>
> - * This is an implementation of the global fixed priority scheduler (G-FP).  It<br>
> - * uses one ready chain per priority to ensure constant time insert operations.<br>
> - * The scheduled chain uses linear insert operations and has at most processor<br>
> - * count entries.  Since the processor and priority count are constants all<br>
> - * scheduler operations complete in a bounded execution time.<br>
> + * This is an implementation of the Strong APA scheduler defined by<br>
> + * Cerqueira et al. in Linux's Processor Affinity API, Refined:<br>
> + * Shifting Real-Time Tasks Towards Higher Schedulability.<br>
>   *<br>
> - * The the_thread preempt mode will be ignored.<br>
> + * This is an implementation of the Strong APA scheduler defined by<br>
> + * Cerqueira et al. in Linux's Processor Affinity API, Refined:<br>
> + * Shifting Real-Time Tasks Towards Higher Schedulability.<br>
repeating text?<br>
<br>
You should add a bit more comment about the high-level design here. Of<br>
course anyone wanting more details can go to the paper.<br>
<br>
>   *<br>
>   * @{<br>
>   */<br>
><br>
>  /**<br>
> - * @brief Scheduler context specialization for Strong APA<br>
> - * schedulers.<br>
> - */<br>
> -typedef struct {<br>
> -  Scheduler_SMP_Context    Base;<br>
> -  Priority_bit_map_Control Bit_map;<br>
> -  Chain_Control            Ready[ RTEMS_ZERO_LENGTH_ARRAY ];<br>
> -} Scheduler_strong_APA_Context;<br>
> -<br>
> -/**<br>
> - * @brief Scheduler node specialization for Strong APA<br>
> - * schedulers.<br>
> + * @brief Scheduler node specialization for Strong APA schedulers.<br>
>   */<br>
>  typedef struct {<br>
>    /**<br>
>     * @brief SMP scheduler node.<br>
>     */<br>
>    Scheduler_SMP_Node Base;<br>
> +<br>
> + /**<br>
> +   * @brief Chain node for Scheduler_strong_APA_Context::All_nodes<br>
> +   */<br>
> +  Chain_Node Chain;<br>
<br>
Don't call this Chain. We refer to a Chain_Control object as the<br>
chain. Some other ideas:<br>
* APA_Node<br>
* All_nodes_Node<br>
* All_nodes_Link<br>
* Link<br>
* Node (that could be confusing)<br>
* Link_Node<br>
<br>
I always felt like Joel missed an opportunity to call them Chain Links<br>
instead of Chain Nodes. Then compiler memory fences for synchronizing<br>
them could be Chain Link Fences? (A bit of dad humor.)<br>
<br>
> +<br>
> +  /**<br>
> +   * @brief CPU that this node would preempt in the backtracking part of<br>
> +   * _Scheduler_strong_APA_Get_highest_ready and<br>
> +   * _Scheduler_strong_APA_Do_Enqueue.<br>
> +   */<br>
> +  Per_CPU_Control *invoker;<br>
<br>
I don't like this name either. What is the invoker invoking? Since it<br>
is used to go backwards, maybe think of a word that conveys that use.<br>
'lowest_scheduled'? 'next_to_preempt'?<br>
<br>
><br>
>    /**<br>
> -   * @brief The associated ready queue of this node.<br>
> +   * @brief The associated affinity set of this node.<br>
>     */<br>
> -  Scheduler_priority_Ready_queue Ready_queue;<br>
> +  Processor_mask Affinity;<br>
>  } Scheduler_strong_APA_Node;<br>
><br>
> +<br>
> +/**<br>
> + * @brief Struct for each index of the variable size arrays<br>
clarify this comment, no one knows what this means.<br>
Add a period (full stop) after brief sentence.<br>
<br>
> + */<br>
> +typedef struct<br>
> +{<br>
> +  /**<br>
> +   * @brief The node that called this CPU, i.e. a node which has<br>
'called' the CPU? That doesn't make sense to me.<br>
<br>
> +   * the cpu at the index of Scheduler_strong_APA_Context::Struct in<br>
this comment makes no sense without understanding how this structure<br>
is being used.<br>
<br>
furthermore, the 'instance' of this structure is "at the index of<br>
Scheduler_strong_APA_Context::Struct" so you can just say "The<br>
scheduling node (owning the thread? executing on?) of a cpu in the BFS<br>
queue. Since by now you'll already have explained what is the BFS algo<br>
and queue in use.<br>
<br>
> +   * its affinity set.<br>
> +   */<br>
> +  Scheduler_Node *caller;<br>
Not sure what it called. Think about what this name means a bit more.<br>
<br>
> +<br>
> +    /**<br>
> +   * @brief Cpu at the index of Scheduler_strong_APA_Context::Struct<br>
Isn't this self-referencing? Just say "CPU in a queue"?<br>
<br>
> +   * in Queue implementation.<br>
> +   */<br>
> +  Per_CPU_Control *cpu;<br>
> +<br>
> +    /**<br>
> +   * @brief Indicates if the CPU at the index of<br>
> +   * Scheduler_strong_APA_Context::Struct is already<br>
> +   * added to the Queue or not.<br>
Whether or not this cpu has been added to the queue (visited in the BFS)<br>
<br>
> +   */<br>
> +  bool visited;<br>
> +} Scheduler_strong_APA_Struct;<br>
<br>
Maybe, Scheduler_strong_APA_BFS_node;<br>
<br>
> +<br>
> + /**<br>
> + * @brief Scheduler context for Strong APA scheduler.<br>
> + *<br>
> + * Has the structure for scheduler context<br>
> + * and Node defintion for Strong APA scheduler<br>
typo: definition<br>
<br>
This little phrase seems not that helpful. Either merge to the brief<br>
or expand it further with details.<br>
"@brief Scheduler context and node definition for Strong APA scheduler."<br>
<br>
<br>
> + */<br>
> +typedef struct {<br>
> + /**<br>
> +   * @brief SMP Context to refer to SMP implementation<br>
> +   * code.<br>
<br>
> +   */<br>
> +  Scheduler_SMP_Context Base;<br>
<br>
I don't think these 'Base' need to be documented, or at best you can<br>
just have @see Scheduler_SMP_Context?<br>
<br>
> +<br>
> +  /**<br>
> +   * @brief Chain of all the nodes present in<br>
> +   * the system. Accounts for ready and scheduled nodes.<br>
<br>
Not the system, but the (strong APA) scheduler?<br>
<br>
> +   */<br>
> +  Chain_Control All_nodes;<br>
> +<br>
> +  /**<br>
> +   * @brief Struct with important variables for each cpu<br>
improve this comment.<br>
<br>
> +   */<br>
> +  Scheduler_strong_APA_Struct Struct[ RTEMS_ZERO_LENGTH_ARRAY ];<br>
> +} Scheduler_strong_APA_Context;<br>
> +<br>
> +#define SCHEDULER_STRONG_APA_MAXIMUM_PRIORITY 255<br>
> +<br>
>  /**<br>
>   * @brief Entry points for the Strong APA Scheduler.<br>
>   */<br>
> @@ -100,81 +162,90 @@ typedef struct {<br>
>      _Scheduler_default_Release_job, \<br>
>      _Scheduler_default_Cancel_job, \<br>
>      _Scheduler_default_Tick, \<br>
> -    _Scheduler_SMP_Start_idle \<br>
> -    SCHEDULER_OPERATION_DEFAULT_GET_SET_AFFINITY \<br>
> +    _Scheduler_strong_APA_Start_idle, \<br>
> +    _Scheduler_strong_APA_Set_affinity \<br>
>    }<br>
><br>
>  /**<br>
> - * @brief Initializes the scheduler.<br>
> + * @brief Initializes the Strong_APA scheduler.<br>
>   *<br>
> - * @param scheduler The scheduler to initialize.<br>
> - */<br>
> -void _Scheduler_strong_APA_Initialize( const Scheduler_Control *scheduler );<br>
> -<br>
> + * Sets the chain containing all the nodes to empty<br>
> + * and initializes the SMP scheduler.<br>
> + *<br>
> + * @param scheduler used to get reference to Strong APA scheduler context<br>
> + * @retval void<br>
<br>
I don't think we document void retval. It is a kind of oxymoron.<br>
<br>
> + * @see _Scheduler_strong_APA_Node_initialize()<br>
> + */<br>
> +void _Scheduler_strong_APA_Initialize(<br>
> +  const Scheduler_Control *scheduler<br>
> +);<br>
> +<br>
>  /**<br>
> - * @brief Initializes the node with the given priority.<br>
> + * @brief Called when a node yields the processor<br>
add period.<br>
I think technically the thread yields the processor.<br>
<br>
>   *<br>
>   * @param scheduler The scheduler control instance.<br>
> - * @param[out] node The node to initialize.<br>
> - * @param the_thread The thread of the node to initialize.<br>
> - * @param priority The priority for @a node.<br>
> + * @param thread Thread corresponding to @node<br>
> + * @param node Node that yield the processor<br>
Kind of backwards. The thread yields the processor, and the Node is<br>
corresponding to the thread.<br>
<br>
Maybe check how other schedulers document this stuff. I don't know why<br>
you are changing it from the existing template file?  I shouldn't have<br>
to be spending time reviewing these kinds of reformatting changes<br>
(especially when what's in the repo seems correct and your changes<br>
seem wrong). I'm going to ignore the rest of your doxygen, but please<br>
make similar fixes as I mentioned already, or revert the changes you<br>
made to the existing doco.<br>
<br>
>   */<br>
> -void _Scheduler_strong_APA_Node_initialize(<br>
> +void _Scheduler_strong_APA_Yield(<br>
>    const Scheduler_Control *scheduler,<br>
> -  Scheduler_Node          *node,<br>
> -  Thread_Control          *the_thread,<br>
> -  Priority_Control         priority<br>
> +  Thread_Control          *thread,<br>
> +  Scheduler_Node          *node<br>
>  );<br>
><br>
>  /**<br>
> - * @brief Blocks the thread.<br>
> + * @brief Blocks a node<br>
>   *<br>
> - * @param scheduler The scheduler control instance.<br>
> - * @param[in, out] the_thread The thread to block.<br>
> - * @param[in, out] node The node of the thread to block.<br>
> - */<br>
> + * Changes the state of the node and extracts it from the queue<br>
> + * calls _Scheduler_SMP_Block().<br>
> + *<br>
> + * @param context The scheduler control instance.<br>
> + * @param thread Thread correspoding to the @node.<br>
> + * @param node node which is to be blocked<br>
> + */<br>
>  void _Scheduler_strong_APA_Block(<br>
>    const Scheduler_Control *scheduler,<br>
> -  Thread_Control          *the_thread,<br>
> +  Thread_Control          *thread,<br>
>    Scheduler_Node          *node<br>
>  );<br>
><br>
>  /**<br>
> - * @brief Unblocks the thread.<br>
> + * @brief Unblocks a node<br>
> + *<br>
> + * Changes the state of the node and calls _Scheduler_SMP_Unblock().<br>
>   *<br>
>   * @param scheduler The scheduler control instance.<br>
> - * @param[in, out] the_thread The thread to unblock.<br>
> - * @param[in, out] node The node of the thread to unblock.<br>
> - */<br>
> + * @param thread Thread correspoding to the @node.<br>
> + * @param node node which is to be unblocked<br>
> + * @see _Scheduler_strong_APA_Enqueue()<br>
> + * @see _Scheduler_strong_APA_Do_update()<br>
> + */<br>
>  void _Scheduler_strong_APA_Unblock(<br>
>    const Scheduler_Control *scheduler,<br>
> -  Thread_Control          *the_thread,<br>
> +  Thread_Control          *thread,<br>
>    Scheduler_Node          *node<br>
>  );<br>
><br>
>  /**<br>
> - * @brief Updates the priority of the node.<br>
> + * @brief Updates the priority of the node<br>
See, this one just really bugs me. I really am going to ignore these<br>
doxygen changes.<br>
<br>
>   *<br>
>   * @param scheduler The scheduler control instance.<br>
> - * @param the_thread The thread for the operation.<br>
> - * @param[in, out] node The node to update the priority of.<br>
> - */<br>
> + * @param thread Thread correspoding to the @node.<br>
> + * @param node Node whose priority has to be updated<br>
> + */<br>
>  void _Scheduler_strong_APA_Update_priority(<br>
>    const Scheduler_Control *scheduler,<br>
> -  Thread_Control          *the_thread,<br>
> +  Thread_Control          *thread,<br>
>    Scheduler_Node          *node<br>
>  );<br>
><br>
>  /**<br>
> - * @brief Asks for help.<br>
> + * @brief Calls the SMP Ask_for_help<br>
>   *<br>
> - * @param  scheduler The scheduler control instance.<br>
> - * @param the_thread The thread that asks for help.<br>
> - * @param node The node of @a the_thread.<br>
> - *<br>
> - * @retval true The request for help was successful.<br>
> - * @retval false The request for help was not successful.<br>
> - */<br>
> + * @param scheduler The scheduler control instance.<br>
> + * @param thread Thread correspoding to the @node that asks for help.<br>
> + * @param node node associated with @thread<br>
> + */<br>
>  bool _Scheduler_strong_APA_Ask_for_help(<br>
>    const Scheduler_Control *scheduler,<br>
>    Thread_Control          *the_thread,<br>
> @@ -182,12 +253,13 @@ bool _Scheduler_strong_APA_Ask_for_help(<br>
>  );<br>
><br>
>  /**<br>
> - * @brief Reconsiders help request.<br>
> + * @brief To Reconsider the help request<br>
>   *<br>
>   * @param scheduler The scheduler control instance.<br>
> - * @param the_thread The thread to reconsider the help request of.<br>
> - * @param[in, out] node The node of @a the_thread<br>
> - */<br>
> + * @param thread Thread correspoding to the @node.<br>
> + * @param node Node corresponding to @thread which asks for<br>
> + * reconsideration<br>
> + */<br>
>  void _Scheduler_strong_APA_Reconsider_help_request(<br>
>    const Scheduler_Control *scheduler,<br>
>    Thread_Control          *the_thread,<br>
> @@ -195,13 +267,13 @@ void _Scheduler_strong_APA_Reconsider_help_request(<br>
>  );<br>
><br>
>  /**<br>
> - * @brief Withdraws the node.<br>
> + * @brief Withdraws a node<br>
>   *<br>
>   * @param scheduler The scheduler control instance.<br>
> - * @param[in, out] the_thread The thread to change the state to @a next_state.<br>
> - * @param[in, out] node The node to withdraw.<br>
> - * @param next_state The next state for @a the_thread.<br>
> - */<br>
> + * @param thread Thread correspoding to the @node.<br>
> + * @param node Node that has to be withdrawn<br>
> + * @param next_state the state that the node goes to<br>
> + */<br>
>  void _Scheduler_strong_APA_Withdraw_node(<br>
>    const Scheduler_Control *scheduler,<br>
>    Thread_Control          *the_thread,<br>
> @@ -210,42 +282,66 @@ void _Scheduler_strong_APA_Withdraw_node(<br>
>  );<br>
><br>
>  /**<br>
> - * @brief Adds the idle thread to a processor.<br>
> + * @brief Adds a processor to the scheduler instance<br>
> + *<br>
> + * and allocates an idle thread to the processor.<br>
>   *<br>
>   * @param scheduler The scheduler control instance.<br>
> - * @param[in, out] The idle thread to add to the processor.<br>
> - */<br>
> + * @param idle Idle thread to be allocated to the processor<br>
> + */<br>
>  void _Scheduler_strong_APA_Add_processor(<br>
>    const Scheduler_Control *scheduler,<br>
>    Thread_Control          *idle<br>
>  );<br>
><br>
>  /**<br>
> - * @brief Removes an idle thread from the given cpu.<br>
> - *<br>
> - * @param scheduler The scheduler instance.<br>
> - * @param cpu The cpu control to remove from @a scheduler.<br>
> + * @brief Removes a processor from the scheduler instance<br>
>   *<br>
> - * @return The idle thread of the processor.<br>
> - */<br>
> + * @param scheduler The scheduler control instance.<br>
> + * @param cpu processor that is removed<br>
> + */<br>
>  Thread_Control *_Scheduler_strong_APA_Remove_processor(<br>
>    const Scheduler_Control *scheduler,<br>
> -  struct Per_CPU_Control  *cpu<br>
> +  Per_CPU_Control         *cpu<br>
>  );<br>
><br>
>  /**<br>
> - * @brief Performs a yield operation.<br>
> + * @brief Initializes the node with the given priority.<br>
>   *<br>
>   * @param scheduler The scheduler control instance.<br>
> - * @param the_thread The thread to yield.<br>
> - * @param[in, out] node The node of @a the_thread.<br>
> + * @param[out] node The node to initialize.<br>
> + * @param the_thread The thread of the node to initialize.<br>
> + * @param priority The priority for @a node.<br>
>   */<br>
> -void _Scheduler_strong_APA_Yield(<br>
> +void _Scheduler_strong_APA_Node_initialize(<br>
>    const Scheduler_Control *scheduler,<br>
> +  Scheduler_Node          *node,<br>
>    Thread_Control          *the_thread,<br>
> -  Scheduler_Node          *node<br>
> +  Priority_Control         priority<br>
>  );<br>
><br>
> +/**<br>
> + * @brief Starts an idle thread on a CPU<br>
> + *<br>
> + * @param scheduler The scheduler control instance.<br>
> + * @param idle Idle Thread<br>
> + * @param cpu processor that gets the idle thread<br>
> + */<br>
> +void _Scheduler_strong_APA_Start_idle(<br>
> +  const Scheduler_Control *scheduler,<br>
> +  Thread_Control          *idle,<br>
> +  Per_CPU_Control         *cpu<br>
> +);<br>
> +<br>
> +/**<br>
> + * @brief Sets the affinity of the @node_base to @affinity<br>
> + */<br>
> +bool _Scheduler_strong_APA_Set_affinity(<br>
> +  const Scheduler_Control *scheduler,<br>
> +  Thread_Control          *thread,<br>
> +  Scheduler_Node          *node_base,<br>
> +  const Processor_mask    *affinity<br>
> +);<br>
>  /** @} */<br>
><br>
>  #ifdef __cplusplus<br>
> diff --git a/cpukit/score/src/schedulerstrongapa.c b/cpukit/score/src/schedulerstrongapa.c<br>
> index 924cd86412..a3f4c49cab 100644<br>
> --- a/cpukit/score/src/schedulerstrongapa.c<br>
> +++ b/cpukit/score/src/schedulerstrongapa.c<br>
> @@ -6,320 +6,758 @@<br>
>   * @brief Strong APA Scheduler Implementation<br>
>   */<br>
><br>
> -/*<br>
> - * Copyright (c) 2013, 2016 embedded brains GmbH.  All rights reserved.<br>
> +/*<br>
> + * Copyright (c) 2020 Richi Dubey<br>
>   *<br>
> - *  embedded brains GmbH<br>
> - *  Dornierstr. 4<br>
> - *  82178 Puchheim<br>
> - *  Germany<br>
> - *  <<a href="mailto:rtems@embedded-brains.de" target="_blank">rtems@embedded-brains.de</a>><br>
> + * <<a href="mailto:richidubey@gmail.com" target="_blank">richidubey@gmail.com</a>><br>
>   *<br>
> - * The license and distribution terms for this file may be<br>
> - * found in the file LICENSE in this distribution or at<br>
> + * Copyright (c) 2013, 2018 embedded brains GmbH. All rights reserved.<br>
> + *<br>
> + *  embedded brains GmbH<br>
> + *  Dornierstr. 4<br>
> + *  82178 Puchheim<br>
> + *  Germany<br>
> + *  <<a href="mailto:rtems@embedded-brains.de" target="_blank">rtems@embedded-brains.de</a>><br>
> + *<br>
> + * The license and distribution terms for this file may be<br>
> + * found in the file LICENSE in this distribution or at<br>
>   * <a href="http://www.rtems.org/license/LICENSE" rel="noreferrer" target="_blank">http://www.rtems.org/license/LICENSE</a>.<br>
>   */<br>
> -<br>
> +<br>
>  #ifdef HAVE_CONFIG_H<br>
>  #include "config.h"<br>
>  #endif<br>
><br>
>  #include <rtems/score/schedulerstrongapa.h><br>
> -#include <rtems/score/schedulerpriorityimpl.h><br>
>  #include <rtems/score/schedulersmpimpl.h><br>
> +#include <rtems/score/assert.h><br>
> +#include <rtems/malloc.h><br>
><br>
> -static Scheduler_strong_APA_Context *_Scheduler_strong_APA_Get_self(<br>
> -  Scheduler_Context *context<br>
> -)<br>
> +static inline Scheduler_strong_APA_Context *<br>
> +_Scheduler_strong_APA_Get_context( const Scheduler_Control *scheduler )<br>
> +{<br>
> +  return (Scheduler_strong_APA_Context *) _Scheduler_Get_context( scheduler );<br>
> +}<br>
> +<br>
> +static inline Scheduler_strong_APA_Context *<br>
> +_Scheduler_strong_APA_Get_self( Scheduler_Context *context )<br>
>  {<br>
>    return (Scheduler_strong_APA_Context *) context;<br>
>  }<br>
><br>
> -static Scheduler_strong_APA_Node *<br>
> +static inline Scheduler_strong_APA_Node *<br>
>  _Scheduler_strong_APA_Node_downcast( Scheduler_Node *node )<br>
>  {<br>
>    return (Scheduler_strong_APA_Node *) node;<br>
>  }<br>
><br>
> -static void _Scheduler_strong_APA_Move_from_scheduled_to_ready(<br>
> +static inline void _Scheduler_strong_APA_Do_update(<br>
>    Scheduler_Context *context,<br>
> -  Scheduler_Node    *scheduled_to_ready<br>
> +  Scheduler_Node    *node,<br>
> +  Priority_Control   new_priority<br>
>  )<br>
>  {<br>
> -  Scheduler_strong_APA_Context *self =<br>
> -    _Scheduler_strong_APA_Get_self( context );<br>
> -  Scheduler_strong_APA_Node *node =<br>
> -    _Scheduler_strong_APA_Node_downcast( scheduled_to_ready );<br>
> -<br>
> -  _Chain_Extract_unprotected( &node->Base.Base.Node.Chain );<br>
> -  _Scheduler_priority_Ready_queue_enqueue_first(<br>
> -    &node->Base.Base.Node.Chain,<br>
> -    &node->Ready_queue,<br>
> -    &self->Bit_map<br>
> +  Scheduler_SMP_Node *smp_node;<br>
> +  (void) context;<br>
> +<br>
> +  smp_node = _Scheduler_SMP_Node_downcast( node );<br>
> +  _Scheduler_SMP_Node_update_priority( smp_node, new_priority );<br>
> +}<br>
> +<br>
<br>
Although we don't need doxygen for static (private) methods, a little<br>
bit of comment can be helpful to understand what the helper function<br>
does.<br>
> +static inline bool _Scheduler_strong_APA_Has_ready( Scheduler_Context *context )<br>
> +{<br>
> +  Scheduler_strong_APA_Context *self = _Scheduler_strong_APA_Get_self( context );<br>
> +<br>
> +  bool                       ret;<br>
> +  const Chain_Node          *tail;<br>
> +  Chain_Node                *next;<br>
> +  Scheduler_strong_APA_Node *node;<br>
> +<br>
> +  tail = _Chain_Immutable_tail( &self->All_nodes );<br>
> +  next = _Chain_First( &self->All_nodes );<br>
> +<br>
> +  ret = false;<br>
> +<br>
> +  while ( next != tail ) {<br>
> +    node = (Scheduler_strong_APA_Node *) STRONG_SCHEDULER_NODE_OF_CHAIN( next );<br>
I see, this only works by chance. fix your macro so it works on purpose.<br>
<br>
> +<br>
> +    if (<br>
> +    _Scheduler_SMP_Node_state( &node->Base.Base ) == SCHEDULER_SMP_NODE_READY<br>
not enough indent levels<br>
To break this you should use<br>
  if (<br>
      _Scheduler_SMP_Node_state( &node->Base.Base ) ==<br>
          SCHEDULER_SMP_NODE_READY<br>
  ) {<br>
I know it is kind of ugly.<br>
<br>
> +    ) {<br>
> +      ret = true;<br>
> +      break;<br>
this is fine, but it could also be 'return true;' and then ...<br>
> +    }<br>
> +<br>
> +    next = _Chain_Next( next );<br>
> +  }<br>
> +<br>
> +  return ret;<br>
return false;<br>
<br>
Minor nit, but it does simplify your code<br>
<br>
> +}<br>
> +<br>
> +static inline void _Scheduler_strong_APA_Allocate_processor(<br>
> +  Scheduler_Context *context,<br>
> +  Scheduler_Node    *scheduled_base,<br>
> +  Scheduler_Node    *victim_base,<br>
> +  Per_CPU_Control   *victim_cpu<br>
> +)<br>
> +{<br>
> +  Scheduler_strong_APA_Node *scheduled;<br>
> +<br>
> +  (void) victim_base;<br>
I personally would like a blank line after this warning suppression to<br>
separate it from 'real code' in my head.<br>
<br>
> +  scheduled = _Scheduler_strong_APA_Node_downcast( scheduled_base );<br>
> +<br>
> +  _Scheduler_SMP_Allocate_processor_exact(<br>
> +    context,<br>
> +    &(scheduled->Base.Base),<br>
> +    NULL,<br>
> +    victim_cpu<br>
>    );<br>
>  }<br>
><br>
> -static void _Scheduler_strong_APA_Move_from_ready_to_scheduled(<br>
> +static inline Scheduler_Node * _Scheduler_strong_APA_Find_highest_ready(<br>
> +  Scheduler_strong_APA_Context *self,<br>
> +  uint32_t                      front,<br>
> +  uint32_t                      rear<br>
> +)<br>
> +{<br>
> +  Scheduler_Node              *highest_ready;<br>
> +  Scheduler_strong_APA_Struct *Struct;<br>
> +  const Chain_Node            *tail;<br>
> +  Chain_Node                  *next;<br>
> +  uint32_t                     index_assigned_cpu;<br>
> +  Scheduler_strong_APA_Node   *node;<br>
> +  Priority_Control             min_priority_num;<br>
> +  Priority_Control             curr_priority;<br>
> +  Per_CPU_Control             *assigned_cpu;<br>
> +  Scheduler_SMP_Node_state     curr_state;<br>
> +  Per_CPU_Control             *curr_CPU;<br>
> +  bool                         first_task;<br>
> +<br>
> +  Struct = self->Struct;<br>
> +   //When the first task accessed has nothing to compare its priority against<br>
> +  // So, it is the task with the highest priority witnessed so far!<br>
Use /* */<br>
<br>
> +  first_task = true;<br>
> +<br>
> +  while( front <= rear ) {<br>
> +    curr_CPU = Struct[ front ].cpu;<br>
<br>
Who ensures that rear < sizeof(Struct)?<br>
<br>
> +    front = front + 1;<br>
> +<br>
> +    tail = _Chain_Immutable_tail( &self->All_nodes );<br>
> +    next = _Chain_First( &self->All_nodes );<br>
> +<br>
> +    while ( next != tail ) {<br>
> +      node = (Scheduler_strong_APA_Node*) STRONG_SCHEDULER_NODE_OF_CHAIN( next );<br>
> +      //Check if the curr_CPU is in the affinity set of the node<br>
> +      if (<br>
> +        _Processor_mask_Is_set(&node->Affinity, _Per_CPU_Get_index(curr_CPU))<br>
> +      ) {<br>
extra ws at end of line<br>
you can search a regex like "\s\s*$" for that kind of problem<br>
<br>
> +        curr_state = _Scheduler_SMP_Node_state( &node->Base.Base );<br>
> +<br>
> +        if ( curr_state == SCHEDULER_SMP_NODE_SCHEDULED ) {<br>
> +          assigned_cpu = _Thread_Get_CPU( node->Base.Base.user );<br>
> +          index_assigned_cpu =  _Per_CPU_Get_index( assigned_cpu );<br>
> +<br>
> +          if ( Struct[ index_assigned_cpu ].visited == false ) {<br>
> +            rear = rear + 1;<br>
> +            Struct[ rear ].cpu = assigned_cpu;<br>
> +            Struct[ index_assigned_cpu ].visited = true;<br>
OK this is a little bit confusing. You are using the same 'Struct[]'<br>
entry to store metadata for two different CPUs. Somehow you need to<br>
either clarify this, or make it consistent.<br>
<br>
> +            // The curr CPU of the queue invoked this node to add its CPU<br>
> +            // that it is executing on to the queue. So this node might get<br>
> +            // preempted because of the invoker curr_CPU and this curr_CPU<br>
> +            // is the CPU that node should preempt in case this node<br>
> +            // gets preempted.<br>
> +            node->invoker = curr_CPU;<br>
> +          }<br>
> +        }<br>
> +        else if ( curr_state == SCHEDULER_SMP_NODE_READY ) {<br>
> +          curr_priority = _Scheduler_Node_get_priority( &node->Base.Base );<br>
> +          curr_priority = SCHEDULER_PRIORITY_PURIFY( curr_priority );<br>
> +<br>
> +          if ( first_task == true || curr_priority < min_priority_num ) {<br>
<br>
you can also initialize min_priority_num to  the scheduler's maximum<br>
priority value? Then get rid of this first_task var?<br>
<br>
> +            min_priority_num = curr_priority;<br>
> +           highest_ready = &node->Base.Base;<br>
> +           first_task = false;<br>
> +           //In case this task is directly reachable from thread_CPU<br>
I don't know what this comment means.<br>
<br>
> +           node->invoker = curr_CPU;<br>
> +         }<br>
> +        }<br>
> +      }<br>
> +    next = _Chain_Next( next );<br>
> +    }<br>
> +  }<br>
> +<br>
> +  return highest_ready;<br>
> +}<br>
> +<br>
> +static inline void  _Scheduler_strong_APA_Move_from_ready_to_scheduled(<br>
>    Scheduler_Context *context,<br>
>    Scheduler_Node    *ready_to_scheduled<br>
>  )<br>
>  {<br>
> -  Scheduler_strong_APA_Context *self;<br>
> -  Scheduler_strong_APA_Node    *node;<br>
> -  Priority_Control              insert_priority;<br>
> +  Priority_Control insert_priority;<br>
><br>
> -  self = _Scheduler_strong_APA_Get_self( context );<br>
> -  node = _Scheduler_strong_APA_Node_downcast( ready_to_scheduled );<br>
> -<br>
> -  _Scheduler_priority_Ready_queue_extract(<br>
> -    &node->Base.Base.Node.Chain,<br>
> -    &node->Ready_queue,<br>
> -    &self->Bit_map<br>
> -  );<br>
> -  insert_priority = _Scheduler_SMP_Node_priority( &node->Base.Base );<br>
> +  insert_priority = _Scheduler_SMP_Node_priority( ready_to_scheduled );<br>
>    insert_priority = SCHEDULER_PRIORITY_APPEND( insert_priority );<br>
> -  _Chain_Insert_ordered_unprotected(<br>
> -    &self->Base.Scheduled,<br>
> -    &node->Base.Base.Node.Chain,<br>
> -    &insert_priority,<br>
> -    _Scheduler_SMP_Priority_less_equal<br>
> +  _Scheduler_SMP_Insert_scheduled(<br>
> +    context,<br>
> +    ready_to_scheduled,<br>
> +    insert_priority<br>
>    );<br>
>  }<br>
> -<br>
> -static void _Scheduler_strong_APA_Insert_ready(<br>
> +<br>
> +static inline Scheduler_Node *_Scheduler_strong_APA_Get_highest_ready(<br>
>    Scheduler_Context *context,<br>
> -  Scheduler_Node    *node_base,<br>
> -  Priority_Control   insert_priority<br>
> +  Scheduler_Node    *filter<br>
>  )<br>
>  {<br>
> +  //Implement the BFS Algorithm for task departure<br>
> +  //to get the highest ready task for a particular CPU<br>
> +  //return the highest ready Scheduler_Node and Scheduler_Node filter here points<br>
> +  // to the victim node that is blocked resulting which this function is called.<br>
>    Scheduler_strong_APA_Context *self;<br>
> +  Per_CPU_Control              *filter_cpu;<br>
>    Scheduler_strong_APA_Node    *node;<br>
> -<br>
> -  self = _Scheduler_strong_APA_Get_self( context );<br>
> -  node = _Scheduler_strong_APA_Node_downcast( node_base );<br>
> -<br>
> -  if ( SCHEDULER_PRIORITY_IS_APPEND( insert_priority ) ) {<br>
> -    _Scheduler_priority_Ready_queue_enqueue(<br>
> -      &node->Base.Base.Node.Chain,<br>
> -      &node->Ready_queue,<br>
> -      &self->Bit_map<br>
> -    );<br>
> -  } else {<br>
> -    _Scheduler_priority_Ready_queue_enqueue_first(<br>
> -      &node->Base.Base.Node.Chain,<br>
> -      &node->Ready_queue,<br>
> -      &self->Bit_map<br>
> -    );<br>
> +  Scheduler_Node               *highest_ready;<br>
> +  Scheduler_Node               *curr_node;<br>
> +  Scheduler_Node               *next_node;<br>
> +  Scheduler_strong_APA_Struct  *Struct;<br>
> +  uint32_t                     front;<br>
> +  uint32_t                     rear;<br>
> +  uint32_t                     cpu_max;<br>
> +  uint32_t                             cpu_index;<br>
> +<br>
> +  self=_Scheduler_strong_APA_Get_self( context );<br>
ws<br>
<br>
> +  //Denotes front and rear of the queue<br>
> +  front = 0;<br>
> +  rear = -1;<br>
> +<br>
> +  filter_cpu = _Thread_Get_CPU( filter->user );<br>
> +  Struct = self->Struct;<br>
> +  cpu_max = _SMP_Get_processor_maximum();<br>
<br>
I think there is a valid scheduler at cpu_max?<br>
<br>
> +<br>
> +  for ( cpu_index = 0 ; cpu_index < cpu_max ; ++cpu_index ) {<br>
So this should be <= not <<br>
Maybe?<br>
> +    Struct[ cpu_index ].visited = false;<br>
> +  }<br>
> +<br>
> +  rear = rear + 1;<br>
why not just init rear to 0?<br>
<br>
> +  Struct[ rear ].cpu = filter_cpu;<br>
> +  Struct[ _Per_CPU_Get_index( filter_cpu ) ].visited = true;<br>
> +<br>
> +  highest_ready = _Scheduler_strong_APA_Find_highest_ready(<br>
> +                    self,<br>
> +                    front,<br>
> +                    rear<br>
> +                  );<br>
wrong indents<br>
<br>
> +<br>
> +  if ( highest_ready != filter ) {<br>
> +    //Backtrack on the path from<br>
> +    //filter_cpu to highest_ready, shifting along every task.<br>
> +<br>
> +    node = _Scheduler_strong_APA_Node_downcast( highest_ready );<br>
> +<br>
> +    if( node->invoker != filter_cpu ) {<br>
> +      // Highest ready is not just directly reachable from the victim cpu<br>
> +      // So there is need of task shifting<br>
> +<br>
> +      curr_node = &node->Base.Base;<br>
> +      next_node = _Thread_Scheduler_get_home_node( node->invoker->heir );<br>
> +<br>
> +      _Scheduler_SMP_Preempt(<br>
> +        context,<br>
> +        curr_node,<br>
> +        _Thread_Scheduler_get_home_node( node->invoker->heir ),<br>
> +        _Scheduler_strong_APA_Allocate_processor<br>
> +      );<br>
> +<br>
> +      _Scheduler_strong_APA_Move_from_ready_to_scheduled(context, curr_node);<br>
> +<br>
> +      node = _Scheduler_strong_APA_Node_downcast( next_node );<br>
> +<br>
> +      while( node->invoker !=  filter_cpu ){<br>
> +        curr_node = &node->Base.Base;<br>
> +        next_node = _Thread_Scheduler_get_home_node( node->invoker->heir );<br>
> +<br>
> +        _Scheduler_SMP_Preempt(<br>
> +          context,<br>
> +          curr_node,<br>
> +          _Thread_Scheduler_get_home_node( node->invoker->heir ),<br>
> +          _Scheduler_strong_APA_Allocate_processor<br>
> +        );<br>
> +<br>
> +        node = _Scheduler_strong_APA_Node_downcast( next_node );<br>
> +      }<br>
This is repetitive code, can you merge the first part of the 'if'<br>
block into the while loop?<br>
<br>
<br>
> +      //To save the last node so that the caller SMP_* function<br>
> +      //can do the allocation<br>
> +<br>
> +      curr_node = &node->Base.Base;<br>
> +      highest_ready = curr_node;<br>
> +    }<br>
>    }<br>
> +<br>
> +  return highest_ready;<br>
>  }<br>
><br>
> -static void _Scheduler_strong_APA_Extract_from_ready(<br>
> +static inline Scheduler_Node *_Scheduler_strong_APA_Get_lowest_scheduled(<br>
>    Scheduler_Context *context,<br>
> -  Scheduler_Node    *the_thread<br>
> +  Scheduler_Node    *filter_base<br>
>  )<br>
> -{<br>
> -  Scheduler_strong_APA_Context *self =<br>
> -    _Scheduler_strong_APA_Get_self( context );<br>
> -  Scheduler_strong_APA_Node *node =<br>
> -    _Scheduler_strong_APA_Node_downcast( the_thread );<br>
> -<br>
> -  _Scheduler_priority_Ready_queue_extract(<br>
> -    &node->Base.Base.Node.Chain,<br>
> -    &node->Ready_queue,<br>
> -    &self->Bit_map<br>
> -  );<br>
> +{<br>
> +  //Checks the lowest scheduled directly reachable task<br>
put as /* */ before the function declaration<br>
<br>
> +<br>
> +  uint32_t                  cpu_max;<br>
> +  uint32_t                  cpu_index;<br>
> +  Thread_Control            *curr_thread;<br>
> +  Scheduler_Node            *curr_node;<br>
> +  Scheduler_Node            *lowest_scheduled;<br>
> +  Priority_Control           max_priority_num;<br>
> +  Priority_Control           curr_priority;<br>
> +  Scheduler_strong_APA_Node *filter_strong_node;<br>
> +<br>
> +  lowest_scheduled = NULL; //To remove compiler warning.<br>
> +  max_priority_num = 0;//Max (Lowest) priority encountered so far.<br>
ws<br>
<br>
> +  filter_strong_node = _Scheduler_strong_APA_Node_downcast( filter_base );<br>
> +<br>
> +  //lowest_scheduled is NULL if affinty of a node is 0<br>
typo<br>
<br>
> +  _Assert( !_Processor_mask_Zero( &filter_strong_node->Affinity ) );<br>
> +  cpu_max = _SMP_Get_processor_maximum();<br>
> +<br>
> +  for ( cpu_index = 0 ; cpu_index < cpu_max ; ++cpu_index ) {<br>
<= ?<br>
<br>
> +    //Checks if the CPU is in the affinity set of filter_strong_node<br>
> +    if ( _Processor_mask_Is_set( &filter_strong_node->Affinity, cpu_index) ) {<br>
> +      Per_CPU_Control *cpu = _Per_CPU_Get_by_index( cpu_index );<br>
> +<br>
> +      if ( _Per_CPU_Is_processor_online( cpu ) ) {<br>
> +        curr_thread = cpu->heir;<br>
> +        curr_node = _Thread_Scheduler_get_home_node( curr_thread );<br>
> +        curr_priority = _Scheduler_Node_get_priority( curr_node );<br>
> +        curr_priority = SCHEDULER_PRIORITY_PURIFY( curr_priority );<br>
> +<br>
> +        if ( curr_priority > max_priority_num ) {<br>
> +          lowest_scheduled = curr_node;<br>
> +          max_priority_num = curr_priority;<br>
> +        }<br>
> +      }<br>
> +    }<br>
> +  }<br>
> +<br>
> +  return lowest_scheduled;<br>
<br>
Is it possible this is NULL? what happens if it is?<br>
<br>
>  }<br>
><br>
> -static void _Scheduler_strong_APA_Do_update(<br>
> +static inline void _Scheduler_strong_APA_Extract_from_scheduled(<br>
>    Scheduler_Context *context,<br>
> -  Scheduler_Node *node_to_update,<br>
> -  Priority_Control new_priority<br>
> +  Scheduler_Node    *node_to_extract<br>
>  )<br>
>  {<br>
> -  Scheduler_strong_APA_Context *self =<br>
> -    _Scheduler_strong_APA_Get_self( context );<br>
> -  Scheduler_strong_APA_Node *node =<br>
> -    _Scheduler_strong_APA_Node_downcast( node_to_update );<br>
> -<br>
> -  _Scheduler_SMP_Node_update_priority( &node->Base, new_priority );<br>
> -  _Scheduler_priority_Ready_queue_update(<br>
> -    &node->Ready_queue,<br>
> -    SCHEDULER_PRIORITY_UNMAP( new_priority ),<br>
> -    &self->Bit_map,<br>
> -    &self->Ready[ 0 ]<br>
> -  );<br>
> -}<br>
> +  Scheduler_strong_APA_Context *self;<br>
> +  Scheduler_strong_APA_Node    *node;<br>
><br>
> -static Scheduler_strong_APA_Context *<br>
> -_Scheduler_strong_APA_Get_context( const Scheduler_Control *scheduler )<br>
> -{<br>
> -  return (Scheduler_strong_APA_Context *) _Scheduler_Get_context( scheduler );<br>
> +  self = _Scheduler_strong_APA_Get_self( context );<br>
> +  node = _Scheduler_strong_APA_Node_downcast( node_to_extract );<br>
> +<br>
> +  _Scheduler_SMP_Extract_from_scheduled( &self->Base.Base, &node->Base.Base );<br>
> +  //Not removing it from All_nodes since the node could go in the ready state.<br>
>  }<br>
><br>
> -void _Scheduler_strong_APA_Initialize( const Scheduler_Control *scheduler )<br>
> +static inline void _Scheduler_strong_APA_Extract_from_ready(<br>
> +  Scheduler_Context *context,<br>
> +  Scheduler_Node    *node_to_extract<br>
> +)<br>
>  {<br>
> -  Scheduler_strong_APA_Context *self =<br>
> -    _Scheduler_strong_APA_Get_context( scheduler );<br>
> +  Scheduler_strong_APA_Context *self;<br>
> +  Scheduler_strong_APA_Node    *node;<br>
><br>
> -  _Scheduler_SMP_Initialize( &self->Base );<br>
> -  _Priority_bit_map_Initialize( &self->Bit_map );<br>
> -  _Scheduler_priority_Ready_queue_initialize(<br>
> -    &self->Ready[ 0 ],<br>
> -    scheduler->maximum_priority<br>
> -  );<br>
> +  self = _Scheduler_strong_APA_Get_self( context );<br>
> +  node = _Scheduler_strong_APA_Node_downcast( node_to_extract );<br>
> +<br>
> +  _Assert( !_Chain_Is_empty(self->All_nodes) );<br>
> +  _Assert( !_Chain_Is_node_off_chain( &node->Chain ) );<br>
> +<br>
> +   _Chain_Extract_unprotected( &node->Chain ); //Removed from All_nodes<br>
<br>
All_nodes name is now confusing me. I thought  maybe it meant blocked<br>
nodes too, but I understand now.<br>
<br>
You can call the All_nodes chain 'Ready'. It should be OK to leave<br>
Executing tasks on a Ready structure. That is how the uniprocessor<br>
schedulers work as I recall.<br>
<br>
> +   _Chain_Set_off_chain( &node->Chain );<br>
>  }<br>
><br>
> -void _Scheduler_strong_APA_Node_initialize(<br>
> -  const Scheduler_Control *scheduler,<br>
> -  Scheduler_Node          *node,<br>
> -  Thread_Control          *the_thread,<br>
> -  Priority_Control         priority<br>
> +static inline void _Scheduler_strong_APA_Insert_ready(<br>
> +  Scheduler_Context *context,<br>
> +  Scheduler_Node    *node_base,<br>
> +  Priority_Control   insert_priority<br>
>  )<br>
>  {<br>
> -  Scheduler_Context            *context;<br>
>    Scheduler_strong_APA_Context *self;<br>
> -  Scheduler_strong_APA_Node    *the_node;<br>
> -<br>
> -  the_node = _Scheduler_strong_APA_Node_downcast( node );<br>
> -  _Scheduler_SMP_Node_initialize(<br>
> -    scheduler,<br>
> -    &the_node->Base,<br>
> -    the_thread,<br>
> -    priority<br>
> -  );<br>
> +  Scheduler_strong_APA_Node    *node;<br>
><br>
> -  context = _Scheduler_Get_context( scheduler );<br>
>    self = _Scheduler_strong_APA_Get_self( context );<br>
> -  _Scheduler_priority_Ready_queue_update(<br>
> -    &the_node->Ready_queue,<br>
> -    SCHEDULER_PRIORITY_UNMAP( priority ),<br>
> -    &self->Bit_map,<br>
> -    &self->Ready[ 0 ]<br>
> -  );<br>
> +  node = _Scheduler_strong_APA_Node_downcast( node_base );<br>
> +<br>
> +  if(_Chain_Is_node_off_chain( &node->Chain ) )<br>
ws after if and { } needed<br>
<br>
> +    _Chain_Append_unprotected( &self->All_nodes, &node->Chain );<br>
>  }<br>
><br>
> -static bool _Scheduler_strong_APA_Has_ready( Scheduler_Context *context )<br>
> +static inline void _Scheduler_strong_APA_Move_from_scheduled_to_ready(<br>
> +  Scheduler_Context *context,<br>
> +  Scheduler_Node    *scheduled_to_ready<br>
> +)<br>
>  {<br>
> -  Scheduler_strong_APA_Context *self =<br>
> -    _Scheduler_strong_APA_Get_self( context );<br>
> +  Priority_Control insert_priority;<br>
><br>
> -  return !_Priority_bit_map_Is_empty( &self->Bit_map );<br>
> +  _Scheduler_SMP_Extract_from_scheduled( context, scheduled_to_ready );<br>
> +  insert_priority = _Scheduler_SMP_Node_priority( scheduled_to_ready );<br>
> +<br>
> +  _Scheduler_strong_APA_Insert_ready(<br>
> +    context,<br>
> +    scheduled_to_ready,<br>
> +    insert_priority<br>
> +  );<br>
>  }<br>
><br>
> -static Scheduler_Node *_Scheduler_strong_APA_Get_highest_ready(<br>
> +static inline Scheduler_Node* _Scheduler_strong_APA_Get_lowest_reachable(<br>
> +  Scheduler_strong_APA_Context *self,<br>
> +  uint32_t                      front,<br>
> +  uint32_t                      rear,<br>
> +  Per_CPU_Control             **cpu_to_preempt<br>
> +)<br>
> +{<br>
> +  Scheduler_Node              *lowest_reachable;<br>
> +  Priority_Control             max_priority_num;<br>
> +  uint32_t                    cpu_max;<br>
> +  uint32_t                    cpu_index;<br>
> +  Thread_Control              *curr_thread;<br>
> +  Per_CPU_Control             *curr_CPU;<br>
> +  Priority_Control             curr_priority;<br>
> +  Scheduler_Node              *curr_node;<br>
> +  Scheduler_strong_APA_Node   *curr_strong_node; //Current Strong_APA_Node<br>
> +  Scheduler_strong_APA_Struct *Struct;<br>
> +<br>
> +  max_priority_num = 0;//Max (Lowest) priority encountered so far.<br>
> +  Struct = self->Struct;<br>
> +  cpu_max = _SMP_Get_processor_maximum();<br>
> +<br>
> +  while( front <= rear ) {<br>
> +    curr_CPU = Struct[ front ].cpu;<br>
> +    front = front + 1;<br>
> +<br>
> +    curr_thread = curr_CPU->heir;<br>
> +    curr_node = _Thread_Scheduler_get_home_node( curr_thread );<br>
> +<br>
> +    curr_priority = _Scheduler_Node_get_priority( curr_node );<br>
> +    curr_priority = SCHEDULER_PRIORITY_PURIFY( curr_priority );<br>
> +<br>
> +    curr_strong_node = _Scheduler_strong_APA_Node_downcast( curr_node );<br>
> +<br>
> +    if ( curr_priority > max_priority_num ) {<br>
> +      lowest_reachable = curr_node;<br>
> +      max_priority_num = curr_priority;<br>
> +      *cpu_to_preempt = curr_CPU;<br>
> +    }<br>
> +<br>
> +    if ( !curr_thread->is_idle ) {<br>
> +      for ( cpu_index = 0 ; cpu_index < cpu_max ; ++cpu_index ) {<br>
<= ?<br>
<br>
> +        if ( _Processor_mask_Is_set( &curr_strong_node->Affinity, cpu_index ) ) {<br>
> +          //Checks if the thread_CPU is in the affinity set of the node<br>
> +          Per_CPU_Control *cpu = _Per_CPU_Get_by_index( cpu_index );<br>
> +          if ( _Per_CPU_Is_processor_online( cpu ) && Struct[ cpu_index ].visited == false ) {<br>
> +            rear = rear + 1;<br>
> +            Struct[ rear ].cpu = cpu;<br>
> +            Struct[ cpu_index ].visited = true;<br>
> +            Struct[ cpu_index ].caller = curr_node;<br>
<br>
maybe instead of caller it should be 'ancestor' or something similar<br>
to denote the ordering.<br>
<br>
> +          }<br>
> +        }<br>
> +      }<br>
> +    }<br>
> +  }<br>
> +<br>
> +  return lowest_reachable;<br>
> +}<br>
> +<br>
> +static inline bool _Scheduler_strong_APA_Do_enqueue(<br>
>    Scheduler_Context *context,<br>
> -  Scheduler_Node    *node<br>
> +  Scheduler_Node    *lowest_reachable,<br>
> +  Scheduler_Node    *node,<br>
> +  Priority_Control  insert_priority,<br>
> +  Per_CPU_Control  *cpu_to_preempt<br>
>  )<br>
>  {<br>
> -  Scheduler_strong_APA_Context *self =<br>
> -    _Scheduler_strong_APA_Get_self( context );<br>
> -<br>
> -  (void) node;<br>
> -<br>
> -  return (Scheduler_Node *) _Scheduler_priority_Ready_queue_first(<br>
> -    &self->Bit_map,<br>
> -    &self->Ready[ 0 ]<br>
> -  );<br>
> +  bool                          needs_help;<br>
> +  Priority_Control              node_priority;<br>
> +  Priority_Control              lowest_priority;<br>
> +  Scheduler_strong_APA_Struct  *Struct;<br>
> +  Scheduler_Node               *curr_node;<br>
> +  Scheduler_strong_APA_Node    *curr_strong_node; //Current Strong_APA_Node<br>
> +  Per_CPU_Control              *curr_CPU;<br>
> +  Thread_Control               *next_thread;<br>
> +  Scheduler_strong_APA_Context *self;<br>
> +  Scheduler_Node               *next_node;<br>
> +<br>
> +  self = _Scheduler_strong_APA_Get_self( context );<br>
> +  Struct = self->Struct;<br>
> +<br>
> +  node_priority = _Scheduler_Node_get_priority( node );<br>
> +  node_priority = SCHEDULER_PRIORITY_PURIFY( node_priority );<br>
> +<br>
> +  lowest_priority =  _Scheduler_Node_get_priority( lowest_reachable );<br>
> +  lowest_priority = SCHEDULER_PRIORITY_PURIFY( lowest_priority );<br>
> +<br>
> +  if( lowest_priority > node_priority ) {<br>
> +    //Backtrack on the path from<br>
> +    //_Thread_Get_CPU(lowest_reachable->user) to lowest_reachable, shifting<br>
> +    //along every task<br>
> +<br>
> +    curr_node = Struct[ _Per_CPU_Get_index(cpu_to_preempt) ].caller;<br>
> +    curr_strong_node = _Scheduler_strong_APA_Node_downcast( curr_node );<br>
> +    curr_strong_node->invoker = cpu_to_preempt;<br>
> +<br>
> +    //Save which cpu to preempt in invoker value of the node<br>
> +    while( curr_node != node ) {<br>
ws after while, and delete at end of line<br>
<br>
> +      curr_CPU = _Thread_Get_CPU( curr_node->user );<br>
> +      curr_node = Struct[ _Per_CPU_Get_index( curr_CPU ) ].caller;<br>
> +      curr_strong_node = _Scheduler_strong_APA_Node_downcast( curr_node );<br>
> +      curr_strong_node->invoker =  curr_CPU;<br>
> +     }<br>
> +<br>
> +    next_thread = curr_strong_node->invoker->heir;<br>
> +    next_node = _Thread_Scheduler_get_home_node( next_thread );<br>
> +<br>
> +    node_priority = _Scheduler_Node_get_priority( curr_node );<br>
> +    node_priority = SCHEDULER_PRIORITY_PURIFY( node_priority );<br>
> +<br>
> +    _Scheduler_SMP_Enqueue_to_scheduled(<br>
> +      context,<br>
> +      curr_node,<br>
> +      node_priority,<br>
> +      next_node,<br>
> +      _Scheduler_SMP_Insert_scheduled,<br>
> +      _Scheduler_strong_APA_Move_from_scheduled_to_ready,<br>
> +      _Scheduler_strong_APA_Allocate_processor<br>
> +    );<br>
> +<br>
> +    curr_node = next_node;<br>
> +    curr_strong_node = _Scheduler_strong_APA_Node_downcast( curr_node );<br>
> +<br>
> +    while( curr_node !=  lowest_reachable) {<br>
ws<br>
<br>
> +      next_thread = curr_strong_node->invoker->heir;<br>
> +      next_node = _Thread_Scheduler_get_home_node( next_thread );<br>
> +      //curr_node preempts the next_node;<br>
> +      _Scheduler_SMP_Preempt(<br>
> +       context,<br>
> +       curr_node,<br>
> +       next_node,<br>
> +       _Scheduler_strong_APA_Allocate_processor<br>
> +      );<br>
> +<br>
> +      curr_node = next_node;<br>
> +      curr_strong_node = _Scheduler_strong_APA_Node_downcast( curr_node );<br>
> +    }<br>
> +<br>
> +    _Scheduler_strong_APA_Move_from_scheduled_to_ready(context, lowest_reachable);<br>
> +<br>
> +    needs_help = false;<br>
> +  } else {<br>
> +    needs_help = true;<br>
> +  }<br>
> +<br>
> +  //Add it to All_nodes chain since it is now either scheduled or just ready.<br>
> +  _Scheduler_strong_APA_Insert_ready(context,node,insert_priority);<br>
ws in params<br>
<br>
> +<br>
> +  return needs_help;<br>
>  }<br>
><br>
> -void _Scheduler_strong_APA_Block(<br>
> -  const Scheduler_Control *scheduler,<br>
> -  Thread_Control          *the_thread,<br>
> -  Scheduler_Node          *node<br>
> +static inline bool _Scheduler_strong_APA_Enqueue(<br>
> +  Scheduler_Context *context,<br>
> +  Scheduler_Node    *node,<br>
> +  Priority_Control   insert_priority<br>
>  )<br>
>  {<br>
> -  Scheduler_Context *context = _Scheduler_Get_context( scheduler );<br>
> +  //Idea: BFS Algorithm for task arrival<br>
> +  //Enqueue node either in the scheduled chain or in the ready chain<br>
> +  //node is the newly arrived node and is not scheduled.<br>
> +  Scheduler_strong_APA_Context *self;<br>
> +  Scheduler_strong_APA_Struct  *Struct;<br>
> +  uint32_t                     cpu_max;<br>
> +  uint32_t                     cpu_index;<br>
> +  Per_CPU_Control              *cpu_to_preempt;<br>
> +  Scheduler_Node               *lowest_reachable;<br>
> +  Scheduler_strong_APA_Node    *strong_node;<br>
> +<br>
> +  //Denotes front and rear of the queue<br>
> +  uint32_t     front;<br>
> +  uint32_t     rear;<br>
> +<br>
> +  front = 0;<br>
> +  rear = -1;<br>
><br>
> -  _Scheduler_SMP_Block(<br>
> +  self = _Scheduler_strong_APA_Get_self( context );<br>
> +  strong_node = _Scheduler_strong_APA_Node_downcast( node );<br>
> +  cpu_max = _SMP_Get_processor_maximum();<br>
> +  Struct = self->Struct;<br>
> +<br>
> +  for ( cpu_index = 0 ; cpu_index < cpu_max ; ++cpu_index ) {<br>
<= ?<br>
<br>
> +    Struct[ cpu_index ].visited = false;<br>
> +<br>
> +    //Checks if the thread_CPU is in the affinity set of the node<br>
> +    if ( _Processor_mask_Is_set( &strong_node->Affinity, cpu_index) ) {<br>
> +      Per_CPU_Control *cpu = _Per_CPU_Get_by_index( cpu_index );<br>
> +<br>
> +      if ( _Per_CPU_Is_processor_online( cpu ) ) {<br>
> +        rear = rear + 1;<br>
> +        Struct[ rear ].cpu = cpu;<br>
> +        Struct[ cpu_index ].visited = true;<br>
> +        Struct[ cpu_index ].caller = node;<br>
> +      }<br>
> +    }<br>
> +  }<br>
> +<br>
> +  //This assert makes sure that there always exist an element in the<br>
> +  // Queue when we start the queue traversal.<br>
> +  _Assert( !_Processor_mask_Zero( &strong_node->Affinity ) );<br>
> +<br>
> +  lowest_reachable = _Scheduler_strong_APA_Get_lowest_reachable(<br>
> +                       self,<br>
> +                       front,<br>
> +                       rear,<br>
> +                       &cpu_to_preempt<br>
> +                     );<br>
indents<br>
<br>
> +<br>
> +  return _Scheduler_strong_APA_Do_enqueue(<br>
> +           context,<br>
> +           lowest_reachable,<br>
> +           node,<br>
> +           insert_priority,<br>
> +           cpu_to_preempt<br>
> +         );<br>
indents<br>
<br>
> +}<br>
> +<br>
> +static inline bool _Scheduler_strong_APA_Enqueue_scheduled(<br>
> +  Scheduler_Context *context,<br>
> +  Scheduler_Node    *node,<br>
> +  Priority_Control   insert_priority<br>
> +)<br>
> +{<br>
> +  return _Scheduler_SMP_Enqueue_scheduled(<br>
>      context,<br>
> -    the_thread,<br>
>      node,<br>
> -    _Scheduler_SMP_Extract_from_scheduled,<br>
> +    insert_priority,<br>
> +    _Scheduler_SMP_Priority_less_equal,<br>
>      _Scheduler_strong_APA_Extract_from_ready,<br>
>      _Scheduler_strong_APA_Get_highest_ready,<br>
> +    _Scheduler_strong_APA_Insert_ready,<br>
> +    _Scheduler_SMP_Insert_scheduled,<br>
>      _Scheduler_strong_APA_Move_from_ready_to_scheduled,<br>
> -    _Scheduler_SMP_Allocate_processor_exact<br>
> +    _Scheduler_strong_APA_Allocate_processor<br>
>    );<br>
>  }<br>
><br>
> -static bool _Scheduler_strong_APA_Enqueue(<br>
> +static inline bool _Scheduler_strong_APA_Do_ask_for_help(<br>
>    Scheduler_Context *context,<br>
> -  Scheduler_Node    *node,<br>
> -  Priority_Control   insert_priority<br>
> +  Thread_Control    *the_thread,<br>
> +  Scheduler_Node    *node<br>
>  )<br>
>  {<br>
> -  return _Scheduler_SMP_Enqueue(<br>
> +  return _Scheduler_SMP_Ask_for_help(<br>
>      context,<br>
> +    the_thread,<br>
>      node,<br>
> -    insert_priority,<br>
>      _Scheduler_SMP_Priority_less_equal,<br>
>      _Scheduler_strong_APA_Insert_ready,<br>
>      _Scheduler_SMP_Insert_scheduled,<br>
>      _Scheduler_strong_APA_Move_from_scheduled_to_ready,<br>
> -    _Scheduler_SMP_Get_lowest_scheduled,<br>
> -    _Scheduler_SMP_Allocate_processor_exact<br>
> +    _Scheduler_strong_APA_Get_lowest_scheduled,<br>
> +    _Scheduler_strong_APA_Allocate_processor<br>
>    );<br>
>  }<br>
><br>
> -static bool _Scheduler_strong_APA_Enqueue_scheduled(<br>
> +static inline void _Scheduler_strong_APA_Register_idle(<br>
>    Scheduler_Context *context,<br>
> -  Scheduler_Node    *node,<br>
> -  Priority_Control  insert_priority<br>
> +  Scheduler_Node    *idle_base,<br>
> +  Per_CPU_Control   *cpu<br>
>  )<br>
>  {<br>
> -  return _Scheduler_SMP_Enqueue_scheduled(<br>
> +  (void) context;<br>
> +  (void) idle_base;<br>
> +  (void) cpu;<br>
> +  //We do not maintain a variable to access the scheduled<br>
> +  //node for a CPU. So this function does nothing.<br>
> +}<br>
> +<br>
> +static inline  void  _Scheduler_strong_APA_Do_set_affinity(<br>
> +  Scheduler_Context *context,<br>
> +  Scheduler_Node    *node_base,<br>
> +  void              *arg<br>
> +)<br>
> +{<br>
> +  Scheduler_strong_APA_Node *node;<br>
> +  const Processor_mask      *affinity;<br>
> +<br>
> +  node = _Scheduler_strong_APA_Node_downcast( node_base );<br>
> +  affinity = arg;<br>
> +  node->Affinity = *affinity;<br>
can simplify to:<br>
   node->Affinity = (const Processor_mask *)arg;<br>
<br>
> +}<br>
> +<br>
> +void _Scheduler_strong_APA_Initialize( const Scheduler_Control *scheduler )<br>
> +{<br>
> +  Scheduler_strong_APA_Context *self =<br>
> +    _Scheduler_strong_APA_Get_context( scheduler );<br>
two more spaces, need to indent 2 levels for line break<br>
<br>
> +<br>
> +  _Scheduler_SMP_Initialize( &self->Base );<br>
> +  _Chain_Initialize_empty( &self->All_nodes );<br>
> +}<br>
> +<br>
> +void _Scheduler_strong_APA_Yield(<br>
> +  const Scheduler_Control *scheduler,<br>
> +  Thread_Control          *thread,<br>
> +  Scheduler_Node          *node<br>
> +)<br>
> +{<br>
> +  Scheduler_Context *context = _Scheduler_Get_context( scheduler );<br>
> +<br>
> +  _Scheduler_SMP_Yield(<br>
>      context,<br>
> +    thread,<br>
>      node,<br>
> -    insert_priority,<br>
> -    _Scheduler_SMP_Priority_less_equal,<br>
>      _Scheduler_strong_APA_Extract_from_ready,<br>
> -    _Scheduler_strong_APA_Get_highest_ready,<br>
> -    _Scheduler_strong_APA_Insert_ready,<br>
> -    _Scheduler_SMP_Insert_scheduled,<br>
> -    _Scheduler_strong_APA_Move_from_ready_to_scheduled,<br>
> -    _Scheduler_SMP_Allocate_processor_exact<br>
> +    _Scheduler_strong_APA_Enqueue,<br>
> +    _Scheduler_strong_APA_Enqueue_scheduled<br>
>    );<br>
>  }<br>
><br>
> -void _Scheduler_strong_APA_Unblock(<br>
> +void _Scheduler_strong_APA_Block(<br>
>    const Scheduler_Control *scheduler,<br>
> -  Thread_Control          *the_thread,<br>
> +  Thread_Control          *thread,<br>
>    Scheduler_Node          *node<br>
>  )<br>
>  {<br>
>    Scheduler_Context *context = _Scheduler_Get_context( scheduler );<br>
> -<br>
> -  _Scheduler_SMP_Unblock(<br>
> +  //The extract from ready automatically removes the node from All_nodes chain.<br>
> +  _Scheduler_SMP_Block(<br>
>      context,<br>
> -    the_thread,<br>
> +    thread,<br>
>      node,<br>
> -    _Scheduler_strong_APA_Do_update,<br>
> -    _Scheduler_strong_APA_Enqueue<br>
> +    _Scheduler_strong_APA_Extract_from_scheduled,<br>
> +    _Scheduler_strong_APA_Extract_from_ready,<br>
> +    _Scheduler_strong_APA_Get_highest_ready,<br>
> +    _Scheduler_strong_APA_Move_from_ready_to_scheduled,<br>
> +    _Scheduler_strong_APA_Allocate_processor<br>
>    );<br>
>  }<br>
><br>
> -static bool _Scheduler_strong_APA_Do_ask_for_help(<br>
> -  Scheduler_Context *context,<br>
> -  Thread_Control    *the_thread,<br>
> -  Scheduler_Node    *node<br>
> +void _Scheduler_strong_APA_Unblock(<br>
> +  const Scheduler_Control *scheduler,<br>
> +  Thread_Control          *thread,<br>
> +  Scheduler_Node          *node<br>
>  )<br>
>  {<br>
> -  return _Scheduler_SMP_Ask_for_help(<br>
> +  Scheduler_Context *context = _Scheduler_Get_context( scheduler );<br>
> +<br>
> +  _Scheduler_SMP_Unblock(<br>
>      context,<br>
> -    the_thread,<br>
> +    thread,<br>
>      node,<br>
> -    _Scheduler_SMP_Priority_less_equal,<br>
> -    _Scheduler_strong_APA_Insert_ready,<br>
> -    _Scheduler_SMP_Insert_scheduled,<br>
> -    _Scheduler_strong_APA_Move_from_scheduled_to_ready,<br>
> -    _Scheduler_SMP_Get_lowest_scheduled,<br>
> -    _Scheduler_SMP_Allocate_processor_lazy<br>
> +    _Scheduler_strong_APA_Do_update,<br>
> +    _Scheduler_strong_APA_Enqueue<br>
>    );<br>
>  }<br>
><br>
>  void _Scheduler_strong_APA_Update_priority(<br>
>    const Scheduler_Control *scheduler,<br>
> -  Thread_Control          *the_thread,<br>
> +  Thread_Control          *thread,<br>
>    Scheduler_Node          *node<br>
>  )<br>
>  {<br>
> @@ -327,7 +765,7 @@ void _Scheduler_strong_APA_Update_priority(<br>
><br>
>    _Scheduler_SMP_Update_priority(<br>
>      context,<br>
> -    the_thread,<br>
> +    thread,<br>
>      node,<br>
>      _Scheduler_strong_APA_Extract_from_ready,<br>
>      _Scheduler_strong_APA_Do_update,<br>
> @@ -345,7 +783,11 @@ bool _Scheduler_strong_APA_Ask_for_help(<br>
>  {<br>
>    Scheduler_Context *context = _Scheduler_Get_context( scheduler );<br>
><br>
> -  return _Scheduler_strong_APA_Do_ask_for_help( context, the_thread, node );<br>
> +  return _Scheduler_strong_APA_Do_ask_for_help(<br>
> +    context,<br>
> +    the_thread,<br>
> +    node<br>
> +  );<br>
>  }<br>
><br>
>  void _Scheduler_strong_APA_Reconsider_help_request(<br>
> @@ -381,7 +823,7 @@ void _Scheduler_strong_APA_Withdraw_node(<br>
>      _Scheduler_strong_APA_Extract_from_ready,<br>
>      _Scheduler_strong_APA_Get_highest_ready,<br>
>      _Scheduler_strong_APA_Move_from_ready_to_scheduled,<br>
> -    _Scheduler_SMP_Allocate_processor_lazy<br>
> +    _Scheduler_strong_APA_Allocate_processor<br>
>    );<br>
>  }<br>
><br>
> @@ -397,7 +839,7 @@ void _Scheduler_strong_APA_Add_processor(<br>
>      idle,<br>
>      _Scheduler_strong_APA_Has_ready,<br>
>      _Scheduler_strong_APA_Enqueue_scheduled,<br>
> -    _Scheduler_SMP_Do_nothing_register_idle<br>
> +    _Scheduler_strong_APA_Register_idle<br>
why not use the Do_nothing?<br>
<br>
>    );<br>
>  }<br>
><br>
> @@ -416,20 +858,83 @@ Thread_Control *_Scheduler_strong_APA_Remove_processor(<br>
>    );<br>
>  }<br>
><br>
> -void _Scheduler_strong_APA_Yield(<br>
> +void _Scheduler_strong_APA_Node_initialize(<br>
>    const Scheduler_Control *scheduler,<br>
> +  Scheduler_Node          *node,<br>
>    Thread_Control          *the_thread,<br>
> -  Scheduler_Node          *node<br>
> +  Priority_Control         priority<br>
>  )<br>
>  {<br>
> -  Scheduler_Context *context = _Scheduler_Get_context( scheduler );<br>
> +  Scheduler_SMP_Node *smp_node;<br>
> +  Scheduler_strong_APA_Node *strong_node;<br>
> +<br>
> +  smp_node = _Scheduler_SMP_Node_downcast( node );<br>
> +  strong_node = _Scheduler_strong_APA_Node_downcast( node );<br>
> +<br>
> +  _Scheduler_SMP_Node_initialize( scheduler, smp_node, the_thread, priority );<br>
> +<br>
> +  _Processor_mask_Assign(<br>
> +    &strong_node->Affinity,<br>
> +   _SMP_Get_online_processors()<br>
> +  );<br>
> +}<br>
><br>
> -  _Scheduler_SMP_Yield(<br>
> +void _Scheduler_strong_APA_Start_idle(<br>
> +  const Scheduler_Control *scheduler,<br>
> +  Thread_Control          *idle,<br>
> +  Per_CPU_Control         *cpu<br>
> +)<br>
> +{<br>
> +  Scheduler_Context *context;<br>
> +<br>
> +  context = _Scheduler_Get_context( scheduler );<br>
> +<br>
> +  _Scheduler_SMP_Do_start_idle(<br>
>      context,<br>
> -    the_thread,<br>
> -    node,<br>
> -    _Scheduler_strong_APA_Extract_from_ready,<br>
> -    _Scheduler_strong_APA_Enqueue,<br>
> -    _Scheduler_strong_APA_Enqueue_scheduled<br>
> +    idle,<br>
> +    cpu,<br>
> +    _Scheduler_strong_APA_Register_idle<br>
>    );<br>
>  }<br>
> +<br>
> +bool _Scheduler_strong_APA_Set_affinity(<br>
> +  const Scheduler_Control *scheduler,<br>
> +  Thread_Control          *thread,<br>
> +  Scheduler_Node          *node_base,<br>
> +  const Processor_mask    *affinity<br>
> +)<br>
> +{<br>
> +  Scheduler_Context         *context;<br>
> +  Scheduler_strong_APA_Node *node;<br>
> +  Processor_mask             local_affinity;<br>
> +<br>
> +  context = _Scheduler_Get_context( scheduler );<br>
> +  _Processor_mask_And( &local_affinity, &context->Processors, affinity );<br>
> +<br>
> +  if ( _Processor_mask_Is_zero( &local_affinity ) ) {<br>
> +    return false;<br>
> +  }<br>
> +<br>
> +  node = _Scheduler_strong_APA_Node_downcast( node_base );<br>
> +<br>
> +  if ( _Processor_mask_Is_equal( &node->Affinity, affinity ) )<br>
{ }<br>
> +    return true;       //Nothing to do. Return true.<br>
> +<br>
> + _Processor_mask_Assign( &node->Affinity, &local_affinity );<br>
> +<br>
> + _Scheduler_SMP_Set_affinity(<br>
> +   context,<br>
> +   thread,<br>
> +   node_base,<br>
> +   &local_affinity,<br>
> +   _Scheduler_strong_APA_Do_set_affinity,<br>
> +   _Scheduler_strong_APA_Extract_from_ready,<br>
> +   _Scheduler_strong_APA_Get_highest_ready,<br>
> +   _Scheduler_strong_APA_Move_from_ready_to_scheduled,<br>
> +   _Scheduler_strong_APA_Enqueue,<br>
> +   _Scheduler_strong_APA_Allocate_processor<br>
> + );<br>
> +<br>
> +  return true;<br>
> +}<br>
> +<br>
> --<br>
> 2.17.1<br>
><br>
> _______________________________________________<br>
> devel mailing list<br>
> <a href="mailto:devel@rtems.org" target="_blank">devel@rtems.org</a><br>
> <a href="http://lists.rtems.org/mailman/listinfo/devel" rel="noreferrer" target="_blank">http://lists.rtems.org/mailman/listinfo/devel</a><br>
</blockquote></div>