[PATCH 8/8] score: Rework thread priority management
Gedare Bloom
gedare at rtems.org
Wed Sep 7 18:52:42 UTC 2016
On Tue, Sep 6, 2016 at 8:40 AM, Sebastian Huber
<sebastian.huber at embedded-brains.de> wrote:
> Add priority nodes which contribute to the overall thread priority.
>
> The actual priority of a thread is now an aggregation of priority nodes.
> The thread priority aggregation for the home scheduler instance of a
> thread consists of at least one priority node, which is normally the
> real priority of the thread. The locking protocols (e.g. priority
> ceiling and priority inheritance), rate-monotonic period objects and the
> POSIX sporadic server add, change and remove priority nodes.
>
> A thread changes its priority now immediately, e.g. priority changes are
> not deferred until the thread releases its last resource.
>
> Replace the _Thread_Change_priority() function with
>
> * _Thread_Priority_perform_actions(),
> * _Thread_Priority_add(),
> * _Thread_Priority_remove(),
> * _Thread_Priority_change(), and
> * _Thread_Priority_update().
>
> Update #2412.
> Update #2556.
> ---
> cpukit/libmisc/capture/capture.h | 2 +-
> cpukit/libmisc/cpuuse/cpuusagetop.c | 6 +-
> cpukit/posix/include/rtems/posix/pthreadimpl.h | 2 +
> cpukit/posix/include/rtems/posix/threadsup.h | 8 +-
> cpukit/posix/src/killinfo.c | 2 +-
> cpukit/posix/src/mutexsetprioceiling.c | 13 +-
> cpukit/posix/src/pthread.c | 103 ++-
> cpukit/posix/src/pthreadcreate.c | 32 +-
> cpukit/posix/src/pthreadgetschedparam.c | 2 +-
> cpukit/posix/src/pthreadsetschedparam.c | 143 ++--
> cpukit/posix/src/pthreadsetschedprio.c | 92 +--
> cpukit/rtems/include/rtems/rtems/ratemon.h | 6 +
> cpukit/rtems/src/ratemoncancel.c | 12 +-
> cpukit/rtems/src/ratemoncreate.c | 2 +
> cpukit/rtems/src/ratemonperiod.c | 15 +-
> cpukit/rtems/src/semsetpriority.c | 18 +-
> cpukit/rtems/src/tasksetpriority.c | 95 +--
> cpukit/score/Makefile.am | 3 +-
> cpukit/score/include/rtems/score/coremutex.h | 4 +-
> cpukit/score/include/rtems/score/coremuteximpl.h | 148 ++--
> cpukit/score/include/rtems/score/mrsp.h | 12 +-
> cpukit/score/include/rtems/score/mrspimpl.h | 255 ++++---
> cpukit/score/include/rtems/score/priority.h | 159 +++-
> cpukit/score/include/rtems/score/priorityimpl.h | 417 ++++++++++
> cpukit/score/include/rtems/score/scheduler.h | 28 +-
> cpukit/score/include/rtems/score/schedulercbs.h | 17 +-
> cpukit/score/include/rtems/score/scheduleredf.h | 26 +-
> .../score/include/rtems/score/scheduleredfimpl.h | 14 +-
> cpukit/score/include/rtems/score/schedulerimpl.h | 86 ++-
> cpukit/score/include/rtems/score/schedulernode.h | 19 +-
> .../score/include/rtems/score/schedulernodeimpl.h | 18 +-
> .../score/include/rtems/score/schedulersmpimpl.h | 11 +-
> cpukit/score/include/rtems/score/thread.h | 53 +-
> cpukit/score/include/rtems/score/threadimpl.h | 261 ++++---
> cpukit/score/include/rtems/score/threadq.h | 98 ++-
> cpukit/score/include/rtems/score/threadqimpl.h | 145 ++--
> cpukit/score/preinstall.am | 4 +
> cpukit/score/src/mutex.c | 21 +-
> cpukit/score/src/schedulercbs.c | 22 +-
> cpukit/score/src/schedulercbsnodeinit.c | 1 +
> cpukit/score/src/schedulercbsreleasejob.c | 40 +-
> cpukit/score/src/schedulercbsunblock.c | 51 +-
> cpukit/score/src/schedulerdefaultnodeinit.c | 4 +-
> cpukit/score/src/schedulerdefaultreleasejob.c | 20 +-
> cpukit/score/src/scheduleredfchangepriority.c | 8 +-
> cpukit/score/src/scheduleredfnodeinit.c | 6 +-
> cpukit/score/src/scheduleredfreleasejob.c | 84 +--
> cpukit/score/src/scheduleredfunblock.c | 2 +-
> cpukit/score/src/scheduleredfyield.c | 2 +-
> cpukit/score/src/schedulerpriority.c | 2 +-
> cpukit/score/src/schedulerprioritysmp.c | 7 +-
> cpukit/score/src/schedulersimplesmp.c | 2 +-
> cpukit/score/src/schedulerstrongapa.c | 7 +-
> cpukit/score/src/thread.c | 4 +-
> cpukit/score/src/threadchangepriority.c | 362 ++++++---
> cpukit/score/src/threadinitialize.c | 7 +-
> cpukit/score/src/threadmp.c | 3 +-
> cpukit/score/src/threadqenqueue.c | 120 +--
> cpukit/score/src/threadqflush.c | 9 +-
> cpukit/score/src/threadqops.c | 839 ++++++++++++++++-----
> cpukit/score/src/threadrestart.c | 61 +-
> cpukit/score/src/threadsetpriority.c | 59 --
> cpukit/score/src/threadtimeout.c | 3 +
> testsuites/smptests/smpmutex01/init.c | 3 +-
> testsuites/smptests/smpscheduler03/init.c | 43 +-
> testsuites/sptests/spmutex01/init.c | 141 +++-
> testsuites/sptests/spsem03/init.c | 30 +-
> testsuites/sptests/spsem03/spsem03.doc | 4 +-
> 68 files changed, 2790 insertions(+), 1508 deletions(-)
> create mode 100644 cpukit/score/include/rtems/score/priorityimpl.h
> delete mode 100644 cpukit/score/src/threadsetpriority.c
>
...
> diff --git a/cpukit/score/include/rtems/score/priority.h b/cpukit/score/include/rtems/score/priority.h
> index 842f017..f53c321 100644
> --- a/cpukit/score/include/rtems/score/priority.h
> +++ b/cpukit/score/include/rtems/score/priority.h
> @@ -1,17 +1,15 @@
> /**
> - * @file rtems/score/priority.h
> + * @file
> *
> - * @brief Thread Priority Manipulation Routines
> - *
> - * This include file contains all thread priority manipulation routines.
> - * This Handler provides mechanisms which can be used to
> - * initialize and manipulate thread priorities.
> + * @brief Priority Handler API
> */
>
> /*
> * COPYRIGHT (c) 1989-2011.
> * On-Line Applications Research Corporation (OAR).
> *
> + * Copyright (c) 2016 embedded brains GmbH.
> + *
> * 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.
> @@ -20,58 +18,153 @@
> #ifndef _RTEMS_SCORE_PRIORITY_H
> #define _RTEMS_SCORE_PRIORITY_H
>
> -/**
> - * @defgroup ScorePriority Priority Handler
> - *
> - * @ingroup Score
> - *
> - * This handler encapsulates functionality which is used to manage
> - * thread priorities. At the SuperCore level 256 priority levels
> - * are supported with lower numbers representing logically more important
> - * threads. The priority level 0 is reserved for internal RTEMS use.
> - * Typically it is assigned to threads which defer internal RTEMS
> - * actions from an interrupt to thread level to improve interrupt response.
> - * Priority level 255 is assigned to the IDLE thread and really should not
> - * be used by application threads. The default IDLE thread implementation
> - * is an infinite "branch to self" loop which never yields to other threads
> - * at the same priority.
> - */
> -/**@{*/
> -
> -/*
> - * Processor specific information.
> - */
> +#include <rtems/score/chain.h>
> #include <rtems/score/cpu.h>
> +#include <rtems/score/rbtree.h>
> +
> +struct Scheduler_Control;
>
> #ifdef __cplusplus
> extern "C" {
> #endif
>
> /**
> - * The following type defines the control block used to manage
> - * thread priorities.
> + * @defgroup ScorePriority Priority Handler
> + *
> + * @ingroup Score
> *
> - * @note Priority 0 is reserved for internal threads only.
> + * This handler encapsulates functionality which is used to manage thread
> + * priorities. The actual priority of a thread is an aggregation of priority
> + * nodes. The thread priority aggregation for the home scheduler instance of a
> + * thread consists of at least one priority node, which is normally the real
> + * priority of the thread. The locking protocols (e.g. priority ceiling and
> + * priority inheritance), rate-monotonic period objects and the POSIX sporadic
> + * server add, change and remove priority nodes.
> + *
> + * @{
> + */
> +
> +/**
> + * @brief A plain thread priority value.
> + *
> + * Lower values represent higher priorities. So, a priority value of zero
> + * represents the highest priority thread. This value is reserved for internal
> + * threads and the priority ceiling protocol.
> */
> typedef uint64_t Priority_Control;
>
> -/** This defines the highest (most important) thread priority. */
> +/**
> + * @brief The highest (most important) thread priority value.
> + */
> #define PRIORITY_MINIMUM 0
>
> /**
> - * @brief This defines the priority of pseudo-ISR threads.
> + * @brief The priority value of pseudo-ISR threads.
> *
> * Examples are the MPCI and timer server threads.
> */
> #define PRIORITY_PSEUDO_ISR PRIORITY_MINIMUM
>
> -/** This defines the default lowest (least important) thread priority. */
> +/**
> + * @brief The default lowest (least important) thread priority value.
> + *
> + * This value is CPU port dependent.
> + */
> #if defined (CPU_PRIORITY_MAXIMUM)
> #define PRIORITY_DEFAULT_MAXIMUM CPU_PRIORITY_MAXIMUM
> #else
> #define PRIORITY_DEFAULT_MAXIMUM 255
> #endif
>
> +/**
> + * @brief The priority node to build up a priority aggregation.
> + */
> +typedef struct {
> + /**
> + * @brief Node component for a chain or red-black tree.
> + */
> + union {
> + Chain_Node Chain;
> + RBTree_Node RBTree;
> + } Node;
> +
> + /**
> + * @brief The priority value of this node.
> + */
> + Priority_Control priority;
> +} Priority_Node;
> +
> +/**
> + * @brief The priority action type.
> + */
> +typedef enum {
> + PRIORITY_ACTION_ADD,
> + PRIORITY_ACTION_CHANGE,
> + PRIORITY_ACTION_REMOVE,
> + PRIORITY_ACTION_INVALID
> +} Priority_Action_type;
> +
> +typedef struct Priority_Aggregation Priority_Aggregation;
> +
> +/**
> + * @brief The priority aggregation.
> + */
> +struct Priority_Aggregation {
> + /**
> + * @brief A priority node reflection the overall priority of the aggregation.
> + *
reflection -> "reflection of" or maybe "reflects"? Or, "represents"
> + * May be used to add this aggregation to another aggregation to build up a
> + * recursive priority scheme.
> + */
> + Priority_Node Node;
> +
> + /**
> + * @brief A red-black tree to contain priority nodes contributing to the
> + * overall priority of the this priority aggregation.
"the this" -> "this"
> + */
> + RBTree_Control Contributors;
> +
Is it the case that a priority node is only ever on one of these
"Contributors" trees at a time?
> +#if defined(RTEMS_SMP)
> + /**
> + * @brief The scheduler instance of this priority aggregation.
> + */
> + const struct Scheduler_Control *scheduler;
> +#endif
> +
> + /**
> + * @brief A priority action block to manage priority node additions, changes
> + * and removals.
> + */
> + struct {
> +#if defined(RTEMS_SMP)
> + /**
> + * @brief The next priority aggregation in the action chain.
> + */
> + Priority_Aggregation *next;
> +#endif
> +
> + /**
> + * @brief The priority node of the action.
> + */
> + Priority_Node *node;
> +
> + /**
> + * @brief The type of the action.
> + */
> + Priority_Action_type type;
> + } Action;
> +};
> +
> +/**
> + * @brief A set of priority actions.
> + */
> +typedef struct {
> + /**
> + * @brief The first action of a priority action chain.
I would prefer consistently to refer to either actions in the priority
action chain, or priority aggregations in the action chain. It should
be clarified somewhere in the doxygen that a Priority_Aggregation can
be on a singly-linked list of aggregations for (pending?) priority
actions, and also on a red-black tree for recursive priority
dependencies.
It may be a bit confusing to refer to something as a chain that is not
making use of the "RTEMS Chains"
> + */
> + Priority_Aggregation *actions;
> +} Priority_Actions;
> +
> #ifdef __cplusplus
> }
> #endif
> diff --git a/cpukit/score/include/rtems/score/priorityimpl.h b/cpukit/score/include/rtems/score/priorityimpl.h
> new file mode 100644
> index 0000000..d022c1f
> --- /dev/null
> +++ b/cpukit/score/include/rtems/score/priorityimpl.h
> @@ -0,0 +1,417 @@
> +/*
> + * Copyright (c) 2016 embedded brains GmbH. All rights reserved.
> + *
> + * embedded brains GmbH
> + * Dornierstr. 4
> + * 82178 Puchheim
> + * Germany
> + * <rtems at 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_PRIORITYIMPL_H
> +#define _RTEMS_SCORE_PRIORITYIMPL_H
> +
> +#include <rtems/score/priority.h>
> +#include <rtems/score/scheduler.h>
> +
> +#ifdef __cplusplus
> +extern "C" {
> +#endif /* __cplusplus */
> +
> +RTEMS_INLINE_ROUTINE void _Priority_Actions_initialize_empty(
> + Priority_Actions *actions
> +)
> +{
> + actions->actions = NULL;
> +}
> +
> +RTEMS_INLINE_ROUTINE void _Priority_Actions_initialize_one(
> + Priority_Actions *actions,
> + Priority_Aggregation *aggregation,
> + Priority_Node *node,
> + Priority_Action_type type
> +)
> +{
> +#if defined(RTEMS_SMP)
> + aggregation->Action.next = NULL;
> +#endif
> + aggregation->Action.node = node;
> + aggregation->Action.type = type;
> +
> + actions->actions = aggregation;
> +}
> +
> +RTEMS_INLINE_ROUTINE bool _Priority_Actions_is_empty(
> + const Priority_Actions *actions
> +)
> +{
> + return actions->actions == NULL;
> +}
> +
> +RTEMS_INLINE_ROUTINE bool _Priority_Actions_is_valid(
> + const Priority_Aggregation *aggregation
> +)
> +{
> +#if defined(RTEMS_SMP)
> + return aggregation != NULL;
> +#else
> + (void) aggregation;
> + return false;
> +#endif
> +}
> +
> +RTEMS_INLINE_ROUTINE void _Priority_Actions_move(
> + Priority_Actions *target_actions,
> + Priority_Actions *source_actions
> +)
> +{
> + target_actions->actions = source_actions->actions;
> + source_actions->actions = NULL;
> +}
> +
> +RTEMS_INLINE_ROUTINE Priority_Aggregation *_Priority_Actions_get_first(
> + const Priority_Actions *actions
> +)
> +{
> + return actions->actions;
> +}
> +
> +RTEMS_INLINE_ROUTINE void _Priority_Actions_add(
> + Priority_Actions *actions,
> + Priority_Aggregation *aggregation
> +)
> +{
> +#if defined(RTEMS_SMP)
> + aggregation->Action.next = actions->actions;
Do we not care what was previously in the .next field?
[...]
> diff --git a/cpukit/score/include/rtems/score/threadq.h b/cpukit/score/include/rtems/score/threadq.h
> index a4ad082..058603b 100644
> --- a/cpukit/score/include/rtems/score/threadq.h
> +++ b/cpukit/score/include/rtems/score/threadq.h
> @@ -47,8 +47,6 @@ typedef struct Thread_queue_Queue Thread_queue_Queue;
>
> typedef struct Thread_queue_Operations Thread_queue_Operations;
>
> -typedef struct Thread_queue_Path Thread_queue_Path;
> -
> /**
> * @brief Thread queue deadlock callout.
> *
> @@ -195,6 +193,45 @@ typedef struct {
> */
> uint64_t timeout;
>
> +#if defined(RTEMS_SMP)
> + /**
> + * @brief Representation of a thread queue path from a start thread queue to
> + * the terminal thread queue.
> + *
> + * The start thread queue is determined by the object on which a thread intends
> + * to block. The terminal thread queue is the thread queue reachable via
> + * thread queue links those owner is not blocked on a thread queue. The thread
those -> whose ?
> + * queue links are determined by the thread queue owner and thread wait queue
> + * relationships.
> + */
> + struct {
> + /**
> + * @brief The chain of thread queue links defining the thread queue path.
> + */
> + Chain_Control Links;
> +
> + /**
> + * @brief The start of a thread queue path.
> + */
> + Thread_queue_Link Start;
> + } Path;
> +#endif
> +
> + struct {
> + Priority_Actions Actions;
> +
> + /**
> + * @brief Count of threads to update the priority via
> + * _Thread_Priority_update().
> + */
> + size_t update_count;
I'd prefer uint32_t for unsigned counters since usually size_t denotes
an object's (byte) size.
> +
> + /**
> + * @brief Threads to update the priority via _Thread_Priority_update().
> + */
> + Thread_Control *update[ 2 ];
Why 2?
> + } Priority;
> +
> /**
> * @brief Invoked in case of a detected deadlock.
> *
> @@ -237,7 +274,7 @@ typedef struct {
> /**
> * @brief The actual thread priority queue.
> */
> - RBTree_Control Queue;
> + Priority_Aggregation Queue;
> } Thread_queue_Priority_queue;
>
> /**
> @@ -289,6 +326,11 @@ typedef struct _Thread_queue_Heads {
>
> #if defined(RTEMS_SMP)
> /**
> + * @brief Boost priority.
This note could be expanded (e.g. boosted by xxx). Thanks for
improving the doxy along the way!
> + */
> + Priority_Node Boost_priority;
> +
> + /**
> * @brief One priority queue per scheduler instance.
> */
> Thread_queue_Priority_queue Priority[ RTEMS_ZERO_LENGTH_ARRAY ];
> @@ -337,34 +379,33 @@ struct Thread_queue_Queue {
> };
>
> /**
> - * @brief Thread queue priority change operation.
> + * @brief Thread queue action operation.
> *
> * @param[in] queue The actual thread queue.
> * @param[in] the_thread The thread.
> - * @param[in] new_priority The new priority value.
> - *
> - * @see Thread_queue_Operations.
> + * @param[in] queue_context The thread queue context providing the thread queue
> + * action set to perform. Returns the thread queue action set to perform on
> + * the thread queue owner or the empty set in case there is nothing to do.
> */
> -typedef void ( *Thread_queue_Priority_change_operation )(
> - Thread_queue_Queue *queue,
> - Thread_Control *the_thread,
> - Priority_Control new_priority
> +typedef void ( *Thread_queue_Priority_actions_operation )(
> + Thread_queue_Queue *queue,
> + Priority_Actions *priority_actions
> );
>
> /**
> * @brief Thread queue enqueue operation.
> *
> * A potential thread to update the priority due to priority inheritance is
> - * returned via the thread queue path. This thread is handed over to
> - * _Thread_Update_priority().
> + * returned via the thread queue context. This thread is handed over to
> + * _Thread_Priority_update().
> *
> * @param[in] queue The actual thread queue.
> * @param[in] the_thread The thread to enqueue on the queue.
> */
> typedef void ( *Thread_queue_Enqueue_operation )(
> - Thread_queue_Queue *queue,
> - Thread_Control *the_thread,
> - Thread_queue_Path *path
> + Thread_queue_Queue *queue,
> + Thread_Control *the_thread,
> + Thread_queue_Context *queue_context
> );
>
> /**
> @@ -374,8 +415,9 @@ typedef void ( *Thread_queue_Enqueue_operation )(
> * @param[in] the_thread The thread to extract from the thread queue.
> */
> typedef void ( *Thread_queue_Extract_operation )(
> - Thread_queue_Queue *queue,
> - Thread_Control *the_thread
> + Thread_queue_Queue *queue,
> + Thread_Control *the_thread,
> + Thread_queue_Context *queue_context
> );
>
> /**
> @@ -390,9 +432,10 @@ typedef void ( *Thread_queue_Extract_operation )(
> * @return The previous first thread on the queue.
> */
> typedef Thread_Control *( *Thread_queue_Surrender_operation )(
> - Thread_queue_Queue *queue,
> - Thread_queue_Heads *heads,
> - Thread_Control *previous_owner
> + Thread_queue_Queue *queue,
> + Thread_queue_Heads *heads,
> + Thread_Control *previous_owner,
> + Thread_queue_Context *queue_context
> );
>
> /**
> @@ -415,16 +458,9 @@ typedef Thread_Control *( *Thread_queue_First_operation )(
> */
> struct Thread_queue_Operations {
> /**
> - * @brief Thread queue priority change operation.
> - *
> - * Called by _Thread_Change_priority() to notify a thread about a priority
> - * change. In case this thread waits currently for a resource the handler
> - * may adjust its data structures according to the new priority value. This
> - * handler must not be NULL, instead the default handler
> - * _Thread_Do_nothing_priority_change() should be used in case nothing needs
> - * to be done during a priority change.
> - */
> - Thread_queue_Priority_change_operation priority_change;
> + * @brief Thread queue priority actions operation.
This note also should be expanded a bit.
> + */
> + Thread_queue_Priority_actions_operation priority_actions;
>
> /**
> * @brief Thread queue enqueue operation.
> diff --git a/cpukit/score/include/rtems/score/threadqimpl.h b/cpukit/score/include/rtems/score/threadqimpl.h
> index 977b0ce..3555b7f 100644
> --- a/cpukit/score/include/rtems/score/threadqimpl.h
> +++ b/cpukit/score/include/rtems/score/threadqimpl.h
> @@ -21,7 +21,7 @@
>
> #include <rtems/score/threadq.h>
> #include <rtems/score/chainimpl.h>
> -#include <rtems/score/rbtreeimpl.h>
> +#include <rtems/score/priorityimpl.h>
> #include <rtems/score/scheduler.h>
> #include <rtems/score/smp.h>
> #include <rtems/score/thread.h>
> @@ -39,38 +39,8 @@ extern "C" {
> */
> /**@{*/
>
> -/**
> - * @brief Representation of a thread queue path from a start thread queue to
> - * the terminal thread queue.
> - *
> - * The start thread queue is determined by the object on which a thread intends
> - * to block. The terminal thread queue is the thread queue reachable via
> - * thread queue links those owner is not blocked on a thread queue. The thread
> - * queue links are determined by the thread queue owner and thread wait queue
> - * relationships.
> - */
> -struct Thread_queue_Path {
> -#if defined(RTEMS_SMP)
> - /**
> - * @brief The chain of thread queue links defining the thread queue path.
> - */
> - Chain_Control Links;
> -
> - /**
> - * @brief The start of a thread queue path.
> - */
> - Thread_queue_Link Start;
> -#endif
> -
> - /**
> - * @brief A potential thread to update the priority via
> - * _Thread_Update_priority().
> - *
> - * This thread is determined by thread queues which support priority
> - * inheritance.
> - */
> - Thread_Control *update_priority;
> -};
> +#define THREAD_QUEUE_LINK_OF_PATH_NODE( node ) \
> + RTEMS_CONTAINER_OF( node, Thread_queue_Link, Path_node );
>
> /**
> * @brief Thread queue with a layout compatible to struct _Thread_queue_Queue
> @@ -210,6 +180,42 @@ RTEMS_INLINE_ROUTINE void _Thread_queue_Context_set_deadlock_callout(
> queue_context->deadlock_callout = deadlock_callout;
> }
>
> +RTEMS_INLINE_ROUTINE void _Thread_queue_Context_clear_priority_updates(
> + Thread_queue_Context *queue_context
> +)
> +{
> + queue_context->Priority.update_count = 0;
> +}
> +
> +RTEMS_INLINE_ROUTINE size_t _Thread_queue_Context_get_priority_updates(
> + Thread_queue_Context *queue_context
> +)
> +{
> + return queue_context->Priority.update_count;
> +}
> +
> +RTEMS_INLINE_ROUTINE void _Thread_queue_Context_set_priority_updates(
> + Thread_queue_Context *queue_context,
> + size_t update_count
> +)
> +{
> + queue_context->Priority.update_count = update_count;
> +}
Are there some rules for what can/should set the priority updates? Is
this a monotonic counter until clear()?
> +
> +RTEMS_INLINE_ROUTINE void _Thread_queue_Context_add_priority_update(
> + Thread_queue_Context *queue_context,
> + Thread_Control *the_thread
> +)
> +{
> + size_t n;
> +
> + n = queue_context->Priority.update_count;
> + _Assert( n < RTEMS_ARRAY_SIZE( queue_context->Priority.update ) );
> +
> + queue_context->Priority.update_count = n + 1;
These two assignments could make use of the above _get/set_priority_updates().
> + queue_context->Priority.update[ n ] = the_thread;
> +}
> +
> /**
> * @brief Sets the MP callout in the thread queue context.
> *
> @@ -274,9 +280,12 @@ RTEMS_INLINE_ROUTINE void _Thread_queue_Heads_initialize(
> #if defined(RTEMS_SMP)
> size_t i;
>
> + _Priority_Node_initialize( &heads->Boost_priority, 0 );
> + _Priority_Node_set_inactive( &heads->Boost_priority );
> +
> for ( i = 0; i < _Scheduler_Count; ++i ) {
> _Chain_Initialize_node( &heads->Priority[ i ].Node );
> - _RBTree_Initialize_empty( &heads->Priority[ i ].Queue );
> + _Priority_Initialize_empty( &heads->Priority[ i ].Queue );
> }
> #endif
>
> @@ -579,16 +588,6 @@ RTEMS_INLINE_ROUTINE void _Thread_queue_Enqueue(
> );
> }
>
> -bool _Thread_queue_Do_extract_locked(
> - Thread_queue_Queue *queue,
> - const Thread_queue_Operations *operations,
> - Thread_Control *the_thread
> -#if defined(RTEMS_MULTIPROCESSING)
> - ,
> - const Thread_queue_Context *queue_context
> -#endif
> -);
> -
> /**
> * @brief Extracts the thread from the thread queue, restores the default wait
> * operations and restores the default thread lock.
> @@ -599,8 +598,7 @@ bool _Thread_queue_Do_extract_locked(
> * @param[in] queue The actual thread queue.
> * @param[in] operations The thread queue operations.
> * @param[in] the_thread The thread to extract.
> - * @param[in] queue_context The thread queue context. This parameter is only
> - * used on multiprocessing configurations.
> + * @param[in] queue_context The thread queue context.
> *
> * @return Returns the unblock indicator for _Thread_queue_Unblock_critical().
> * True indicates, that this thread must be unblocked by the scheduler later in
> @@ -610,32 +608,12 @@ bool _Thread_queue_Do_extract_locked(
> * since this thread may already block on another resource in an SMP
> * configuration.
> */
> -#if defined(RTEMS_MULTIPROCESSING)
> - #define _Thread_queue_Extract_locked( \
> - unblock, \
> - queue, \
> - the_thread, \
> - queue_context \
> - ) \
> - _Thread_queue_Do_extract_locked( \
> - unblock, \
> - queue, \
> - the_thread, \
> - queue_context \
> - )
> -#else
> - #define _Thread_queue_Extract_locked( \
> - unblock, \
> - queue, \
> - the_thread, \
> - queue_context \
> - ) \
> - _Thread_queue_Do_extract_locked( \
> - unblock, \
> - queue, \
> - the_thread \
> - )
> -#endif
> +bool _Thread_queue_Extract_locked(
> + Thread_queue_Queue *queue,
> + const Thread_queue_Operations *operations,
> + Thread_Control *the_thread,
> + const Thread_queue_Context *queue_context
> +);
>
> /**
> * @brief Unblocks the thread which was on the thread queue before.
> @@ -735,7 +713,7 @@ void _Thread_queue_Extract_with_proxy(
>
> /**
> * @brief Surrenders the thread queue previously owned by the thread to the
> - * first enqueued thread if it exists.
> + * first enqueued thread.
> *
> * The owner of the thread queue must be set to NULL by the caller.
> *
> @@ -743,21 +721,18 @@ void _Thread_queue_Extract_with_proxy(
> * thread dispatch if necessary.
> *
> * @param[in] queue The actual thread queue.
> - * @param[in] operations The thread queue operations.
> - * @param[in] heads The thread queue heads.
> + * @param[in] heads The thread queue heads. It must not be NULL.
> * @param[in] previous_owner The previous owner thread surrendering the thread
> * queue.
> - * @param[in] keep_priority Indicates if the previous owner thread should keep
> - * its current priority.
> * @param[in] queue_context The thread queue context of the lock acquire.
> + * @param[in] operations The thread queue operations.
> */
> void _Thread_queue_Surrender(
> Thread_queue_Queue *queue,
> - const Thread_queue_Operations *operations,
> Thread_queue_Heads *heads,
> Thread_Control *previous_owner,
> - bool keep_priority,
> - Thread_queue_Context *queue_context
> + Thread_queue_Context *queue_context,
> + const Thread_queue_Operations *operations
> );
>
> RTEMS_INLINE_ROUTINE bool _Thread_queue_Is_empty(
> @@ -980,6 +955,16 @@ void _Thread_queue_Unblock_proxy(
> );
> #endif
>
> +bool _Thread_queue_Path_acquire_critical(
> + Thread_queue_Queue *queue,
> + Thread_Control *the_thread,
> + Thread_queue_Context *queue_context
> +);
> +
> +void _Thread_queue_Path_release_critical(
> + Thread_queue_Context *queue_context
> +);
> +
> /**
> * @brief Helper structure to ensure that all objects containing a thread queue
> * have the right layout.
> diff --git a/cpukit/score/preinstall.am b/cpukit/score/preinstall.am
> index 61d44b8..94865a0 100644
> --- a/cpukit/score/preinstall.am
> +++ b/cpukit/score/preinstall.am
> @@ -200,6 +200,10 @@ $(PROJECT_INCLUDE)/rtems/score/priority.h: include/rtems/score/priority.h $(PROJ
> $(INSTALL_DATA) $< $(PROJECT_INCLUDE)/rtems/score/priority.h
> PREINSTALL_FILES += $(PROJECT_INCLUDE)/rtems/score/priority.h
>
> +$(PROJECT_INCLUDE)/rtems/score/priorityimpl.h: include/rtems/score/priorityimpl.h $(PROJECT_INCLUDE)/rtems/score/$(dirstamp)
> + $(INSTALL_DATA) $< $(PROJECT_INCLUDE)/rtems/score/priorityimpl.h
> +PREINSTALL_FILES += $(PROJECT_INCLUDE)/rtems/score/priorityimpl.h
> +
> $(PROJECT_INCLUDE)/rtems/score/prioritybitmap.h: include/rtems/score/prioritybitmap.h $(PROJECT_INCLUDE)/rtems/score/$(dirstamp)
> $(INSTALL_DATA) $< $(PROJECT_INCLUDE)/rtems/score/prioritybitmap.h
> PREINSTALL_FILES += $(PROJECT_INCLUDE)/rtems/score/prioritybitmap.h
> diff --git a/cpukit/score/src/mutex.c b/cpukit/score/src/mutex.c
> index bfa36ff..daa90a5 100644
> --- a/cpukit/score/src/mutex.c
> +++ b/cpukit/score/src/mutex.c
> @@ -128,33 +128,20 @@ static void _Mutex_Release_critical(
> )
> {
> Thread_queue_Heads *heads;
> - bool keep_priority;
>
> + heads = mutex->Queue.Queue.heads;
> mutex->Queue.Queue.owner = NULL;
> -
> --executing->resource_count;
>
> - /*
> - * Ensure that the owner resource count is visible to all other
> - * processors and that we read the latest priority restore
> - * hint.
> - */
> - _Atomic_Fence( ATOMIC_ORDER_ACQ_REL );
> -
> - heads = mutex->Queue.Queue.heads;
> - keep_priority = _Thread_Owns_resources( executing )
> - || !executing->priority_restore_hint;
> -
> - if ( __predict_true( heads == NULL && keep_priority ) ) {
> + if ( __predict_true( heads == NULL ) ) {
> _Mutex_Queue_release( mutex, queue_context );
> } else {
> _Thread_queue_Surrender(
> &mutex->Queue.Queue,
> - MUTEX_TQ_OPERATIONS,
> heads,
> executing,
> - keep_priority,
> - queue_context
> + queue_context,
> + MUTEX_TQ_OPERATIONS
> );
> }
> }
> diff --git a/cpukit/score/src/schedulercbs.c b/cpukit/score/src/schedulercbs.c
> index 98ec0eb..f114d4f 100644
> --- a/cpukit/score/src/schedulercbs.c
> +++ b/cpukit/score/src/schedulercbs.c
> @@ -19,24 +19,28 @@
> #endif
>
> #include <rtems/score/schedulercbsimpl.h>
> -#include <rtems/score/threadimpl.h>
> -#include <rtems/score/wkspace.h>
>
> void _Scheduler_CBS_Budget_callout(
> Thread_Control *the_thread
> )
> {
> - Priority_Control new_priority;
> - Priority_Control unused;
> - Scheduler_CBS_Node *node;
> - Scheduler_CBS_Server_id server_id;
> + Scheduler_CBS_Node *node;
> + Scheduler_CBS_Server_id server_id;
> + Thread_queue_Context queue_context;
> +
> + node = _Scheduler_CBS_Thread_get_node( the_thread );
>
> /* Put violating task to background until the end of period. */
> - new_priority = the_thread->Start.initial_priority;
> - _Thread_Set_priority( the_thread, new_priority, &unused, true );
> + _Thread_queue_Context_clear_priority_updates( &queue_context );
> + _Scheduler_CBS_Cancel_job(
> + NULL,
> + the_thread,
> + node->deadline_node,
> + &queue_context
> + );
> + _Thread_Priority_update( &queue_context );
>
> /* Invoke callback function if any. */
> - node = _Scheduler_CBS_Thread_get_node( the_thread );
> if ( node->cbs_server->cbs_budget_overrun ) {
> _Scheduler_CBS_Get_server_id(
> node->cbs_server->task_id,
> diff --git a/cpukit/score/src/schedulercbsnodeinit.c b/cpukit/score/src/schedulercbsnodeinit.c
> index 5380069..89b6f8e 100644
> --- a/cpukit/score/src/schedulercbsnodeinit.c
> +++ b/cpukit/score/src/schedulercbsnodeinit.c
> @@ -33,4 +33,5 @@ void _Scheduler_CBS_Node_initialize(
>
> the_node = _Scheduler_CBS_Node_downcast( node );
> the_node->cbs_server = NULL;
> + the_node->deadline_node = NULL;
> }
> diff --git a/cpukit/score/src/schedulercbsreleasejob.c b/cpukit/score/src/schedulercbsreleasejob.c
> index d2169af..186f95c 100644
> --- a/cpukit/score/src/schedulercbsreleasejob.c
> +++ b/cpukit/score/src/schedulercbsreleasejob.c
> @@ -21,10 +21,12 @@
>
> #include <rtems/score/schedulercbsimpl.h>
>
> -Thread_Control *_Scheduler_CBS_Release_job(
> +void _Scheduler_CBS_Release_job(
> const Scheduler_Control *scheduler,
> Thread_Control *the_thread,
> - uint64_t deadline
> + Priority_Node *priority_node,
> + uint64_t deadline,
> + Thread_queue_Context *queue_context
> )
> {
> Scheduler_CBS_Node *node;
> @@ -38,5 +40,37 @@ Thread_Control *_Scheduler_CBS_Release_job(
> the_thread->cpu_time_budget = serv_info->parameters.budget;
> }
>
> - return _Scheduler_EDF_Release_job( scheduler, the_thread, deadline );
> + node->deadline_node = priority_node;
> +
> + _Scheduler_EDF_Release_job(
> + scheduler,
> + the_thread,
> + priority_node,
> + deadline,
> + queue_context
> + );
> +}
> +
> +void _Scheduler_CBS_Cancel_job(
> + const Scheduler_Control *scheduler,
> + Thread_Control *the_thread,
> + Priority_Node *priority_node,
> + Thread_queue_Context *queue_context
> +)
> +{
> + Scheduler_CBS_Node *node;
> +
> + node = _Scheduler_CBS_Thread_get_node( the_thread );
> +
> + if ( node->deadline_node != NULL ) {
> + _Assert( node->deadline_node == priority_node );
> + node->deadline_node = NULL;
> +
> + _Scheduler_EDF_Cancel_job(
> + scheduler,
> + the_thread,
> + priority_node,
> + queue_context
> + );
> + }
> }
> diff --git a/cpukit/score/src/schedulercbsunblock.c b/cpukit/score/src/schedulercbsunblock.c
> index 0c1e48e..c09f471 100644
> --- a/cpukit/score/src/schedulercbsunblock.c
> +++ b/cpukit/score/src/schedulercbsunblock.c
> @@ -30,13 +30,11 @@ Scheduler_Void_or_thread _Scheduler_CBS_Unblock(
> Thread_Control *the_thread
> )
> {
> - Scheduler_EDF_Context *context;
> - Scheduler_CBS_Node *node;
> - Scheduler_CBS_Server *serv_info;
> - Priority_Control priority;
> - bool prepend_it;
> + Scheduler_CBS_Node *node;
> + Scheduler_CBS_Server *serv_info;
> + Priority_Control priority;
> + bool prepend_it;
>
> - context = _Scheduler_EDF_Get_context( scheduler );
> node = _Scheduler_CBS_Thread_get_node( the_thread );
> serv_info = node->cbs_server;
> priority = _Scheduler_Node_get_priority( &node->Base.Base, &prepend_it );
> @@ -55,40 +53,19 @@ Scheduler_Void_or_thread _Scheduler_CBS_Unblock(
> Priority_Control budget_left = priority - _Watchdog_Ticks_since_boot;
>
> if ( deadline * budget_left > budget * deadline_left ) {
> - /* Put late unblocked task to background until the end of period. */
> -
> - priority = node->Base.background_priority;
> - the_thread->real_priority = priority;
> + Thread_queue_Context queue_context;
>
> - if (
> - _Thread_Priority_less_than(
> - _Thread_Get_priority( the_thread ),
> - priority
> - ) || !_Thread_Owns_resources( the_thread )
> - ) {
> - the_thread->current_priority = priority;
> - }
> + /* Put late unblocked task to background until the end of period. */
> + _Thread_queue_Context_clear_priority_updates( &queue_context );
> + _Scheduler_CBS_Cancel_job(
> + scheduler,
> + the_thread,
> + node->deadline_node,
> + &queue_context
> + );
> }
> }
>
> - node->Base.current_priority = priority;
> - _Scheduler_EDF_Enqueue( context, &node->Base, priority );
> -
> - /*
> - * 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 ( priority < _Thread_Get_priority( _Thread_Heir ) ) {
> - _Scheduler_Update_heir( the_thread, priority == PRIORITY_PSEUDO_ISR );
> - }
> -
> + _Scheduler_EDF_Unblock( scheduler, the_thread );
> SCHEDULER_RETURN_VOID_OR_NULL;
> }
> diff --git a/cpukit/score/src/schedulerdefaultnodeinit.c b/cpukit/score/src/schedulerdefaultnodeinit.c
> index 10e71f8..53aed52 100644
> --- a/cpukit/score/src/schedulerdefaultnodeinit.c
> +++ b/cpukit/score/src/schedulerdefaultnodeinit.c
> @@ -28,7 +28,5 @@ void _Scheduler_default_Node_initialize(
> Priority_Control priority
> )
> {
> - (void) scheduler;
> -
> - _Scheduler_Node_do_initialize( node, the_thread, priority );
> + _Scheduler_Node_do_initialize( scheduler, node, the_thread, priority );
> }
> diff --git a/cpukit/score/src/schedulerdefaultreleasejob.c b/cpukit/score/src/schedulerdefaultreleasejob.c
> index 7272fc1..490d58b 100644
> --- a/cpukit/score/src/schedulerdefaultreleasejob.c
> +++ b/cpukit/score/src/schedulerdefaultreleasejob.c
> @@ -21,26 +21,30 @@
>
> #include <rtems/score/scheduler.h>
>
> -Thread_Control *_Scheduler_default_Release_job(
> +void _Scheduler_default_Release_job(
> const Scheduler_Control *scheduler,
> Thread_Control *the_thread,
> - uint64_t deadline
> + Priority_Node *priority_node,
> + uint64_t deadline,
> + Thread_queue_Context *queue_context
> )
> {
> (void) scheduler;
> (void) the_thread;
> + (void) priority_node;
> (void) deadline;
> -
> - return NULL;
> + (void) queue_context;
> }
>
> -Thread_Control *_Scheduler_default_Cancel_job(
> +void _Scheduler_default_Cancel_job(
> const Scheduler_Control *scheduler,
> - Thread_Control *the_thread
> + Thread_Control *the_thread,
> + Priority_Node *priority_node,
> + Thread_queue_Context *queue_context
> )
> {
> (void) scheduler;
> (void) the_thread;
> -
> - return NULL;
> + (void) priority_node;
> + (void) queue_context;
> }
> diff --git a/cpukit/score/src/scheduleredfchangepriority.c b/cpukit/score/src/scheduleredfchangepriority.c
> index 9a73128..8940b1d 100644
> --- a/cpukit/score/src/scheduleredfchangepriority.c
> +++ b/cpukit/score/src/scheduleredfchangepriority.c
> @@ -54,16 +54,12 @@ Scheduler_Void_or_thread _Scheduler_EDF_Update_priority(
> node = _Scheduler_EDF_Thread_get_node( the_thread );
> priority = _Scheduler_Node_get_priority( &node->Base, &prepend_it );
>
> - if ( priority == node->current_priority ) {
> + if ( priority == node->priority ) {
> /* Nothing to do */
> SCHEDULER_RETURN_VOID_OR_NULL;
> }
>
> - if ( ( priority & SCHEDULER_EDF_PRIO_MSB ) != 0 ) {
> - node->background_priority = priority;
> - }
> -
> - node->current_priority = priority;
> + node->priority = priority;
> context = _Scheduler_EDF_Get_context( scheduler );
>
> _Scheduler_EDF_Extract( context, node );
> diff --git a/cpukit/score/src/scheduleredfnodeinit.c b/cpukit/score/src/scheduleredfnodeinit.c
> index d290bd7..94f8fac 100644
> --- a/cpukit/score/src/scheduleredfnodeinit.c
> +++ b/cpukit/score/src/scheduleredfnodeinit.c
> @@ -29,11 +29,9 @@ void _Scheduler_EDF_Node_initialize(
> {
> Scheduler_EDF_Node *the_node;
>
> - (void) scheduler;
> -
> - _Scheduler_Node_do_initialize( node, the_thread, priority );
> + _Scheduler_Node_do_initialize( scheduler, node, the_thread, priority );
>
> the_node = _Scheduler_EDF_Node_downcast( node );
> - the_node->thread = the_thread;
> _RBTree_Initialize_node( &the_node->Node );
> + the_node->priority = priority;
> }
> diff --git a/cpukit/score/src/scheduleredfreleasejob.c b/cpukit/score/src/scheduleredfreleasejob.c
> index 4c74c48..c19d9b9 100644
> --- a/cpukit/score/src/scheduleredfreleasejob.c
> +++ b/cpukit/score/src/scheduleredfreleasejob.c
> @@ -20,75 +20,47 @@
>
> #include <rtems/score/scheduleredfimpl.h>
>
> -static bool _Scheduler_EDF_Release_job_filter(
> - Thread_Control *the_thread,
> - Priority_Control *new_priority_p,
> - void *arg
> +void _Scheduler_EDF_Release_job(
> + const Scheduler_Control *scheduler,
> + Thread_Control *the_thread,
> + Priority_Node *priority_node,
> + uint64_t deadline,
> + Thread_queue_Context *queue_context
> )
> {
> - Scheduler_EDF_Node *node;
> - Priority_Control current_priority;
> - Priority_Control new_priority;
> + (void) scheduler;
>
> - node = _Scheduler_EDF_Thread_get_node( the_thread );
> + _Thread_Wait_acquire_critical( the_thread, queue_context );
>
> - current_priority = _Thread_Get_priority( the_thread );
> - new_priority = *new_priority_p;
> + _Priority_Node_set_priority( priority_node, deadline );
>
> - node->current_priority = new_priority;
> - the_thread->real_priority = new_priority;
> + if ( _Priority_Node_is_active( priority_node ) ) {
> + _Thread_Priority_changed(
> + the_thread,
> + priority_node,
> + false,
> + queue_context
> + );
> + } else {
> + _Thread_Priority_add( the_thread, priority_node, queue_context );
> + }
>
> - return _Thread_Priority_less_than( current_priority, new_priority )
> - || !_Thread_Owns_resources( the_thread );
> + _Thread_Wait_release_critical( the_thread, queue_context );
> }
>
> -Thread_Control *_Scheduler_EDF_Release_job(
> +void _Scheduler_EDF_Cancel_job(
> const Scheduler_Control *scheduler,
> Thread_Control *the_thread,
> - uint64_t deadline
> -)
> -{
> - return _Thread_Apply_priority(
> - the_thread,
> - deadline,
> - NULL,
> - _Scheduler_EDF_Release_job_filter,
> - true
> - );
> -}
> -
> -static bool _Scheduler_EDF_Cancel_job_filter(
> - Thread_Control *the_thread,
> - Priority_Control *new_priority_p,
> - void *arg
> + Priority_Node *priority_node,
> + Thread_queue_Context *queue_context
> )
> {
> - Scheduler_EDF_Node *node;
> - Priority_Control current_priority;
> - Priority_Control new_priority;
> + (void) scheduler;
>
> - node = _Scheduler_EDF_Thread_get_node( the_thread );
> + _Thread_Wait_acquire_critical( the_thread, queue_context );
>
> - current_priority = _Thread_Get_priority( the_thread );
> - new_priority = node->background_priority;
> + _Thread_Priority_remove( the_thread, priority_node, queue_context );
> + _Priority_Node_set_inactive( priority_node );
>
> - node->current_priority = new_priority;
> - the_thread->real_priority = new_priority;
> -
> - return _Thread_Priority_less_than( current_priority, new_priority )
> - || !_Thread_Owns_resources( the_thread );
> -}
> -
> -Thread_Control *_Scheduler_EDF_Cancel_job(
> - const Scheduler_Control *scheduler,
> - Thread_Control *the_thread
> -)
> -{
> - return _Thread_Apply_priority(
> - the_thread,
> - 0,
> - NULL,
> - _Scheduler_EDF_Cancel_job_filter,
> - true
> - );
> + _Thread_Wait_release_critical( the_thread, queue_context );
> }
> diff --git a/cpukit/score/src/scheduleredfunblock.c b/cpukit/score/src/scheduleredfunblock.c
> index 9b156ec..a5cc4b6 100644
> --- a/cpukit/score/src/scheduleredfunblock.c
> +++ b/cpukit/score/src/scheduleredfunblock.c
> @@ -37,7 +37,7 @@ Scheduler_Void_or_thread _Scheduler_EDF_Unblock(
> priority = _Scheduler_Node_get_priority( &node->Base, &prepend_it );
> (void) prepend_it;
>
> - node->current_priority = priority;
> + node->priority = priority;
> _Scheduler_EDF_Enqueue( context, node, priority );
>
> /*
> diff --git a/cpukit/score/src/scheduleredfyield.c b/cpukit/score/src/scheduleredfyield.c
> index 06c1b46..3e64e5c 100644
> --- a/cpukit/score/src/scheduleredfyield.c
> +++ b/cpukit/score/src/scheduleredfyield.c
> @@ -33,7 +33,7 @@ Scheduler_Void_or_thread _Scheduler_EDF_Yield(
> node = _Scheduler_EDF_Thread_get_node( the_thread );
>
> _Scheduler_EDF_Extract( context, node );
> - _Scheduler_EDF_Enqueue( context, node, node->current_priority );
> + _Scheduler_EDF_Enqueue( context, node, node->priority );
> _Scheduler_EDF_Schedule_body( scheduler, the_thread, true );
>
> SCHEDULER_RETURN_VOID_OR_NULL;
> diff --git a/cpukit/score/src/schedulerpriority.c b/cpukit/score/src/schedulerpriority.c
> index 11cee92..ddfd973 100644
> --- a/cpukit/score/src/schedulerpriority.c
> +++ b/cpukit/score/src/schedulerpriority.c
> @@ -43,7 +43,7 @@ void _Scheduler_priority_Node_initialize(
> Scheduler_priority_Context *context;
> Scheduler_priority_Node *the_node;
>
> - _Scheduler_Node_do_initialize( node, the_thread, priority );
> + _Scheduler_Node_do_initialize( scheduler, node, the_thread, priority );
>
> context = _Scheduler_priority_Get_context( scheduler );
> the_node = _Scheduler_priority_Node_downcast( node );
> diff --git a/cpukit/score/src/schedulerprioritysmp.c b/cpukit/score/src/schedulerprioritysmp.c
> index 07e7af4..e624a6a 100644
> --- a/cpukit/score/src/schedulerprioritysmp.c
> +++ b/cpukit/score/src/schedulerprioritysmp.c
> @@ -57,7 +57,12 @@ void _Scheduler_priority_SMP_Node_initialize(
> Scheduler_priority_SMP_Node *the_node;
>
> the_node = _Scheduler_priority_SMP_Node_downcast( node );
> - _Scheduler_SMP_Node_initialize( &the_node->Base, the_thread, priority );
> + _Scheduler_SMP_Node_initialize(
> + scheduler,
> + &the_node->Base,
> + the_thread,
> + priority
> + );
>
> context = _Scheduler_Get_context( scheduler );
> self = _Scheduler_priority_SMP_Get_self( context );
> diff --git a/cpukit/score/src/schedulersimplesmp.c b/cpukit/score/src/schedulersimplesmp.c
> index 8f86ea8..9606896 100644
> --- a/cpukit/score/src/schedulersimplesmp.c
> +++ b/cpukit/score/src/schedulersimplesmp.c
> @@ -52,7 +52,7 @@ void _Scheduler_simple_SMP_Node_initialize(
> Scheduler_SMP_Node *the_node;
>
> the_node = _Scheduler_SMP_Node_downcast( node );
> - _Scheduler_SMP_Node_initialize( the_node, the_thread, priority );
> + _Scheduler_SMP_Node_initialize( scheduler, the_node, the_thread, priority );
> }
>
> static void _Scheduler_simple_SMP_Do_update(
> diff --git a/cpukit/score/src/schedulerstrongapa.c b/cpukit/score/src/schedulerstrongapa.c
> index 5d7c7f7..fc6d012 100644
> --- a/cpukit/score/src/schedulerstrongapa.c
> +++ b/cpukit/score/src/schedulerstrongapa.c
> @@ -183,7 +183,12 @@ void _Scheduler_strong_APA_Node_initialize(
> Scheduler_strong_APA_Node *the_node;
>
> the_node = _Scheduler_strong_APA_Node_downcast( node );
> - _Scheduler_SMP_Node_initialize( &the_node->Base, the_thread, priority );
> + _Scheduler_SMP_Node_initialize(
> + scheduler,
> + &the_node->Base,
> + the_thread,
> + priority
> + );
>
> context = _Scheduler_Get_context( scheduler );
> self = _Scheduler_strong_APA_Get_self( context );
> diff --git a/cpukit/score/src/thread.c b/cpukit/score/src/thread.c
> index c569ae5..864b21b 100644
> --- a/cpukit/score/src/thread.c
> +++ b/cpukit/score/src/thread.c
> @@ -32,9 +32,7 @@
> THREAD_OFFSET_ASSERT( Object );
> THREAD_OFFSET_ASSERT( Join_queue );
> THREAD_OFFSET_ASSERT( current_state );
> -THREAD_OFFSET_ASSERT( current_priority );
> -THREAD_OFFSET_ASSERT( real_priority );
> -THREAD_OFFSET_ASSERT( priority_restore_hint );
> +THREAD_OFFSET_ASSERT( Real_priority );
> THREAD_OFFSET_ASSERT( resource_count );
> THREAD_OFFSET_ASSERT( Scheduler );
> THREAD_OFFSET_ASSERT( Wait );
> diff --git a/cpukit/score/src/threadchangepriority.c b/cpukit/score/src/threadchangepriority.c
> index 3429e1a..42172b2 100644
> --- a/cpukit/score/src/threadchangepriority.c
> +++ b/cpukit/score/src/threadchangepriority.c
> @@ -10,6 +10,8 @@
> * COPYRIGHT (c) 1989-2014.
> * On-Line Applications Research Corporation (OAR).
> *
> + * Copyright (c) 2013, 2016 embedded brains GmbH
> + *
> * 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.
> @@ -20,145 +22,313 @@
> #endif
>
> #include <rtems/score/threadimpl.h>
> +#include <rtems/score/assert.h>
> #include <rtems/score/schedulerimpl.h>
>
> -static Thread_Control *_Thread_Apply_priority_locked(
> +static void _Thread_Set_scheduler_node_priority(
> + Priority_Aggregation *priority_aggregation,
> + bool prepend_it
> +)
> +{
> + _Scheduler_Node_set_priority(
> + SCHEDULER_NODE_OF_WAIT_PRIORITY_NODE( priority_aggregation ),
> + _Priority_Get_priority( priority_aggregation ),
> + prepend_it
> + );
> +}
> +
> +#if defined(RTEMS_SMP)
> +static void _Thread_Priority_action_add(
> + Priority_Aggregation *priority_aggregation,
> + Priority_Actions *priority_actions,
> + void *arg
> +)
> +{
> + _Thread_Set_scheduler_node_priority( priority_aggregation, false );
> + _Priority_Set_action_type( priority_aggregation, PRIORITY_ACTION_ADD );
> + _Priority_Actions_add( priority_actions, priority_aggregation );
> +}
> +
> +static void _Thread_Priority_action_remove(
> + Priority_Aggregation *priority_aggregation,
> + Priority_Actions *priority_actions,
> + void *arg
> +)
> +{
> + _Thread_Set_scheduler_node_priority( priority_aggregation, true );
> + _Priority_Set_action_type( priority_aggregation, PRIORITY_ACTION_REMOVE );
> + _Priority_Actions_add( priority_actions, priority_aggregation );
> +}
> +#endif
> +
> +static void _Thread_Priority_action_change(
> + Priority_Aggregation *priority_aggregation,
> + bool prepend_it,
> + Priority_Actions *priority_actions,
> + void *arg
> +)
> +{
> + _Thread_Set_scheduler_node_priority( priority_aggregation, prepend_it );
> +#if defined(RTEMS_SMP)
> + _Priority_Set_action_type( priority_aggregation, PRIORITY_ACTION_CHANGE );
> +#elif defined(RTEMS_DEBUG)
> + _Priority_Set_action_type( priority_aggregation, PRIORITY_ACTION_INVALID );
> +#endif
> + _Priority_Actions_add( priority_actions, priority_aggregation );
> +}
> +
> +static void _Thread_Priority_do_perform_actions(
> Thread_Control *the_thread,
> - Priority_Control new_priority,
> - void *arg,
> - Thread_Change_priority_filter filter,
> + Thread_queue_Queue *queue,
> + const Thread_queue_Operations *operations,
> bool prepend_it,
> Thread_queue_Context *queue_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 ) ) {
> - _Scheduler_Thread_set_priority( the_thread, new_priority, prepend_it );
> -
> - ( *the_thread->Wait.operations->priority_change )(
> - the_thread->Wait.queue,
> - the_thread,
> - new_priority
> + Priority_Actions actions_now;
> + Priority_Aggregation *priority_aggregation;
> +
> + _Assert( !_Priority_Actions_is_empty( &queue_context->Priority.Actions ) );
> +
> + _Priority_Actions_move( &actions_now, &queue_context->Priority.Actions );
> + priority_aggregation = _Priority_Actions_get_first( &actions_now );
> +
> + do {
> + Priority_Aggregation *priority_aggregation_next;
> + Priority_Node *priority_action_node;
> + Priority_Action_type priority_action_type;
> +
> + priority_aggregation_next = _Priority_Get_next_action(
> + priority_aggregation
> + );
> +
> + priority_action_node = priority_aggregation->Action.node;
> + priority_action_type = priority_aggregation->Action.type;
> +
> + switch ( priority_action_type ) {
> + case PRIORITY_ACTION_ADD:
> +#if defined(RTEMS_SMP)
> + _Priority_Insert(
> + priority_aggregation,
> + priority_action_node,
> + &queue_context->Priority.Actions,
> + _Thread_Priority_action_add,
> + _Thread_Priority_action_change,
> + NULL
> + );
> +#else
> + _Priority_Non_empty_insert(
> + priority_aggregation,
> + priority_action_node,
> + &queue_context->Priority.Actions,
> + _Thread_Priority_action_change,
> + NULL
> + );
> +#endif
> + break;
> + case PRIORITY_ACTION_REMOVE:
> +#if defined(RTEMS_SMP)
> + _Priority_Extract(
> + priority_aggregation,
> + priority_action_node,
> + &queue_context->Priority.Actions,
> + _Thread_Priority_action_remove,
> + _Thread_Priority_action_change,
> + NULL
> + );
> +#else
> + _Priority_Extract_non_empty(
> + priority_aggregation,
> + priority_action_node,
> + &queue_context->Priority.Actions,
> + _Thread_Priority_action_change,
> + NULL
> + );
> +#endif
> + break;
> + default:
> + _Assert( priority_action_type == PRIORITY_ACTION_CHANGE );
> + _Priority_Change(
> + priority_aggregation,
> + priority_action_node,
> + prepend_it,
> + &queue_context->Priority.Actions,
> + _Thread_Priority_action_change,
> + NULL
> + );
> + break;
> + }
> +
> + priority_aggregation = priority_aggregation_next;
> + } while ( _Priority_Actions_is_valid( priority_aggregation ) );
> +
> + if ( !_Priority_Actions_is_empty( &queue_context->Priority.Actions ) ) {
> + _Thread_queue_Context_add_priority_update( queue_context, the_thread );
> + ( *operations->priority_actions )(
> + queue,
> + &queue_context->Priority.Actions
> );
> - } else {
> - the_thread = NULL;
> }
> +}
>
> - return the_thread;
> +void _Thread_Priority_perform_actions(
> + Thread_Control *start_of_path,
> + Thread_queue_Context *queue_context
> +)
> +{
> +#if defined(RTEMS_SMP)
> + Thread_queue_Link *link;
> +#endif
> + Thread_Control *the_thread;
> + size_t update_count;
> +
> + _Assert( start_of_path != NULL );
> +
> +#if defined(RTEMS_SMP)
> + link = &queue_context->Path.Start;
> +#endif
> + the_thread = start_of_path;
> + update_count = _Thread_queue_Context_get_priority_updates( queue_context );
> +
> + while ( true ) {
> + Thread_queue_Queue *queue;
> +
> +#if defined(RTEMS_SMP)
> + _Assert( link->owner == the_thread );
> + queue = link->Lock_context.Wait.queue;
> +#else
> + queue = the_thread->Wait.queue;
> +#endif
> +
> + _Thread_Priority_do_perform_actions(
> + the_thread,
> + queue,
> + the_thread->Wait.operations,
> + false,
> + queue_context
> + );
> +
> + if ( _Priority_Actions_is_empty( &queue_context->Priority.Actions ) ) {
> + return;
> + }
> +
> + _Assert( queue != NULL );
> + the_thread = queue->owner;
> + _Assert( the_thread != NULL );
> +
> +#if defined(RTEMS_SMP)
> + link = THREAD_QUEUE_LINK_OF_PATH_NODE( _Chain_Next( &link->Path_node ) );
> +#endif
> + _Thread_queue_Context_set_priority_updates( queue_context, update_count );
Has the queue_context->update_count changed since it was earlier read?
If yes, why is it correct to restore it?
> + }
> }
>
> -Thread_Control *_Thread_Apply_priority(
> - Thread_Control *the_thread,
> - Priority_Control new_priority,
> - void *arg,
> - Thread_Change_priority_filter filter,
> - bool prepend_it
> +static void _Thread_Priority_apply(
> + Thread_Control *the_thread,
> + Priority_Node *priority_action_node,
> + Thread_queue_Context *queue_context,
> + bool prepend_it,
> + Priority_Action_type priority_action_type
> )
> {
> - Thread_queue_Context queue_context;
> - Thread_Control *the_thread_to_update;
> + Scheduler_Node *own_node;
> + Thread_queue_Queue *queue;
>
> - _Thread_Wait_acquire( the_thread, &queue_context );
> - the_thread_to_update = _Thread_Apply_priority_locked(
> + own_node = _Thread_Scheduler_get_own_node( the_thread );
> + _Priority_Actions_initialize_one(
> + &queue_context->Priority.Actions,
> + &own_node->Wait.Priority,
> + priority_action_node,
> + priority_action_type
> + );
> + queue = the_thread->Wait.queue;
> + _Thread_Priority_do_perform_actions(
> the_thread,
> - new_priority,
> - arg,
> - filter,
> + queue,
> + the_thread->Wait.operations,
> prepend_it,
> - &queue_context
> + queue_context
> );
> - _Thread_Wait_release( the_thread, &queue_context );
> - return the_thread_to_update;
> -}
> -
> -void _Thread_Update_priority( Thread_Control *the_thread )
> -{
> - if ( the_thread != NULL ) {
> - ISR_lock_Context lock_context;
>
> - _Thread_State_acquire( the_thread, &lock_context );
> - _Scheduler_Update_priority( the_thread );
> - _Thread_State_release( the_thread, &lock_context );
> + if ( !_Priority_Actions_is_empty( &queue_context->Priority.Actions ) ) {
> + _Thread_queue_Path_acquire_critical( queue, the_thread, queue_context );
> + _Thread_Priority_perform_actions( queue->owner, queue_context );
> + _Thread_queue_Path_release_critical( queue_context );
> }
> }
>
> -void _Thread_Change_priority(
> - Thread_Control *the_thread,
> - Priority_Control new_priority,
> - void *arg,
> - Thread_Change_priority_filter filter,
> - bool prepend_it
> +void _Thread_Priority_add(
> + Thread_Control *the_thread,
> + Priority_Node *priority_node,
> + Thread_queue_Context *queue_context
> )
> {
> - the_thread = _Thread_Apply_priority(
> + _Thread_Priority_apply(
> the_thread,
> - new_priority,
> - arg,
> - filter,
> - prepend_it
> + priority_node,
> + queue_context,
> + false,
> + PRIORITY_ACTION_ADD
> );
> - _Thread_Update_priority( the_thread );
> }
>
> -static bool _Thread_Raise_priority_filter(
> - Thread_Control *the_thread,
> - Priority_Control *new_priority,
> - void *arg
> +void _Thread_Priority_remove(
> + Thread_Control *the_thread,
> + Priority_Node *priority_node,
> + Thread_queue_Context *queue_context
> )
> {
> - return _Thread_Priority_less_than(
> - _Thread_Get_priority( the_thread ),
> - *new_priority
> + _Thread_Priority_apply(
> + the_thread,
> + priority_node,
> + queue_context,
> + true,
> + PRIORITY_ACTION_REMOVE
> );
> }
>
> -void _Thread_Raise_priority(
> - Thread_Control *the_thread,
> - Priority_Control new_priority
> +void _Thread_Priority_changed(
> + Thread_Control *the_thread,
> + Priority_Node *priority_node,
> + bool prepend_it,
> + Thread_queue_Context *queue_context
> )
> {
> - _Thread_Change_priority(
> + _Thread_Priority_apply(
> the_thread,
> - new_priority,
> - NULL,
> - _Thread_Raise_priority_filter,
> - false
> + priority_node,
> + queue_context,
> + prepend_it,
> + PRIORITY_ACTION_CHANGE
> );
> }
>
> -static bool _Thread_Restore_priority_filter(
> - Thread_Control *the_thread,
> - Priority_Control *new_priority,
> - void *arg
> +void _Thread_Priority_replace(
> + Thread_Control *the_thread,
> + Priority_Node *victim_node,
> + Priority_Node *replacement_node
> )
> {
> - *new_priority = the_thread->real_priority;
> -
> - the_thread->priority_restore_hint = false;
> + Scheduler_Node *own_node;
>
> - return *new_priority != _Thread_Get_priority( the_thread );
> + own_node = _Thread_Scheduler_get_own_node( the_thread );
> + _Priority_Replace( &own_node->Wait.Priority, victim_node, replacement_node );
> }
>
> -void _Thread_Restore_priority( Thread_Control *the_thread )
> +void _Thread_Priority_update( Thread_queue_Context *queue_context )
> {
> - _Thread_Change_priority(
> - the_thread,
> - 0,
> - NULL,
> - _Thread_Restore_priority_filter,
> - true
> - );
> + size_t i;
> + size_t n;
> +
> + n = queue_context->Priority.update_count;
> +
> + for ( i = 0; i < n ; ++i ) {
> + Thread_Control *the_thread;
> + ISR_lock_Context lock_context;
> +
> + the_thread = queue_context->Priority.update[ i ];
> + _Thread_State_acquire( the_thread, &lock_context );
> + _Scheduler_Update_priority( the_thread );
> + _Thread_State_release( the_thread, &lock_context );
> + }
Why doesn't this decrement the update_count after completing the
update? I'm missing some important detail about the "lifetime" of
these update counters.
[...]
The rest looked relatively straightforward on a quick skim.
-Gedare
More information about the devel
mailing list