summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSebastian Huber <sebastian.huber@embedded-brains.de>2016-09-09 11:00:06 +0200
committerSebastian Huber <sebastian.huber@embedded-brains.de>2016-09-21 08:59:33 +0200
commitf6142c19f192e40ee1aa9ff67eb1c711343c157d (patch)
tree061086bf693d934063cdd601498e0e138e72eeb7
parent8123cae864579219e5003a67b451ca4cc07d998b (diff)
downloadrtems-f6142c19f192e40ee1aa9ff67eb1c711343c157d.tar.bz2
score: Scheduler node awareness for thread queues
Maintain the priority of a thread for each scheduler instance via the thread queue enqueue, extract, priority actions and surrender operations. This replaces the primitive priority boosting. Update #2556.
-rw-r--r--cpukit/score/include/rtems/score/schedulernode.h5
-rw-r--r--cpukit/score/include/rtems/score/threadimpl.h45
-rw-r--r--cpukit/score/include/rtems/score/threadq.h11
-rw-r--r--cpukit/score/include/rtems/score/threadqimpl.h6
-rw-r--r--cpukit/score/src/threadchangepriority.c50
-rw-r--r--cpukit/score/src/threadqenqueue.c97
-rw-r--r--cpukit/score/src/threadqops.c967
-rw-r--r--testsuites/smptests/smpmutex01/init.c373
8 files changed, 1211 insertions, 343 deletions
diff --git a/cpukit/score/include/rtems/score/schedulernode.h b/cpukit/score/include/rtems/score/schedulernode.h
index 8d00a43d31..2397ba4b79 100644
--- a/cpukit/score/include/rtems/score/schedulernode.h
+++ b/cpukit/score/include/rtems/score/schedulernode.h
@@ -209,6 +209,11 @@ typedef struct Scheduler_Node {
extern const size_t _Scheduler_Node_size;
#endif
+#if defined(RTEMS_SMP)
+#define SCHEDULER_NODE_OF_THREAD_WAIT_NODE( node ) \
+ RTEMS_CONTAINER_OF( node, Scheduler_Node, Thread.Wait_node )
+#endif
+
#ifdef __cplusplus
}
#endif /* __cplusplus */
diff --git a/cpukit/score/include/rtems/score/threadimpl.h b/cpukit/score/include/rtems/score/threadimpl.h
index 09af9c15dd..7b978ea477 100644
--- a/cpukit/score/include/rtems/score/threadimpl.h
+++ b/cpukit/score/include/rtems/score/threadimpl.h
@@ -997,6 +997,20 @@ RTEMS_INLINE_ROUTINE Scheduler_Node *_Thread_Scheduler_get_own_node(
#endif
}
+RTEMS_INLINE_ROUTINE Scheduler_Node *_Thread_Scheduler_get_home_node(
+ const Thread_Control *the_thread
+)
+{
+#if defined(RTEMS_SMP)
+ _Assert( !_Chain_Is_empty( &the_thread->Scheduler.Wait_nodes ) );
+ return SCHEDULER_NODE_OF_THREAD_WAIT_NODE(
+ _Chain_First( &the_thread->Scheduler.Wait_nodes )
+ );
+#else
+ return the_thread->Scheduler.nodes;
+#endif
+}
+
RTEMS_INLINE_ROUTINE Scheduler_Node *_Thread_Scheduler_get_node_by_index(
const Thread_Control *the_thread,
size_t scheduler_index
@@ -1308,21 +1322,22 @@ RTEMS_INLINE_ROUTINE void _Thread_Wait_release(
}
/**
- * @brief Claims the thread wait queue and operations.
+ * @brief Claims the thread wait queue.
*
* The caller must not be the owner of the default thread wait lock. The
- * caller must be the owner of the corresponding thread queue lock.
+ * caller must be the owner of the corresponding thread queue lock. The
+ * registration of the corresponding thread queue operations is deferred and
+ * done after the deadlock detection. This is crucial to support timeouts on
+ * SMP configurations.
*
* @param[in] the_thread The thread.
* @param[in] queue The new thread queue.
- * @param[in] operations The new thread operations.
*
- * @see _Thread_Wait_restore_default().
+ * @see _Thread_Wait_claim_finalize() and _Thread_Wait_restore_default().
*/
RTEMS_INLINE_ROUTINE void _Thread_Wait_claim(
- Thread_Control *the_thread,
- Thread_queue_Queue *queue,
- const Thread_queue_Operations *operations
+ Thread_Control *the_thread,
+ Thread_queue_Queue *queue
)
{
ISR_lock_Context lock_context;
@@ -1338,12 +1353,26 @@ RTEMS_INLINE_ROUTINE void _Thread_Wait_claim(
#endif
the_thread->Wait.queue = queue;
- the_thread->Wait.operations = operations;
_Thread_Wait_release_default_critical( the_thread, &lock_context );
}
/**
+ * @brief Finalizes the thread wait queue claim via registration of the
+ * corresponding thread queue operations.
+ *
+ * @param[in] the_thread The thread.
+ * @param[in] operations The corresponding thread queue operations.
+ */
+RTEMS_INLINE_ROUTINE void _Thread_Wait_claim_finalize(
+ Thread_Control *the_thread,
+ const Thread_queue_Operations *operations
+)
+{
+ the_thread->Wait.operations = operations;
+}
+
+/**
* @brief Removes a thread wait lock request.
*
* On SMP configurations, removes a thread wait lock request.
diff --git a/cpukit/score/include/rtems/score/threadq.h b/cpukit/score/include/rtems/score/threadq.h
index 6f62506c26..084161cc4d 100644
--- a/cpukit/score/include/rtems/score/threadq.h
+++ b/cpukit/score/include/rtems/score/threadq.h
@@ -216,6 +216,12 @@ typedef struct {
* @brief The start of a thread queue path.
*/
Thread_queue_Link Start;
+
+ /**
+ * @brief In case of a deadlock, a link for the first thread on the path
+ * that tries to enqueue on a thread queue.
+ */
+ Thread_queue_Link Deadlock;
} Path;
#endif
@@ -345,11 +351,6 @@ typedef struct _Thread_queue_Heads {
#if defined(RTEMS_SMP)
/**
- * @brief Boost priority.
- */
- Priority_Node Boost_priority;
-
- /**
* @brief One priority queue per scheduler instance.
*/
Thread_queue_Priority_queue Priority[ RTEMS_ZERO_LENGTH_ARRAY ];
diff --git a/cpukit/score/include/rtems/score/threadqimpl.h b/cpukit/score/include/rtems/score/threadqimpl.h
index 65b0e8eeab..e24beec1bb 100644
--- a/cpukit/score/include/rtems/score/threadqimpl.h
+++ b/cpukit/score/include/rtems/score/threadqimpl.h
@@ -280,12 +280,10 @@ 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 );
_Priority_Initialize_empty( &heads->Priority[ i ].Queue );
+ heads->Priority[ i ].Queue.scheduler = &_Scheduler_Table[ i ];
}
#endif
@@ -955,6 +953,7 @@ void _Thread_queue_Unblock_proxy(
);
#endif
+#if defined(RTEMS_SMP)
bool _Thread_queue_Path_acquire_critical(
Thread_queue_Queue *queue,
Thread_Control *the_thread,
@@ -964,6 +963,7 @@ bool _Thread_queue_Path_acquire_critical(
void _Thread_queue_Path_release_critical(
Thread_queue_Context *queue_context
);
+#endif
/**
* @brief Helper structure to ensure that all objects containing a thread queue
diff --git a/cpukit/score/src/threadchangepriority.c b/cpukit/score/src/threadchangepriority.c
index c10c712710..41b6382333 100644
--- a/cpukit/score/src/threadchangepriority.c
+++ b/cpukit/score/src/threadchangepriority.c
@@ -44,6 +44,16 @@ static void _Thread_Priority_action_add(
void *arg
)
{
+ Scheduler_Node *scheduler_node;
+ Thread_Control *the_thread;
+
+ scheduler_node = SCHEDULER_NODE_OF_WAIT_PRIORITY( priority_aggregation );
+ the_thread = arg;
+
+ _Chain_Append_unprotected(
+ &the_thread->Scheduler.Wait_nodes,
+ &scheduler_node->Thread.Wait_node
+ );
_Thread_Set_scheduler_node_priority( priority_aggregation, false );
_Priority_Set_action_type( priority_aggregation, PRIORITY_ACTION_ADD );
_Priority_Actions_add( priority_actions, priority_aggregation );
@@ -55,6 +65,11 @@ static void _Thread_Priority_action_remove(
void *arg
)
{
+ Scheduler_Node *scheduler_node;
+
+ scheduler_node = SCHEDULER_NODE_OF_WAIT_PRIORITY( priority_aggregation );
+
+ _Chain_Extract_unprotected( &scheduler_node->Thread.Wait_node );
_Thread_Set_scheduler_node_priority( priority_aggregation, true );
_Priority_Set_action_type( priority_aggregation, PRIORITY_ACTION_REMOVE );
_Priority_Actions_add( priority_actions, priority_aggregation );
@@ -107,7 +122,7 @@ static void _Thread_Priority_do_perform_actions(
&queue_context->Priority.Actions,
_Thread_Priority_action_add,
_Thread_Priority_action_change,
- NULL
+ the_thread
);
#else
_Priority_Non_empty_insert(
@@ -157,6 +172,7 @@ static void _Thread_Priority_do_perform_actions(
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
@@ -169,29 +185,27 @@ void _Thread_Priority_perform_actions(
Thread_queue_Context *queue_context
)
{
-#if defined(RTEMS_SMP)
- Thread_queue_Link *link;
-#endif
- Thread_Control *the_thread;
- size_t update_count;
+ Thread_Control *the_thread;
+ size_t update_count;
_Assert( start_of_path != NULL );
-#if defined(RTEMS_SMP)
- link = &queue_context->Path.Start;
-#endif
+ /*
+ * This function is tricky on SMP configurations. Please note that we do not
+ * use the thread queue path available via the thread queue context. Instead
+ * we directly use the thread wait information to traverse the thread queue
+ * path. Thus, we do not necessarily acquire all thread queue locks on our
+ * own. In case of a deadlock, we use locks acquired by other processors
+ * along the path.
+ */
+
the_thread = start_of_path;
update_count = _Thread_queue_Context_save_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,
@@ -209,10 +223,6 @@ void _Thread_Priority_perform_actions(
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
-
/*
* In case the priority action list is non-empty, then the current thread
* is enqueued on a thread queue. There is no need to notify the scheduler
@@ -255,9 +265,13 @@ static void _Thread_Priority_apply(
);
if ( !_Priority_Actions_is_empty( &queue_context->Priority.Actions ) ) {
+#if defined(RTEMS_SMP)
_Thread_queue_Path_acquire_critical( queue, the_thread, queue_context );
+#endif
_Thread_Priority_perform_actions( queue->owner, queue_context );
+#if defined(RTEMS_SMP)
_Thread_queue_Path_release_critical( queue_context );
+#endif
}
}
diff --git a/cpukit/score/src/threadqenqueue.c b/cpukit/score/src/threadqenqueue.c
index 2864c0924a..362ce8f5e8 100644
--- a/cpukit/score/src/threadqenqueue.c
+++ b/cpukit/score/src/threadqenqueue.c
@@ -114,6 +114,9 @@ static bool _Thread_queue_Link_add(
Thread_queue_Queue *recursive_target;
ISR_lock_Context lock_context;
+ link->source = source;
+ link->target = target;
+
links = &_Thread_queue_Links;
recursive_target = target;
@@ -136,8 +139,6 @@ static bool _Thread_queue_Link_add(
}
}
- link->source = source;
- link->target = target;
_RBTree_Insert_inline(
&links->Links,
&link->Registry_node,
@@ -162,6 +163,9 @@ static void _Thread_queue_Link_remove( Thread_queue_Link *link )
}
#endif
+#if !defined(RTEMS_SMP)
+static
+#endif
void _Thread_queue_Path_release_critical(
Thread_queue_Context *queue_context
)
@@ -173,51 +177,80 @@ void _Thread_queue_Path_release_critical(
head = _Chain_Head( &queue_context->Path.Links );
node = _Chain_Last( &queue_context->Path.Links );
- if ( head != node ) {
+ while ( head != node ) {
Thread_queue_Link *link;
- /*
- * The terminal link may have an owner which does not wait on a thread
- * queue.
- */
-
link = THREAD_QUEUE_LINK_OF_PATH_NODE( node );
- if ( link->Lock_context.Wait.queue == NULL ) {
- _Thread_Wait_release_default_critical(
- link->owner,
- &link->Lock_context.Lock_context
- );
-
- node = _Chain_Previous( node );
-#if defined(RTEMS_DEBUG)
- _Chain_Set_off_chain( &link->Path_node );
-#endif
- }
-
- while ( head != node ) {
- /* The other links have an owner which waits on a thread queue */
- link = THREAD_QUEUE_LINK_OF_PATH_NODE( node );
- _Assert( link->Lock_context.Wait.queue != NULL );
-
+ if ( link->Lock_context.Wait.queue != NULL ) {
_Thread_queue_Link_remove( link );
_Thread_Wait_release_queue_critical(
link->Lock_context.Wait.queue,
&link->Lock_context
);
_Thread_Wait_remove_request( link->owner, &link->Lock_context );
+ } else {
+ _Thread_Wait_release_default_critical(
+ link->owner,
+ &link->Lock_context.Lock_context
+ );
+ }
- node = _Chain_Previous( node );
+ node = _Chain_Previous( node );
#if defined(RTEMS_DEBUG)
- _Chain_Set_off_chain( &link->Path_node );
+ _Chain_Set_off_chain( &link->Path_node );
#endif
- }
}
#else
(void) queue_context;
#endif
}
+#if defined(RTEMS_SMP)
+static void _Thread_queue_Path_append_deadlock_thread(
+ Thread_Control *the_thread,
+ Thread_queue_Context *queue_context
+)
+{
+ Thread_Control *deadlock;
+
+ /*
+ * In case of a deadlock, we must obtain the thread wait default lock for the
+ * first thread on the path that tries to enqueue on a thread queue. This
+ * thread can be identified by the thread wait operations. This lock acquire
+ * is necessary for the timeout and explicit thread priority changes, see
+ * _Thread_Priority_perform_actions().
+ */
+
+ deadlock = NULL;
+
+ while ( the_thread->Wait.operations != &_Thread_queue_Operations_default ) {
+ the_thread = the_thread->Wait.queue->owner;
+ deadlock = the_thread;
+ }
+
+ if ( deadlock != NULL ) {
+ Thread_queue_Link *link;
+
+ link = &queue_context->Path.Deadlock;
+ _Chain_Initialize_node( &link->Path_node );
+ _Chain_Append_unprotected(
+ &queue_context->Path.Links,
+ &link->Path_node
+ );
+ link->owner = deadlock;
+ link->Lock_context.Wait.queue = NULL;
+ _Thread_Wait_acquire_default_critical(
+ deadlock,
+ &link->Lock_context.Lock_context
+ );
+ }
+}
+#endif
+
+#if !defined(RTEMS_SMP)
+static
+#endif
bool _Thread_queue_Path_acquire_critical(
Thread_queue_Queue *queue,
Thread_Control *the_thread,
@@ -249,12 +282,12 @@ bool _Thread_queue_Path_acquire_critical(
return false;
}
- _RBTree_Initialize_node( &queue_context->Path.Start.Registry_node );
- _Chain_Initialize_node( &queue_context->Path.Start.Path_node );
_Chain_Initialize_node(
&queue_context->Path.Start.Lock_context.Wait.Gate.Node
);
link = &queue_context->Path.Start;
+ _RBTree_Initialize_node( &link->Registry_node );
+ _Chain_Initialize_node( &link->Path_node );
do {
_Chain_Append_unprotected( &queue_context->Path.Links, &link->Path_node );
@@ -293,6 +326,7 @@ bool _Thread_queue_Path_acquire_critical(
}
} else {
link->Lock_context.Wait.queue = NULL;
+ _Thread_queue_Path_append_deadlock_thread( owner, queue_context );
return false;
}
} else {
@@ -353,7 +387,7 @@ void _Thread_queue_Enqueue_critical(
}
#endif
- _Thread_Wait_claim( the_thread, queue, operations );
+ _Thread_Wait_claim( the_thread, queue );
if ( !_Thread_queue_Path_acquire_critical( queue, the_thread, queue_context ) ) {
_Thread_queue_Path_release_critical( queue_context );
@@ -365,6 +399,7 @@ void _Thread_queue_Enqueue_critical(
}
_Thread_queue_Context_clear_priority_updates( queue_context );
+ _Thread_Wait_claim_finalize( the_thread, operations );
( *operations->enqueue )( queue, the_thread, queue_context );
_Thread_queue_Path_release_critical( queue_context );
diff --git a/cpukit/score/src/threadqops.c b/cpukit/score/src/threadqops.c
index 602d6bbffb..f212f25154 100644
--- a/cpukit/score/src/threadqops.c
+++ b/cpukit/score/src/threadqops.c
@@ -256,8 +256,7 @@ static Thread_Control *_Thread_queue_FIFO_surrender(
return first;
}
-static Thread_queue_Priority_queue *_Thread_queue_Priority_queue(
- Thread_queue_Heads *heads,
+static size_t _Thread_queue_Scheduler_index(
const Scheduler_Node *scheduler_node
)
{
@@ -265,13 +264,76 @@ static Thread_queue_Priority_queue *_Thread_queue_Priority_queue(
const Scheduler_Control *scheduler;
scheduler = _Priority_Get_scheduler( &scheduler_node->Wait.Priority );
- return &heads->Priority[ _Scheduler_Get_index( scheduler ) ];
+ return _Scheduler_Get_index( scheduler );
#else
(void) scheduler_node;
+ return 0;
+#endif
+}
+
+static Thread_queue_Priority_queue *_Thread_queue_Priority_queue_by_index(
+ Thread_queue_Heads *heads,
+ size_t scheduler_index
+)
+{
+#if defined(RTEMS_SMP)
+ return &heads->Priority[ scheduler_index ];
+#else
+ (void) scheduler_index;
return &heads->Heads.Priority;
#endif
}
+static Thread_queue_Priority_queue *_Thread_queue_Priority_queue(
+ Thread_queue_Heads *heads,
+ const Scheduler_Node *scheduler_node
+)
+{
+ return _Thread_queue_Priority_queue_by_index(
+ heads,
+ _Thread_queue_Scheduler_index( scheduler_node )
+ );
+}
+
+static Chain_Node *_Thread_queue_Priority_queue_rotation(
+ Thread_queue_Heads *heads
+)
+{
+ Chain_Node *fifo_node;
+
+#if defined(RTEMS_SMP)
+ /* Ensure FIFO order with respect to the priority queues */
+ fifo_node = _Chain_First( &heads->Heads.Fifo );
+ _Chain_Extract_unprotected( fifo_node );
+ _Chain_Append_unprotected( &heads->Heads.Fifo, fifo_node );
+#else
+ (void) heads;
+ fifo_node = NULL;
+#endif
+
+ return fifo_node;
+}
+
+#if defined(RTEMS_SMP)
+static void _Thread_queue_Priority_queue_extract(
+ Priority_Aggregation *priority_aggregation,
+ Priority_Actions *priority_actions,
+ void *arg
+)
+{
+ Thread_queue_Priority_queue *priority_queue;
+
+ (void) priority_actions;
+ (void) arg;
+
+ priority_queue = THREAD_QUEUE_PRIORITY_QUEUE_OF_PRIORITY_AGGREGATION(
+ priority_aggregation
+ );
+
+ _Chain_Extract_unprotected( &priority_queue->Node );
+}
+#endif
+
static void _Thread_queue_Priority_priority_actions(
Thread_queue_Queue *queue,
Priority_Actions *priority_actions
@@ -289,15 +351,36 @@ static void _Thread_queue_Priority_priority_actions(
do {
Scheduler_Node *scheduler_node;
Thread_queue_Priority_queue *priority_queue;
+ Priority_Action_type priority_action_type;
scheduler_node = SCHEDULER_NODE_OF_WAIT_PRIORITY( priority_aggregation );
priority_queue = _Thread_queue_Priority_queue( heads, scheduler_node );
+ priority_action_type = priority_aggregation->Action.type;
- _Assert( priority_aggregation->Action.type == PRIORITY_ACTION_CHANGE );
- _Priority_Plain_changed(
- &priority_queue->Queue,
- &scheduler_node->Wait.Priority.Node
- );
+ switch ( priority_action_type ) {
+#if defined(RTEMS_SMP)
+ case PRIORITY_ACTION_ADD:
+ _Priority_Plain_insert(
+ &priority_queue->Queue,
+ &scheduler_node->Wait.Priority.Node,
+ _Priority_Get_priority( &scheduler_node->Wait.Priority )
+ );
+ break;
+ case PRIORITY_ACTION_REMOVE:
+ _Priority_Plain_extract(
+ &priority_queue->Queue,
+ &scheduler_node->Wait.Priority.Node
+ );
+ break;
+#endif
+ default:
+ _Assert( priority_action_type == PRIORITY_ACTION_CHANGE );
+ _Priority_Plain_changed(
+ &priority_queue->Queue,
+ &scheduler_node->Wait.Priority.Node
+ );
+ break;
+ }
priority_aggregation = _Priority_Get_next_action( priority_aggregation );
} while ( _Priority_Actions_is_valid( priority_aggregation ) );
@@ -312,18 +395,38 @@ static void _Thread_queue_Priority_do_initialize(
{
Scheduler_Node *scheduler_node;
Thread_queue_Priority_queue *priority_queue;
-
- scheduler_node = _Thread_Scheduler_get_own_node( the_thread );
- priority_queue = _Thread_queue_Priority_queue( heads, scheduler_node );
-
#if defined(RTEMS_SMP)
- _Chain_Initialize_one( &heads->Heads.Fifo, &priority_queue->Node );
+ Chain_Node *wait_node;
+ const Chain_Node *wait_tail;
#endif
+ scheduler_node = _Thread_Scheduler_get_home_node( the_thread );
+ priority_queue = _Thread_queue_Priority_queue( heads, scheduler_node );
+
_Priority_Initialize_one(
&priority_queue->Queue,
&scheduler_node->Wait.Priority.Node
);
+
+#if defined(RTEMS_SMP)
+ _Chain_Initialize_one( &heads->Heads.Fifo, &priority_queue->Node );
+
+ wait_node = _Chain_Next( &scheduler_node->Thread.Wait_node );
+ wait_tail = _Chain_Immutable_tail( &the_thread->Scheduler.Wait_nodes );
+
+ while ( wait_node != wait_tail ) {
+ scheduler_node = SCHEDULER_NODE_OF_THREAD_WAIT_NODE( wait_node );
+ priority_queue = _Thread_queue_Priority_queue( heads, scheduler_node );
+
+ _Priority_Initialize_one(
+ &priority_queue->Queue,
+ &scheduler_node->Wait.Priority.Node
+ );
+ _Chain_Append_unprotected( &heads->Heads.Fifo, &priority_queue->Node );
+
+ wait_node = _Chain_Next( &scheduler_node->Thread.Wait_node );
+ }
+#endif
}
static void _Thread_queue_Priority_do_enqueue(
@@ -333,28 +436,49 @@ static void _Thread_queue_Priority_do_enqueue(
Thread_queue_Heads *heads
)
{
+#if defined(RTEMS_SMP)
+ Chain_Node *wait_node;
+ const Chain_Node *wait_tail;
+
+ wait_node = _Chain_First( &the_thread->Scheduler.Wait_nodes );
+ wait_tail = _Chain_Immutable_tail( &the_thread->Scheduler.Wait_nodes );
+
+ do {
+ Scheduler_Node *scheduler_node;
+ Thread_queue_Priority_queue *priority_queue;
+
+ scheduler_node = SCHEDULER_NODE_OF_THREAD_WAIT_NODE( wait_node );
+ priority_queue = _Thread_queue_Priority_queue( heads, scheduler_node );
+
+ if ( _Priority_Is_empty( &priority_queue->Queue ) ) {
+ _Chain_Append_unprotected( &heads->Heads.Fifo, &priority_queue->Node );
+ _Priority_Initialize_one(
+ &priority_queue->Queue,
+ &scheduler_node->Wait.Priority.Node
+ );
+ } else {
+ _Priority_Plain_insert(
+ &priority_queue->Queue,
+ &scheduler_node->Wait.Priority.Node,
+ _Priority_Get_priority( &scheduler_node->Wait.Priority )
+ );
+ }
+
+ wait_node = _Chain_Next( &scheduler_node->Thread.Wait_node );
+ } while ( wait_node != wait_tail );
+#else
Scheduler_Node *scheduler_node;
Thread_queue_Priority_queue *priority_queue;
- scheduler_node = _Thread_Scheduler_get_own_node( the_thread );
+ scheduler_node = _Thread_Scheduler_get_home_node( the_thread );
priority_queue = _Thread_queue_Priority_queue( heads, scheduler_node );
-#if defined(RTEMS_SMP)
- if ( _Priority_Is_empty( &priority_queue->Queue ) ) {
- _Chain_Append_unprotected( &heads->Heads.Fifo, &priority_queue->Node );
- _Priority_Initialize_one(
- &priority_queue->Queue,
- &scheduler_node->Wait.Priority.Node
- );
- return;
- }
-#endif
-
_Priority_Plain_insert(
&priority_queue->Queue,
&scheduler_node->Wait.Priority.Node,
_Priority_Get_priority( &scheduler_node->Wait.Priority )
);
+#endif
}
static void _Thread_queue_Priority_do_extract(
@@ -365,27 +489,64 @@ static void _Thread_queue_Priority_do_extract(
Thread_Control *the_thread
)
{
+#if defined(RTEMS_SMP)
+ Chain_Node *wait_node;
+ const Chain_Node *wait_tail;
+
+ wait_node = _Chain_First( &the_thread->Scheduler.Wait_nodes );
+ wait_tail = _Chain_Immutable_tail( &the_thread->Scheduler.Wait_nodes );
+
+ do {
+ Scheduler_Node *scheduler_node;
+ Thread_queue_Priority_queue *priority_queue;
+
+ scheduler_node = SCHEDULER_NODE_OF_THREAD_WAIT_NODE( wait_node );
+ priority_queue = _Thread_queue_Priority_queue( heads, scheduler_node );
+
+ _Priority_Plain_extract(
+ &priority_queue->Queue,
+ &scheduler_node->Wait.Priority.Node
+ );
+
+ if ( _Priority_Is_empty( &priority_queue->Queue ) ) {
+ _Chain_Extract_unprotected( &priority_queue->Node );
+ }
+
+ wait_node = _Chain_Next( &scheduler_node->Thread.Wait_node );
+ } while ( wait_node != wait_tail );
+#else
Scheduler_Node *scheduler_node;
Thread_queue_Priority_queue *priority_queue;
- (void) current_or_previous_owner;
- (void) queue_context;
-
- scheduler_node = _Thread_Scheduler_get_own_node( the_thread );
+ scheduler_node = _Thread_Scheduler_get_home_node( the_thread );
priority_queue = _Thread_queue_Priority_queue( heads, scheduler_node );
_Priority_Plain_extract(
&priority_queue->Queue,
&scheduler_node->Wait.Priority.Node
);
+#endif
-#if defined(RTEMS_SMP)
- _Chain_Extract_unprotected( &priority_queue->Node );
+ (void) current_or_previous_owner;
+ (void) queue_context;
+}
- if ( !_Priority_Is_empty( &priority_queue->Queue ) ) {
- _Chain_Append_unprotected( &heads->Heads.Fifo, &priority_queue->Node );
- }
-#endif
+static void _Thread_queue_Priority_do_surrender(
+ Thread_queue_Queue *queue,
+ Thread_queue_Heads *heads,
+ Thread_Control *current_or_previous_owner,
+ Thread_queue_Context *queue_context,
+ Thread_Control *the_thread
+)
+{
+ _Thread_queue_Priority_queue_rotation( heads );
+ _Thread_queue_Priority_do_extract(
+ queue,
+ heads,
+ current_or_previous_owner,
+ queue_context,
+ the_thread
+ );
}
static void _Thread_queue_Priority_enqueue(
@@ -458,33 +619,78 @@ static Thread_Control *_Thread_queue_Priority_surrender(
NULL,
queue_context,
first,
- _Thread_queue_Priority_do_extract
+ _Thread_queue_Priority_do_surrender
);
return first;
}
-static void _Thread_queue_Priority_inherit_do_actions_change(
+static void _Thread_queue_Priority_inherit_do_priority_actions_action(
+ Priority_Aggregation *priority_aggregation,
+ Priority_Actions *priority_actions,
+ Scheduler_Node *scheduler_node_of_owner,
+ Priority_Action_type priority_action_type
+)
+{
+ _Priority_Set_action(
+ &scheduler_node_of_owner->Wait.Priority,
+ &priority_aggregation->Node,
+ priority_action_type
+ );
+ _Priority_Actions_add(
+ priority_actions,
+ &scheduler_node_of_owner->Wait.Priority
+ );
+}
+
+#if defined(RTEMS_SMP)
+static void _Thread_queue_Priority_inherit_do_priority_actions_add(
Priority_Aggregation *priority_aggregation,
- bool prepend_it,
Priority_Actions *priority_actions,
void *arg
)
{
- Thread_queue_Priority_queue *priority_queue;
- Scheduler_Node *scheduler_node;
+ _Thread_queue_Priority_inherit_do_priority_actions_action(
+ priority_aggregation,
+ priority_actions,
+ arg,
+ PRIORITY_ACTION_ADD
+ );
+}
- priority_queue = THREAD_QUEUE_PRIORITY_QUEUE_OF_PRIORITY_AGGREGATION(
- priority_aggregation
+static void _Thread_queue_Priority_inherit_do_priority_actions_remove(
+ Priority_Aggregation *priority_aggregation,
+ Priority_Actions *priority_actions,
+ void *arg
+)
+{
+ _Thread_queue_Priority_queue_extract(
+ priority_aggregation,
+ priority_actions,
+ arg
);
- scheduler_node = priority_queue->scheduler_node;
+ _Thread_queue_Priority_inherit_do_priority_actions_action(
+ priority_aggregation,
+ priority_actions,
+ arg,
+ PRIORITY_ACTION_REMOVE
+ );
+}
+#endif
- _Priority_Set_action(
- &scheduler_node->Wait.Priority,
- &priority_aggregation->Node,
+static void _Thread_queue_Priority_inherit_do_priority_actions_change(
+ Priority_Aggregation *priority_aggregation,
+ bool prepend_it,
+ Priority_Actions *priority_actions,
+ void *arg
+)
+{
+ _Thread_queue_Priority_inherit_do_priority_actions_action(
+ priority_aggregation,
+ priority_actions,
+ arg,
PRIORITY_ACTION_CHANGE
);
- _Priority_Actions_add( priority_actions, &scheduler_node->Wait.Priority );
}
static void _Thread_queue_Priority_inherit_priority_actions(
@@ -493,83 +699,84 @@ static void _Thread_queue_Priority_inherit_priority_actions(
)
{
Thread_queue_Heads *heads;
+ Thread_Control *owner;
Priority_Aggregation *priority_aggregation;
heads = queue->heads;
_Assert( heads != NULL );
+ owner = queue->owner;
+ _Assert( owner != NULL );
+
_Assert( !_Priority_Actions_is_empty( priority_actions ) );
priority_aggregation = _Priority_Actions_move( priority_actions );
do {
Priority_Aggregation *next_aggregation;
Scheduler_Node *scheduler_node;
+ size_t scheduler_index;
Thread_queue_Priority_queue *priority_queue;
+ Scheduler_Node *scheduler_node_of_owner;
+ Priority_Action_type priority_action_type;
next_aggregation = _Priority_Get_next_action( priority_aggregation );
scheduler_node = SCHEDULER_NODE_OF_WAIT_PRIORITY( priority_aggregation );
- priority_queue = _Thread_queue_Priority_queue( heads, scheduler_node );
-
- _Assert( priority_aggregation->Action.type == PRIORITY_ACTION_CHANGE );
- _Priority_Changed(
- &priority_queue->Queue,
- &scheduler_node->Wait.Priority.Node,
- false,
- priority_actions,
- _Thread_queue_Priority_inherit_do_actions_change,
- NULL
+ scheduler_index = _Thread_queue_Scheduler_index( scheduler_node );
+ priority_queue = _Thread_queue_Priority_queue_by_index(
+ heads,
+ scheduler_index
);
+ scheduler_node_of_owner = _Thread_Scheduler_get_node_by_index(
+ owner,
+ scheduler_index
+ );
+ priority_action_type = priority_aggregation->Action.type;
- priority_aggregation = next_aggregation;
- } while ( _Priority_Actions_is_valid( priority_aggregation ) );
-}
-
-static void _Thread_queue_Boost_priority(
- Thread_queue_Heads *heads,
- Thread_Control *the_thread,
- Thread_Control *owner,
- Thread_queue_Context *queue_context
-)
-{
+ switch ( priority_action_type ) {
#if defined(RTEMS_SMP)
- const Scheduler_Control *scheduler;
- const Scheduler_Control *scheduler_of_owner;
- Scheduler_Node *scheduler_node_of_owner;
- Priority_Control boost_priority;
-
- if ( _Priority_Node_is_active( &heads->Boost_priority ) ) {
- return;
- }
-
- scheduler = _Scheduler_Get_own( the_thread );
- scheduler_of_owner = _Scheduler_Get_own( owner );
-
- if ( scheduler == scheduler_of_owner ) {
- return;
- }
-
- scheduler_node_of_owner = _Thread_Scheduler_get_own_node( owner );
-
- boost_priority = _Scheduler_Map_priority(
- scheduler_of_owner,
- PRIORITY_PSEUDO_ISR
- );
-
- _Priority_Node_initialize( &heads->Boost_priority, boost_priority );
- _Priority_Actions_initialize_one(
- &queue_context->Priority.Actions,
- &scheduler_node_of_owner->Wait.Priority,
- &heads->Boost_priority,
- PRIORITY_ACTION_ADD
- );
- _Thread_Priority_perform_actions( owner, queue_context );
-#else
- (void) heads;
- (void) the_thread;
- (void) owner;
- (void) queue_context;
+ case PRIORITY_ACTION_ADD:
+ if ( _Priority_Is_empty( &priority_queue->Queue ) ) {
+ _Chain_Append_unprotected( &heads->Heads.Fifo, &priority_queue->Node );
+ priority_queue->scheduler_node = scheduler_node_of_owner;
+ }
+
+ _Priority_Insert(
+ &priority_queue->Queue,
+ &scheduler_node->Wait.Priority.Node,
+ priority_actions,
+ _Thread_queue_Priority_inherit_do_priority_actions_add,
+ _Thread_queue_Priority_inherit_do_priority_actions_change,
+ scheduler_node_of_owner
+ );
+ break;
+ case PRIORITY_ACTION_REMOVE:
+ _Priority_Extract(
+ &priority_queue->Queue,
+ &scheduler_node->Wait.Priority.Node,
+ priority_actions,
+ _Thread_queue_Priority_inherit_do_priority_actions_remove,
+ _Thread_queue_Priority_inherit_do_priority_actions_change,
+ scheduler_node_of_owner
+ );
+
+ break;
#endif
+ default:
+ _Assert( priority_action_type == PRIORITY_ACTION_CHANGE );
+ _Priority_Changed(
+ &priority_queue->Queue,
+ &scheduler_node->Wait.Priority.Node,
+ false,
+ priority_actions,
+ _Thread_queue_Priority_inherit_do_priority_actions_change,
+ scheduler_node_of_owner
+ );
+ break;
+ }
+
+ priority_aggregation = next_aggregation;
+ } while ( _Priority_Actions_is_valid( priority_aggregation ) );
}
static void _Thread_queue_Priority_inherit_do_initialize(
@@ -580,34 +787,79 @@ static void _Thread_queue_Priority_inherit_do_initialize(
)
{
Scheduler_Node *scheduler_node;
+ size_t scheduler_index;
Thread_queue_Priority_queue *priority_queue;
Thread_Control *owner;
Scheduler_Node *scheduler_node_of_owner;
-
- scheduler_node = _Thread_Scheduler_get_own_node( the_thread );
- priority_queue = _Thread_queue_Priority_queue( heads, scheduler_node );
-
#if defined(RTEMS_SMP)
- _Chain_Initialize_one( &heads->Heads.Fifo, &priority_queue->Node );
+ Chain_Node *wait_node;
+ const Chain_Node *wait_tail;
#endif
+ owner = queue->owner;
+
+ scheduler_node = _Thread_Scheduler_get_home_node( the_thread );
+ scheduler_index = _Thread_queue_Scheduler_index( scheduler_node );
+ priority_queue = _Thread_queue_Priority_queue_by_index(
+ heads,
+ scheduler_index
+ );
+ scheduler_node_of_owner = _Thread_Scheduler_get_node_by_index(
+ owner,
+ scheduler_index
+ );
+
+ priority_queue->scheduler_node = scheduler_node_of_owner;
_Priority_Initialize_one(
&priority_queue->Queue,
&scheduler_node->Wait.Priority.Node
);
-
- owner = queue->owner;
- scheduler_node_of_owner = _Thread_Scheduler_get_own_node( owner );
- priority_queue->scheduler_node = scheduler_node_of_owner;
-
_Priority_Actions_initialize_one(
&queue_context->Priority.Actions,
&scheduler_node_of_owner->Wait.Priority,
&priority_queue->Queue.Node,
PRIORITY_ACTION_ADD
);
+
+#if defined(RTEMS_SMP)
+ _Chain_Initialize_one( &heads->Heads.Fifo, &priority_queue->Node );
+
+ wait_node = _Chain_Next( &scheduler_node->Thread.Wait_node );
+ wait_tail = _Chain_Immutable_tail( &the_thread->Scheduler.Wait_nodes );
+
+ while ( wait_node != wait_tail ) {
+ scheduler_node = SCHEDULER_NODE_OF_THREAD_WAIT_NODE( wait_node );
+ scheduler_index = _Thread_queue_Scheduler_index( scheduler_node );
+ priority_queue = _Thread_queue_Priority_queue_by_index(
+ heads,
+ scheduler_index
+ );
+ scheduler_node_of_owner = _Thread_Scheduler_get_node_by_index(
+ owner,
+ scheduler_index
+ );
+
+ _Chain_Append_unprotected( &heads->Heads.Fifo, &priority_queue->Node );
+ priority_queue->scheduler_node = scheduler_node_of_owner;
+ _Priority_Initialize_one(
+ &priority_queue->Queue,
+ &scheduler_node->Wait.Priority.Node
+ );
+ _Priority_Set_action(
+ &scheduler_node_of_owner->Wait.Priority,
+ &priority_queue->Queue.Node,
+ PRIORITY_ACTION_ADD
+ );
+ _Priority_Actions_add(
+ &queue_context->Priority.Actions,
+ &scheduler_node_of_owner->Wait.Priority
+ );
+
+ wait_node = _Chain_Next( &scheduler_node->Thread.Wait_node );
+ }
+#endif
+
_Thread_Priority_perform_actions( owner, queue_context );
- _Thread_queue_Boost_priority( heads, the_thread, owner, queue_context );
}
static void _Thread_queue_Priority_inherit_do_enqueue_change(
@@ -617,6 +869,21 @@ static void _Thread_queue_Priority_inherit_do_enqueue_change(
void *arg
)
{
+#if defined(RTEMS_SMP)
+ Scheduler_Node *scheduler_node_of_owner;
+
+ scheduler_node_of_owner = arg;
+
+ _Priority_Set_action(
+ &scheduler_node_of_owner->Wait.Priority,
+ &priority_aggregation->Node,
+ PRIORITY_ACTION_CHANGE
+ );
+ _Priority_Actions_add(
+ priority_actions,
+ &scheduler_node_of_owner->Wait.Priority
+ );
+#else
Thread_queue_Queue *queue;
Thread_Control *owner;
Scheduler_Node *scheduler_node_of_owner;
@@ -634,6 +901,7 @@ static void _Thread_queue_Priority_inherit_do_enqueue_change(
PRIORITY_ACTION_CHANGE
);
_Thread_Priority_perform_actions( owner, queue_context );
+#endif
}
static void _Thread_queue_Priority_inherit_do_enqueue(
@@ -643,38 +911,72 @@ static void _Thread_queue_Priority_inherit_do_enqueue(
Thread_queue_Heads *heads
)
{
- Scheduler_Node *scheduler_node;
- Thread_queue_Priority_queue *priority_queue;
-
- scheduler_node = _Thread_Scheduler_get_own_node( the_thread );
- priority_queue = _Thread_queue_Priority_queue( heads, scheduler_node );
-
#if defined(RTEMS_SMP)
- if ( _Priority_Is_empty( &priority_queue->Queue ) ) {
- Thread_Control *owner;
- Scheduler_Node *scheduler_node_of_owner;
+ Thread_Control *owner;
+ Chain_Node *wait_node;
+ const Chain_Node *wait_tail;
- _Chain_Append_unprotected( &heads->Heads.Fifo, &priority_queue->Node );
- _Priority_Initialize_one(
- &priority_queue->Queue,
- &scheduler_node->Wait.Priority.Node
- );
+ owner = queue->owner;
+ wait_node = _Chain_First( &the_thread->Scheduler.Wait_nodes );
+ wait_tail = _Chain_Immutable_tail( &the_thread->Scheduler.Wait_nodes );
- owner = queue->owner;
- scheduler_node_of_owner = _Thread_Scheduler_get_own_node( owner );
- priority_queue->scheduler_node = scheduler_node_of_owner;
+ _Priority_Actions_initialize_empty( &queue_context->Priority.Actions );
- _Priority_Actions_initialize_one(
- &queue_context->Priority.Actions,
- &scheduler_node_of_owner->Wait.Priority,
- &priority_queue->Queue.Node,
- PRIORITY_ACTION_ADD
+ do {
+ Scheduler_Node *scheduler_node;
+ size_t scheduler_index;
+ Thread_queue_Priority_queue *priority_queue;
+ Scheduler_Node *scheduler_node_of_owner;
+
+ scheduler_node = SCHEDULER_NODE_OF_THREAD_WAIT_NODE( wait_node );
+ scheduler_index = _Thread_queue_Scheduler_index( scheduler_node );
+ priority_queue = _Thread_queue_Priority_queue_by_index(
+ heads,
+ scheduler_index
+ );
+ scheduler_node_of_owner = _Thread_Scheduler_get_node_by_index(
+ owner,
+ scheduler_index
);
+
+ if ( _Priority_Is_empty( &priority_queue->Queue ) ) {
+ _Chain_Append_unprotected( &heads->Heads.Fifo, &priority_queue->Node );
+ priority_queue->scheduler_node = scheduler_node_of_owner;
+ _Priority_Initialize_one(
+ &priority_queue->Queue,
+ &scheduler_node->Wait.Priority.Node
+ );
+ _Priority_Set_action(
+ &scheduler_node_of_owner->Wait.Priority,
+ &priority_queue->Queue.Node,
+ PRIORITY_ACTION_ADD
+ );
+ _Priority_Actions_add(
+ &queue_context->Priority.Actions,
+ &scheduler_node_of_owner->Wait.Priority
+ );
+ } else {
+ _Priority_Non_empty_insert(
+ &priority_queue->Queue,
+ &scheduler_node->Wait.Priority.Node,
+ &queue_context->Priority.Actions,
+ _Thread_queue_Priority_inherit_do_enqueue_change,
+ scheduler_node_of_owner
+ );
+ }
+
+ wait_node = _Chain_Next( &scheduler_node->Thread.Wait_node );
+ } while ( wait_node != wait_tail );
+
+ if ( !_Priority_Actions_is_empty( &queue_context->Priority.Actions ) ) {
_Thread_Priority_perform_actions( owner, queue_context );
- _Thread_queue_Boost_priority( heads, the_thread, owner, queue_context );
- return;
}
-#endif
+#else
+ Scheduler_Node *scheduler_node;
+ Thread_queue_Priority_queue *priority_queue;
+
+ scheduler_node = _Thread_Scheduler_get_home_node( the_thread );
+ priority_queue = _Thread_queue_Priority_queue( heads, scheduler_node );
_Priority_Non_empty_insert(
&priority_queue->Queue,
@@ -683,12 +985,7 @@ static void _Thread_queue_Priority_inherit_do_enqueue(
_Thread_queue_Priority_inherit_do_enqueue_change,
queue
);
- _Thread_queue_Boost_priority(
- heads,
- the_thread,
- queue->owner,
- queue_context
- );
+#endif
}
static void _Thread_queue_Priority_inherit_enqueue(
@@ -708,24 +1005,42 @@ static void _Thread_queue_Priority_inherit_enqueue(
static void _Thread_queue_Priority_inherit_do_extract_action(
Priority_Actions *priority_actions,
- Thread_Control *owner,
- Priority_Node *priority_action_node,
+ void *arg,
+ Priority_Aggregation *priority_aggregation,
Priority_Action_type priority_action_type
)
{
+#if defined(RTEMS_SMP)
+ Scheduler_Node *scheduler_node_of_owner;
+
+ scheduler_node_of_owner = arg;
+
+ _Priority_Set_action(
+ &scheduler_node_of_owner->Wait.Priority,
+ &priority_aggregation->Node,
+ priority_action_type
+ );
+ _Priority_Actions_add(
+ priority_actions,
+ &scheduler_node_of_owner->Wait.Priority
+ );
+#else
Thread_queue_Context *queue_context;
+ Thread_Control *owner;
Scheduler_Node *scheduler_node_of_owner;
queue_context = THREAD_QUEUE_CONTEXT_OF_PRIORITY_ACTIONS( priority_actions );
- scheduler_node_of_owner = _Thread_Scheduler_get_own_node( owner );
+ owner = arg;
+ scheduler_node_of_owner = _Thread_Scheduler_get_home_node( owner );
_Priority_Actions_initialize_one(
&queue_context->Priority.Actions,
&scheduler_node_of_owner->Wait.Priority,
- priority_action_node,
+ &priority_aggregation->Node,
priority_action_type
);
- _Thread_Priority_perform_actions( owner, queue_context );
+ _Thread_Priority_perform_actions( arg, queue_context );
+#endif
}
static void _Thread_queue_Priority_inherit_do_extract_remove(
@@ -737,7 +1052,7 @@ static void _Thread_queue_Priority_inherit_do_extract_remove(
_Thread_queue_Priority_inherit_do_extract_action(
priority_actions,
arg,
- &priority_aggregation->Node,
+ priority_aggregation,
PRIORITY_ACTION_REMOVE
);
}
@@ -752,7 +1067,7 @@ static void _Thread_queue_Priority_inherit_do_extract_change(
_Thread_queue_Priority_inherit_do_extract_action(
priority_actions,
arg,
- &priority_aggregation->Node,
+ priority_aggregation,
PRIORITY_ACTION_CHANGE
);
}
@@ -765,13 +1080,56 @@ static void _Thread_queue_Priority_inherit_do_extract(
Thread_Control *the_thread
)
{
+#if defined(RTEMS_SMP)
+ Chain_Node *wait_node;
+ const Chain_Node *wait_tail;
+#endif
Scheduler_Node *scheduler_node;
Thread_queue_Priority_queue *priority_queue;
- scheduler_node = _Thread_Scheduler_get_own_node( the_thread );
- priority_queue = _Thread_queue_Priority_queue( heads, scheduler_node );
+#if defined(RTEMS_SMP)
+ wait_node = _Chain_First( &the_thread->Scheduler.Wait_nodes );
+ wait_tail = _Chain_Immutable_tail( &the_thread->Scheduler.Wait_nodes );
- _Thread_queue_Path_acquire_critical( queue, the_thread, queue_context );
+ _Priority_Actions_initialize_empty( &queue_context->Priority.Actions );
+
+ do {
+ size_t scheduler_index;
+ Scheduler_Node *scheduler_node_of_owner;
+
+ scheduler_node = SCHEDULER_NODE_OF_THREAD_WAIT_NODE( wait_node );
+ scheduler_index = _Thread_queue_Scheduler_index( scheduler_node );
+ priority_queue = _Thread_queue_Priority_queue_by_index(
+ heads,
+ scheduler_index
+ );
+ scheduler_node_of_owner = _Thread_Scheduler_get_node_by_index(
+ owner,
+ scheduler_index
+ );
+
+ _Priority_Extract(
+ &priority_queue->Queue,
+ &scheduler_node->Wait.Priority.Node,
+ &queue_context->Priority.Actions,
+ _Thread_queue_Priority_inherit_do_extract_remove,
+ _Thread_queue_Priority_inherit_do_extract_change,
+ scheduler_node_of_owner
+ );
+
+ if ( _Priority_Is_empty( &priority_queue->Queue ) ) {
+ _Chain_Extract_unprotected( &priority_queue->Node );
+ }
+
+ wait_node = _Chain_Next( &scheduler_node->Thread.Wait_node );
+ } while ( wait_node != wait_tail );
+
+ if ( !_Priority_Actions_is_empty( &queue_context->Priority.Actions ) ) {
+ _Thread_Priority_perform_actions( owner, queue_context );
+ }
+#else
+ scheduler_node = _Thread_Scheduler_get_home_node( the_thread );
+ priority_queue = _Thread_queue_Priority_queue( heads, scheduler_node );
_Priority_Extract(
&priority_queue->Queue,
@@ -781,30 +1139,7 @@ static void _Thread_queue_Priority_inherit_do_extract(
_Thread_queue_Priority_inherit_do_extract_change,
owner
);
-
-#if defined(RTEMS_SMP)
- _Chain_Extract_unprotected( &priority_queue->Node );
-
- if ( !_Priority_Is_empty( &priority_queue->Queue ) ) {
- _Chain_Append_unprotected( &heads->Heads.Fifo, &priority_queue->Node );
- }
-
- if (
- _Priority_Node_is_active( &heads->Boost_priority )
- && ( _Chain_Is_empty( &heads->Heads.Fifo )
- || _Chain_Has_only_one_node( &heads->Heads.Fifo ) )
- ) {
- _Thread_queue_Priority_inherit_do_extract_action(
- &queue_context->Priority.Actions,
- owner,
- &heads->Boost_priority,
- PRIORITY_ACTION_REMOVE
- );
- _Priority_Node_set_inactive( &heads->Boost_priority );
- }
#endif
-
- _Thread_queue_Path_release_critical( queue_context );
}
static void _Thread_queue_Priority_inherit_extract(
@@ -813,6 +1148,38 @@ static void _Thread_queue_Priority_inherit_extract(
Thread_queue_Context *queue_context
)
{
+#if defined(RTEMS_SMP)
+ /*
+ * We must lock the thread wait path for the complete extract operation
+ * including the thread queue head management. Consider the following
+ * scenario on three processors. Thread T0 owns thread queue A, thread T1
+ * owns thread queue B and thread T2 owns thread queue C. Thread T0 waits
+ * for B and thread T1 waits for C.
+ *
+ * A <-------------------------\
+ * \ |
+ * > T0 -> B |
+ * \ |
+ * > T1 -> C |
+ * \ |
+ * > T2 -/
+ *
+ * Now three things happen at the same time
+ * - thread T0 times out,
+ * - thread T1 times out,
+ * - thread T2 tries to enqueue on a thread queue A.
+ *
+ * Thread T1 acquires thread queue lock C and waits for thread queue lock A.
+ * Thread T2 acquires thread queue lock A and waits for thread queue lock B.
+ * Thread T0 acquires thread queue lock B and detects a potential deadlock.
+ * Thread T0 carries out the thread queue extraction due to the timeout and
+ * uses the thread wait path segments acquired by thread T1 and T2. This
+ * resolves the deadlock. Thread T1 and T2 can the complete their
+ * operations.
+ */
+ _Thread_queue_Path_acquire_critical( queue, the_thread, queue_context );
+#endif
+
_Thread_queue_Queue_extract(
queue,
queue->heads,
@@ -821,8 +1188,51 @@ static void _Thread_queue_Priority_inherit_extract(
the_thread,
_Thread_queue_Priority_inherit_do_extract
);
+
+#if defined(RTEMS_SMP)
+ _Thread_queue_Path_release_critical( queue_context );
+#endif
+}
+
+#if defined(RTEMS_SMP)
+static void _Thread_queue_Priority_inherit_do_surrender_add(
+ Priority_Aggregation *priority_aggregation,
+ Priority_Actions *priority_actions,
+ void *arg
+)
+{
+ Scheduler_Node *scheduler_node;
+ Thread_Control *the_thread;
+
+ scheduler_node = SCHEDULER_NODE_OF_WAIT_PRIORITY( priority_aggregation );
+ the_thread = arg;
+
+ _Chain_Append_unprotected(
+ &the_thread->Scheduler.Wait_nodes,
+ &scheduler_node->Thread.Wait_node
+ );
+ _Scheduler_Node_set_priority(
+ scheduler_node,
+ _Priority_Get_priority( priority_aggregation ),
+ false
+ );
}
+static void _Thread_queue_Priority_inherit_do_surrender_remove(
+ Priority_Aggregation *priority_aggregation,
+ Priority_Actions *priority_actions,
+ void *arg
+)
+{
+ Scheduler_Node *scheduler_node;
+
+ scheduler_node = SCHEDULER_NODE_OF_WAIT_PRIORITY( priority_aggregation );
+
+ _Priority_Actions_add( priority_actions, priority_aggregation );
+ _Chain_Extract_unprotected( &scheduler_node->Thread.Wait_node );
+}
+#endif
+
static void _Thread_queue_Priority_inherit_do_surrender_change(
Priority_Aggregation *priority_aggregation,
bool prepend_it,
@@ -830,10 +1240,14 @@ static void _Thread_queue_Priority_inherit_do_surrender_change(
void *arg
)
{
+#if defined(RTEMS_SMP)
+ _Priority_Actions_add( priority_actions, priority_aggregation );
+#else
_Thread_queue_Context_add_priority_update(
THREAD_QUEUE_CONTEXT_OF_PRIORITY_ACTIONS( priority_actions ),
arg
);
+#endif
_Scheduler_Node_set_priority(
SCHEDULER_NODE_OF_WAIT_PRIORITY( priority_aggregation ),
_Priority_Get_priority( priority_aggregation ),
@@ -841,35 +1255,17 @@ static void _Thread_queue_Priority_inherit_do_surrender_change(
);
}
-static void _Thread_queue_Priority_add(
- Thread_Control *the_thread,
+static void _Thread_queue_Priority_inherit_do_surrender_change_2(
Priority_Aggregation *priority_aggregation,
- Priority_Node *priority_node,
- Thread_queue_Context *queue_context
-)
-{
- _Priority_Non_empty_insert(
- priority_aggregation,
- priority_node,
- &queue_context->Priority.Actions,
- _Thread_queue_Priority_inherit_do_surrender_change,
- the_thread
- );
-}
-
-static void _Thread_queue_Priority_remove(
- Thread_Control *the_thread,
- Scheduler_Node *scheduler_node,
- Priority_Node *priority_node,
- Thread_queue_Context *queue_context
+ bool prepend_it,
+ Priority_Actions *priority_actions,
+ void *arg
)
{
- _Priority_Extract_non_empty(
- &scheduler_node->Wait.Priority,
- priority_node,
- &queue_context->Priority.Actions,
- _Thread_queue_Priority_inherit_do_surrender_change,
- the_thread
+ _Scheduler_Node_set_priority(
+ SCHEDULER_NODE_OF_WAIT_PRIORITY( priority_aggregation ),
+ _Priority_Get_priority( priority_aggregation ),
+ prepend_it
);
}
@@ -881,78 +1277,141 @@ static void _Thread_queue_Priority_inherit_do_surrender(
Thread_Control *the_thread
)
{
+#if defined(RTEMS_SMP)
+ Chain_Node *fifo_node;
+ const Chain_Node *fifo_head;
+ const Chain_Node *fifo_tail;
+ Chain_Node *wait_node;
+ const Chain_Node *wait_tail;
+ ISR_lock_Context lock_context;
+#endif
Scheduler_Node *scheduler_node;
Thread_queue_Priority_queue *priority_queue;
- ISR_lock_Context lock_context;
+ Scheduler_Node *scheduler_node_of_owner;
- scheduler_node = _Thread_Scheduler_get_own_node( the_thread );
- priority_queue = _Thread_queue_Priority_queue( heads, scheduler_node );
+#if defined(RTEMS_SMP)
+ /*
+ * Remove the priority node of each priority queue from the previous owner.
+ * If a priority changes due to this, then register it for a priority update.
+ */
+
+ fifo_node = _Thread_queue_Priority_queue_rotation( heads );
+ fifo_head = _Chain_Immutable_head( &heads->Heads.Fifo );
+
+ _Priority_Actions_initialize_empty( &queue_context->Priority.Actions );
_Thread_Wait_acquire_default_critical( previous_owner, &lock_context );
-#if defined(RTEMS_SMP)
- if ( _Priority_Node_is_active( &heads->Boost_priority ) ) {
- _Thread_queue_Priority_remove(
- previous_owner,
- _Thread_Scheduler_get_own_node( previous_owner ),
- &heads->Boost_priority,
- queue_context
+ do {
+ priority_queue = (Thread_queue_Priority_queue *) fifo_node;
+ scheduler_node_of_owner = priority_queue->scheduler_node;
+
+ _Assert( scheduler_node_of_owner->owner == previous_owner );
+
+ _Priority_Extract(
+ &scheduler_node_of_owner->Wait.Priority,
+ &priority_queue->Queue.Node,
+ &queue_context->Priority.Actions,
+ _Thread_queue_Priority_inherit_do_surrender_remove,
+ _Thread_queue_Priority_inherit_do_surrender_change,
+ NULL
);
- _Priority_Node_set_inactive( &heads->Boost_priority );
- }
-#endif
- _Thread_queue_Priority_remove(
- previous_owner,
- priority_queue->scheduler_node,
- &priority_queue->Queue.Node,
- queue_context
- );
+ fifo_node = _Chain_Previous( fifo_node );
+ } while ( fifo_node != fifo_head );
+
+ if ( !_Priority_Actions_is_empty( &queue_context->Priority.Actions ) ) {
+ /*
+ * The previous owner performs this surrender operation. So, it is
+ * definitely not enqueued on a thread queue. It is sufficient to notify
+ * the scheduler about a priority update. There is no need for a
+ * _Thread_Priority_perform_actions().
+ */
+ _Thread_queue_Context_add_priority_update( queue_context, previous_owner );
+ }
_Thread_Wait_release_default_critical( previous_owner, &lock_context );
+ /*
+ * Remove the wait node of the new owner from the corresponding priority
+ * queue.
+ */
+
+ wait_node = _Chain_First( &the_thread->Scheduler.Wait_nodes );
+ wait_tail = _Chain_Immutable_tail( &the_thread->Scheduler.Wait_nodes );
+
+ do {
+ scheduler_node = SCHEDULER_NODE_OF_THREAD_WAIT_NODE( wait_node );
+ priority_queue = _Thread_queue_Priority_queue( heads, scheduler_node );
+
+ _Priority_Extract(
+ &priority_queue->Queue,
+ &scheduler_node->Wait.Priority.Node,
+ NULL,
+ _Thread_queue_Priority_queue_extract,
+ _Priority_Change_nothing,
+ NULL
+ );
+
+ wait_node = _Chain_Next( &scheduler_node->Thread.Wait_node );
+ } while ( wait_node != wait_tail );
+
+ /* Add the priority node of the remaining priority queues to the new owner */
+
+ fifo_node = _Chain_First( &heads->Heads.Fifo );
+ fifo_tail = _Chain_Immutable_tail( &heads->Heads.Fifo );
+
+ while ( fifo_node != fifo_tail ) {
+ const Scheduler_Control *scheduler;
+
+ priority_queue = (Thread_queue_Priority_queue *) fifo_node;
+ scheduler = _Priority_Get_scheduler( &priority_queue->Queue );
+ scheduler_node = _Thread_Scheduler_get_node_by_index(
+ the_thread,
+ _Scheduler_Get_index( scheduler )
+ );
+
+ priority_queue->scheduler_node = scheduler_node;
+ _Priority_Insert(
+ &scheduler_node->Wait.Priority,
+ &priority_queue->Queue.Node,
+ &queue_context->Priority.Actions,
+ _Thread_queue_Priority_inherit_do_surrender_add,
+ _Thread_queue_Priority_inherit_do_surrender_change_2,
+ the_thread
+ );
+
+ fifo_node = _Chain_Next( fifo_node );
+ }
+#else
+ scheduler_node = _Thread_Scheduler_get_own_node( the_thread );
+ priority_queue = _Thread_queue_Priority_queue( heads, scheduler_node );
+ scheduler_node_of_owner = priority_queue->scheduler_node;
+
+ _Priority_Extract_non_empty(
+ &scheduler_node_of_owner->Wait.Priority,
+ &priority_queue->Queue.Node,
+ &queue_context->Priority.Actions,
+ _Thread_queue_Priority_inherit_do_surrender_change,
+ previous_owner
+ );
_Priority_Extract(
&priority_queue->Queue,
&scheduler_node->Wait.Priority.Node,
NULL,
_Priority_Remove_nothing,
_Priority_Change_nothing,
- previous_owner
+ NULL
);
if ( !_Priority_Is_empty( &priority_queue->Queue ) ) {
priority_queue->scheduler_node = scheduler_node;
- _Thread_queue_Priority_add(
- the_thread,
+ _Priority_Non_empty_insert(
&scheduler_node->Wait.Priority,
&priority_queue->Queue.Node,
- queue_context
- );
- }
-
-#if defined(RTEMS_SMP)
- _Chain_Extract_unprotected( &priority_queue->Node );
-
- if ( !_Priority_Is_empty( &priority_queue->Queue ) ) {
- _Chain_Append_unprotected( &heads->Heads.Fifo, &priority_queue->Node );
- }
-
- if (
- !_Chain_Is_empty( &heads->Heads.Fifo)
- && !_Chain_Has_only_one_node( &heads->Heads.Fifo)
- ) {
- Priority_Control boost_priority;
-
- boost_priority = _Scheduler_Map_priority(
- _Scheduler_Get_own( the_thread ),
- PRIORITY_PSEUDO_ISR
- );
- _Priority_Node_initialize( &heads->Boost_priority, boost_priority );
- _Thread_queue_Priority_add(
- the_thread,
- &scheduler_node->Wait.Priority,
- &heads->Boost_priority,
- queue_context
+ &queue_context->Priority.Actions,
+ _Thread_queue_Priority_inherit_do_surrender_change,
+ the_thread
);
}
#endif
diff --git a/testsuites/smptests/smpmutex01/init.c b/testsuites/smptests/smpmutex01/init.c
index d88b7b8113..f595755b26 100644
--- a/testsuites/smptests/smpmutex01/init.c
+++ b/testsuites/smptests/smpmutex01/init.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2015 embedded brains GmbH. All rights reserved.
+ * Copyright (c) 2015, 2016 embedded brains GmbH. All rights reserved.
*
* embedded brains GmbH
* Dornierstr. 4
@@ -28,11 +28,21 @@ const char rtems_test_name[] = "SMPMUTEX 1";
#define TASK_COUNT 9
+#define PRIO_NONE 0
+
+/* Value choosen for Qemu, 2 would be sufficient for real targets */
+#define TIMEOUT_IN_TICKS 10
+
typedef enum {
REQ_WAKE_UP_MASTER = RTEMS_EVENT_0,
REQ_WAKE_UP_HELPER = RTEMS_EVENT_1,
REQ_MTX_OBTAIN = RTEMS_EVENT_2,
- REQ_MTX_RELEASE = RTEMS_EVENT_3
+ REQ_MTX_OBTAIN_TIMEOUT = RTEMS_EVENT_3,
+ REQ_MTX_RELEASE = RTEMS_EVENT_4,
+ REQ_MTX_2_OBTAIN = RTEMS_EVENT_5,
+ REQ_MTX_2_RELEASE = RTEMS_EVENT_6,
+ REQ_SEM_OBTAIN_RELEASE = RTEMS_EVENT_7,
+ REQ_SEM_RELEASE = RTEMS_EVENT_8
} request_id;
typedef enum {
@@ -50,6 +60,8 @@ typedef enum {
typedef struct {
rtems_id mtx;
+ rtems_id mtx_2;
+ rtems_id sem;
rtems_id tasks[TASK_COUNT];
int generation[TASK_COUNT];
int expected_generation[TASK_COUNT];
@@ -156,6 +168,14 @@ static void obtain(test_context *ctx)
rtems_test_assert(sc == RTEMS_SUCCESSFUL);
}
+static void obtain_timeout(test_context *ctx)
+{
+ rtems_status_code sc;
+
+ sc = rtems_semaphore_obtain(ctx->mtx, RTEMS_WAIT, TIMEOUT_IN_TICKS);
+ rtems_test_assert(sc == RTEMS_TIMEOUT);
+}
+
static void release(test_context *ctx)
{
rtems_status_code sc;
@@ -164,6 +184,46 @@ static void release(test_context *ctx)
rtems_test_assert(sc == RTEMS_SUCCESSFUL);
}
+static void obtain_2(test_context *ctx)
+{
+ rtems_status_code sc;
+
+ sc = rtems_semaphore_obtain(ctx->mtx_2, RTEMS_WAIT, RTEMS_NO_TIMEOUT);
+ rtems_test_assert(sc == RTEMS_SUCCESSFUL);
+}
+
+static void release_2(test_context *ctx)
+{
+ rtems_status_code sc;
+
+ sc = rtems_semaphore_release(ctx->mtx_2);
+ rtems_test_assert(sc == RTEMS_SUCCESSFUL);
+}
+
+static void sem_obtain(test_context *ctx)
+{
+ rtems_status_code sc;
+
+ sc = rtems_semaphore_obtain(ctx->sem, RTEMS_WAIT, RTEMS_NO_TIMEOUT);
+ rtems_test_assert(sc == RTEMS_SUCCESSFUL);
+}
+
+static void sem_release(test_context *ctx)
+{
+ rtems_status_code sc;
+
+ sc = rtems_semaphore_release(ctx->sem);
+ rtems_test_assert(sc == RTEMS_SUCCESSFUL);
+}
+
+static void wait(void)
+{
+ rtems_status_code sc;
+
+ sc = rtems_task_wake_after(TIMEOUT_IN_TICKS + 1);
+ rtems_test_assert(sc == RTEMS_SUCCESSFUL);
+}
+
static void check_generations(test_context *ctx, task_id a, task_id b)
{
size_t i;
@@ -199,14 +259,50 @@ static void assert_prio(
rtems_test_assert(expected == actual);
}
+static void assert_prio_by_scheduler(
+ test_context *ctx,
+ task_id id,
+ rtems_name scheduler,
+ rtems_task_priority expected
+)
+{
+ rtems_task_priority actual;
+ rtems_status_code sc;
+ rtems_id scheduler_id;
+
+ sc = rtems_scheduler_ident(scheduler, &scheduler_id);
+ rtems_test_assert(sc == RTEMS_SUCCESSFUL);
+
+ actual = PRIO_NONE;
+ sc = rtems_task_get_priority(
+ ctx->tasks[id],
+ scheduler_id,
+ &actual
+ );
+
+ if (expected == PRIO_NONE) {
+ rtems_test_assert(sc == RTEMS_NOT_DEFINED);
+ } else {
+ rtems_test_assert(sc == RTEMS_SUCCESSFUL);
+ }
+
+ rtems_test_assert(actual == expected);
+}
+
static void helper(rtems_task_argument arg)
{
test_context *ctx = &test_instance;
while (true) {
rtems_event_set events = wait_for_events();
- rtems_test_assert(events == REQ_WAKE_UP_HELPER);
- send_event(ctx, M, REQ_WAKE_UP_MASTER);
+
+ if ((events & REQ_WAKE_UP_HELPER) != 0) {
+ send_event(ctx, M, REQ_WAKE_UP_MASTER);
+ }
+
+ if ((events & REQ_SEM_RELEASE) != 0) {
+ sem_release(ctx);
+ }
}
}
@@ -223,10 +319,31 @@ static void worker(rtems_task_argument arg)
++ctx->generation[id];
}
+ if ((events & REQ_MTX_OBTAIN_TIMEOUT) != 0) {
+ obtain_timeout(ctx);
+ ++ctx->generation[id];
+ }
+
if ((events & REQ_MTX_RELEASE) != 0) {
release(ctx);
++ctx->generation[id];
}
+
+ if ((events & REQ_MTX_2_OBTAIN) != 0) {
+ obtain_2(ctx);
+ ++ctx->generation[id];
+ }
+
+ if ((events & REQ_MTX_2_RELEASE) != 0) {
+ release_2(ctx);
+ ++ctx->generation[id];
+ }
+
+ if ((events & REQ_SEM_OBTAIN_RELEASE) != 0) {
+ sem_obtain(ctx);
+ ++ctx->generation[id];
+ sem_release(ctx);
+ }
}
}
@@ -245,13 +362,31 @@ static void test_init(test_context *ctx)
start_task(ctx, H_B, helper, 6, SCHED_B);
sc = rtems_semaphore_create(
- rtems_build_name(' ', 'M', 'T', 'X'),
+ rtems_build_name('M', 'T', 'X', '1'),
1,
RTEMS_BINARY_SEMAPHORE | RTEMS_PRIORITY | RTEMS_INHERIT_PRIORITY,
0,
&ctx->mtx
);
rtems_test_assert(sc == RTEMS_SUCCESSFUL);
+
+ sc = rtems_semaphore_create(
+ rtems_build_name('M', 'T', 'X', '2'),
+ 1,
+ RTEMS_BINARY_SEMAPHORE | RTEMS_PRIORITY | RTEMS_INHERIT_PRIORITY,
+ 0,
+ &ctx->mtx_2
+ );
+ rtems_test_assert(sc == RTEMS_SUCCESSFUL);
+
+ sc = rtems_semaphore_create(
+ rtems_build_name(' ', 'S', 'E', 'M'),
+ 0,
+ RTEMS_COUNTING_SEMAPHORE | RTEMS_PRIORITY,
+ 0,
+ &ctx->sem
+ );
+ rtems_test_assert(sc == RTEMS_SUCCESSFUL);
}
static void test_simple_inheritance(test_context *ctx)
@@ -287,67 +422,254 @@ static void test_dequeue_order_one_scheduler_instance(test_context *ctx)
check_generations(ctx, A_2_1, NONE);
}
-static void test_simple_boosting(test_context *ctx)
+static void test_mixed_queue_two_scheduler_instances(test_context *ctx)
+{
+ obtain(ctx);
+ assert_prio_by_scheduler(ctx, M, SCHED_A, 3);
+ assert_prio_by_scheduler(ctx, M, SCHED_B, PRIO_NONE);
+
+ request(ctx, B_4, REQ_MTX_OBTAIN_TIMEOUT);
+ assert_prio_by_scheduler(ctx, M, SCHED_A, 3);
+ assert_prio_by_scheduler(ctx, M, SCHED_B, 4);
+ check_generations(ctx, NONE, NONE);
+ wait();
+ assert_prio_by_scheduler(ctx, M, SCHED_A, 3);
+ assert_prio_by_scheduler(ctx, M, SCHED_B, PRIO_NONE);
+ check_generations(ctx, B_4, NONE);
+
+ request(ctx, B_4, REQ_MTX_OBTAIN);
+ assert_prio_by_scheduler(ctx, M, SCHED_A, 3);
+ assert_prio_by_scheduler(ctx, M, SCHED_B, 4);
+ check_generations(ctx, NONE, NONE);
+
+ request(ctx, B_5_0, REQ_SEM_OBTAIN_RELEASE);
+ send_event(ctx, H_A, REQ_SEM_RELEASE);
+ check_generations(ctx, NONE, NONE);
+
+ /*
+ * We are in scheduler instance A. Task B_5_0 of scheduler instance B issued
+ * the counting semaphore obtain before us. However, we inherited the
+ * priority of B_4, so we get the semaphore before B_5_0 (priority order
+ * within scheduler instance B).
+ */
+ sem_obtain(ctx);
+ check_generations(ctx, NONE, NONE);
+
+ release(ctx);
+ assert_prio_by_scheduler(ctx, M, SCHED_A, 3);
+ assert_prio_by_scheduler(ctx, M, SCHED_B, PRIO_NONE);
+ sync_with_helper(ctx);
+ check_generations(ctx, B_4, NONE);
+
+ request(ctx, B_4, REQ_MTX_RELEASE);
+ check_generations(ctx, B_4, NONE);
+
+ sem_release(ctx);
+ sync_with_helper(ctx);
+ check_generations(ctx, B_5_0, NONE);
+
+ sem_obtain(ctx);
+}
+
+static void test_mixed_queue_two_scheduler_instances_sem_only(test_context *ctx)
+{
+ request(ctx, B_5_0, REQ_SEM_OBTAIN_RELEASE);
+ send_event(ctx, H_A, REQ_SEM_RELEASE);
+ check_generations(ctx, NONE, NONE);
+
+ /*
+ * We are in scheduler instance A. Task B_5_0 of scheduler instance B issued
+ * the counting semaphore obtain before us. No priority inheritance is
+ * involved, so task B_5_0 gets the counting semaphore first.
+ */
+ sem_obtain(ctx);
+ check_generations(ctx, B_5_0, NONE);
+
+ sem_release(ctx);
+}
+
+static void test_simple_inheritance_two_scheduler_instances(test_context *ctx)
{
obtain(ctx);
+ assert_prio_by_scheduler(ctx, M, SCHED_A, 3);
+ assert_prio_by_scheduler(ctx, M, SCHED_B, PRIO_NONE);
+
request(ctx, B_5_0, REQ_MTX_OBTAIN);
+ assert_prio_by_scheduler(ctx, M, SCHED_A, 3);
+ assert_prio_by_scheduler(ctx, M, SCHED_B, 5);
+
request(ctx, B_4, REQ_MTX_OBTAIN);
+ assert_prio_by_scheduler(ctx, M, SCHED_A, 3);
+ assert_prio_by_scheduler(ctx, M, SCHED_B, 4);
+
request(ctx, B_5_1, REQ_MTX_OBTAIN);
+ assert_prio_by_scheduler(ctx, M, SCHED_A, 3);
+ assert_prio_by_scheduler(ctx, M, SCHED_B, 4);
check_generations(ctx, NONE, NONE);
- assert_prio(ctx, M, 0);
+
release(ctx);
+ assert_prio_by_scheduler(ctx, M, SCHED_A, 3);
+ assert_prio_by_scheduler(ctx, M, SCHED_B, PRIO_NONE);
sync_with_helper(ctx);
- assert_prio(ctx, M, 3);
check_generations(ctx, B_4, NONE);
+
request(ctx, B_4, REQ_MTX_RELEASE);
check_generations(ctx, B_4, B_5_0);
+
request(ctx, B_5_0, REQ_MTX_RELEASE);
check_generations(ctx, B_5_0, B_5_1);
+
request(ctx, B_5_1, REQ_MTX_RELEASE);
check_generations(ctx, B_5_1, NONE);
}
+static void test_nested_inheritance_two_scheduler_instances(test_context *ctx)
+{
+ obtain_2(ctx);
+ assert_prio_by_scheduler(ctx, M, SCHED_A, 3);
+ assert_prio_by_scheduler(ctx, M, SCHED_B, PRIO_NONE);
+
+ request(ctx, B_5_0, REQ_MTX_OBTAIN);
+ assert_prio_by_scheduler(ctx, M, SCHED_A, 3);
+ assert_prio_by_scheduler(ctx, M, SCHED_B, PRIO_NONE);
+ assert_prio_by_scheduler(ctx, B_5_0, SCHED_A, PRIO_NONE);
+ assert_prio_by_scheduler(ctx, B_5_0, SCHED_B, 5);
+ check_generations(ctx, B_5_0, NONE);
+
+ request(ctx, B_5_0, REQ_MTX_2_OBTAIN);
+ assert_prio_by_scheduler(ctx, M, SCHED_A, 3);
+ assert_prio_by_scheduler(ctx, M, SCHED_B, 5);
+ assert_prio_by_scheduler(ctx, B_5_0, SCHED_A, PRIO_NONE);
+ assert_prio_by_scheduler(ctx, B_5_0, SCHED_B, 5);
+
+ request(ctx, B_4, REQ_MTX_OBTAIN_TIMEOUT);
+ assert_prio_by_scheduler(ctx, M, SCHED_A, 3);
+ assert_prio_by_scheduler(ctx, M, SCHED_B, 4);
+ assert_prio_by_scheduler(ctx, B_5_0, SCHED_A, PRIO_NONE);
+ assert_prio_by_scheduler(ctx, B_5_0, SCHED_B, 4);
+ wait();
+ assert_prio_by_scheduler(ctx, M, SCHED_A, 3);
+ assert_prio_by_scheduler(ctx, M, SCHED_B, 5);
+ assert_prio_by_scheduler(ctx, B_5_0, SCHED_A, PRIO_NONE);
+ assert_prio_by_scheduler(ctx, B_5_0, SCHED_B, 5);
+ check_generations(ctx, B_4, NONE);
+
+ request(ctx, B_4, REQ_MTX_OBTAIN);
+ assert_prio_by_scheduler(ctx, M, SCHED_A, 3);
+ assert_prio_by_scheduler(ctx, M, SCHED_B, 4);
+ assert_prio_by_scheduler(ctx, B_5_0, SCHED_A, PRIO_NONE);
+ assert_prio_by_scheduler(ctx, B_5_0, SCHED_B, 4);
+
+ request(ctx, B_5_1, REQ_MTX_2_OBTAIN);
+ assert_prio_by_scheduler(ctx, M, SCHED_A, 3);
+ assert_prio_by_scheduler(ctx, M, SCHED_B, 4);
+ assert_prio_by_scheduler(ctx, B_5_0, SCHED_A, PRIO_NONE);
+ assert_prio_by_scheduler(ctx, B_5_0, SCHED_B, 4);
+ check_generations(ctx, NONE, NONE);
+
+ release_2(ctx);
+ assert_prio_by_scheduler(ctx, M, SCHED_A, 3);
+ assert_prio_by_scheduler(ctx, M, SCHED_B, PRIO_NONE);
+ assert_prio_by_scheduler(ctx, B_5_0, SCHED_A, PRIO_NONE);
+ assert_prio_by_scheduler(ctx, B_5_0, SCHED_B, 4);
+ sync_with_helper(ctx);
+ check_generations(ctx, B_5_0, NONE);
+
+ request(ctx, B_5_0, REQ_MTX_RELEASE);
+ assert_prio_by_scheduler(ctx, B_5_0, SCHED_A, PRIO_NONE);
+ assert_prio_by_scheduler(ctx, B_5_0, SCHED_B, 5);
+ check_generations(ctx, B_4, B_5_0);
+
+ request(ctx, B_4, REQ_MTX_RELEASE);
+ check_generations(ctx, B_4, NONE);
+
+ request(ctx, B_5_0, REQ_MTX_2_RELEASE);
+ check_generations(ctx, B_5_0, B_5_1);
+
+ request(ctx, B_5_1, REQ_MTX_2_RELEASE);
+ check_generations(ctx, B_5_1, NONE);
+}
+
static void test_dequeue_order_two_scheduler_instances(test_context *ctx)
{
obtain(ctx);
+ assert_prio_by_scheduler(ctx, M, SCHED_A, 3);
+ assert_prio_by_scheduler(ctx, M, SCHED_B, PRIO_NONE);
+
request(ctx, A_2_0, REQ_MTX_OBTAIN);
+ assert_prio_by_scheduler(ctx, M, SCHED_A, 2);
+ assert_prio_by_scheduler(ctx, M, SCHED_B, PRIO_NONE);
check_generations(ctx, NONE, NONE);
- assert_prio(ctx, M, 2);
+
request(ctx, B_5_0, REQ_MTX_OBTAIN);
+ assert_prio_by_scheduler(ctx, M, SCHED_A, 2);
+ assert_prio_by_scheduler(ctx, M, SCHED_B, 5);
check_generations(ctx, NONE, NONE);
- assert_prio(ctx, M, 0);
+
request(ctx, B_5_1, REQ_MTX_OBTAIN);
+ assert_prio_by_scheduler(ctx, M, SCHED_A, 2);
+ assert_prio_by_scheduler(ctx, M, SCHED_B, 5);
+
request(ctx, B_4, REQ_MTX_OBTAIN);
+ assert_prio_by_scheduler(ctx, M, SCHED_A, 2);
+ assert_prio_by_scheduler(ctx, M, SCHED_B, 4);
+
request(ctx, A_2_1, REQ_MTX_OBTAIN);
+ assert_prio_by_scheduler(ctx, M, SCHED_A, 2);
+ assert_prio_by_scheduler(ctx, M, SCHED_B, 4);
+
request(ctx, A_1, REQ_MTX_OBTAIN);
+ assert_prio_by_scheduler(ctx, M, SCHED_A, 1);
+ assert_prio_by_scheduler(ctx, M, SCHED_B, 4);
check_generations(ctx, NONE, NONE);
+
release(ctx);
sync_with_helper(ctx);
+ assert_prio_by_scheduler(ctx, M, SCHED_A, 3);
+ assert_prio_by_scheduler(ctx, M, SCHED_B, PRIO_NONE);
+ assert_prio_by_scheduler(ctx, A_1, SCHED_A, 1);
+ assert_prio_by_scheduler(ctx, A_1, SCHED_B, 4);
check_generations(ctx, A_1, NONE);
- assert_prio(ctx, M, 3);
- assert_prio(ctx, A_1, 0);
+
request(ctx, A_1, REQ_MTX_RELEASE);
+ assert_prio_by_scheduler(ctx, A_1, SCHED_A, 1);
+ assert_prio_by_scheduler(ctx, A_1, SCHED_B, PRIO_NONE);
+ assert_prio_by_scheduler(ctx, B_4, SCHED_A, 2);
+ assert_prio_by_scheduler(ctx, B_4, SCHED_B, 4);
check_generations(ctx, A_1, B_4);
- assert_prio(ctx, A_1, 1);
- assert_prio(ctx, B_4, 0);
+
request(ctx, B_4, REQ_MTX_RELEASE);
+ assert_prio_by_scheduler(ctx, B_4, SCHED_A, PRIO_NONE);
+ assert_prio_by_scheduler(ctx, B_4, SCHED_B, 4);
+ assert_prio_by_scheduler(ctx, A_2_0, SCHED_A, 2);
+ assert_prio_by_scheduler(ctx, A_2_0, SCHED_B, 5);
check_generations(ctx, B_4, A_2_0);
- assert_prio(ctx, B_4, 4);
- assert_prio(ctx, A_2_0, 0);
+
request(ctx, A_2_0, REQ_MTX_RELEASE);
+ assert_prio_by_scheduler(ctx, A_2_0, SCHED_A, 2);
+ assert_prio_by_scheduler(ctx, A_2_0, SCHED_B, PRIO_NONE);
+ assert_prio_by_scheduler(ctx, B_5_0, SCHED_A, 2);
+ assert_prio_by_scheduler(ctx, B_5_0, SCHED_B, 5);
check_generations(ctx, A_2_0, B_5_0);
- assert_prio(ctx, A_2_0, 2);
- assert_prio(ctx, B_5_0, 0);
+
request(ctx, B_5_0, REQ_MTX_RELEASE);
+ assert_prio_by_scheduler(ctx, B_5_0, SCHED_A, PRIO_NONE);
+ assert_prio_by_scheduler(ctx, B_5_0, SCHED_B, 5);
+ assert_prio_by_scheduler(ctx, A_2_1, SCHED_A, 2);
+ assert_prio_by_scheduler(ctx, A_2_1, SCHED_B, 5);
check_generations(ctx, B_5_0, A_2_1);
- assert_prio(ctx, B_5_0, 5);
- assert_prio(ctx, A_2_1, 2);
+
request(ctx, A_2_1, REQ_MTX_RELEASE);
+ assert_prio_by_scheduler(ctx, A_2_1, SCHED_A, 2);
+ assert_prio_by_scheduler(ctx, A_2_1, SCHED_B, PRIO_NONE);
+ assert_prio_by_scheduler(ctx, B_5_1, SCHED_A, PRIO_NONE);
+ assert_prio_by_scheduler(ctx, B_5_1, SCHED_B, 5);
check_generations(ctx, A_2_1, B_5_1);
- assert_prio(ctx, B_5_1, 5);
+
request(ctx, B_5_1, REQ_MTX_RELEASE);
+ assert_prio_by_scheduler(ctx, B_5_1, SCHED_A, PRIO_NONE);
+ assert_prio_by_scheduler(ctx, B_5_1, SCHED_B, 5);
check_generations(ctx, B_5_1, NONE);
- assert_prio(ctx, B_5_1, 5);
}
static void test(void)
@@ -358,7 +680,10 @@ static void test(void)
test_task_get_priority_not_defined(ctx);
test_simple_inheritance(ctx);
test_dequeue_order_one_scheduler_instance(ctx);
- test_simple_boosting(ctx);
+ test_mixed_queue_two_scheduler_instances(ctx);
+ test_mixed_queue_two_scheduler_instances_sem_only(ctx);
+ test_simple_inheritance_two_scheduler_instances(ctx);
+ test_nested_inheritance_two_scheduler_instances(ctx);
test_dequeue_order_two_scheduler_instances(ctx);
}
@@ -399,7 +724,7 @@ RTEMS_SCHEDULER_CONTEXT_SIMPLE_SMP(b);
#define CONFIGURE_MAXIMUM_TASKS TASK_COUNT
-#define CONFIGURE_MAXIMUM_SEMAPHORES 1
+#define CONFIGURE_MAXIMUM_SEMAPHORES 3
#define CONFIGURE_INITIAL_EXTENSIONS RTEMS_TEST_INITIAL_EXTENSION