mirror of
https://gitlab.rtems.org/rtems/rtos/rtems.git
synced 2026-08-25 21:59:19 +08:00
@@ -23,6 +23,7 @@
|
||||
#include <rtems/asm.h>
|
||||
#else
|
||||
#include <rtems/score/assert.h>
|
||||
#include <rtems/score/chain.h>
|
||||
#include <rtems/score/isrlock.h>
|
||||
#include <rtems/score/smp.h>
|
||||
#include <rtems/score/smplock.h>
|
||||
@@ -394,6 +395,13 @@ typedef struct Per_CPU_Control {
|
||||
SMP_lock_Stats_context Lock_stats_context;
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief Chain of threads in need for help.
|
||||
*
|
||||
* This field is protected by the Per_CPU_Control::Lock lock.
|
||||
*/
|
||||
Chain_Control Threads_in_need_for_help;
|
||||
|
||||
/**
|
||||
* @brief Bit field for SMP messages.
|
||||
*
|
||||
|
||||
@@ -103,6 +103,52 @@ typedef struct {
|
||||
);
|
||||
|
||||
#if defined(RTEMS_SMP)
|
||||
/**
|
||||
* @brief Ask for help operation.
|
||||
*
|
||||
* @param[in] scheduler The scheduler instance to ask for help.
|
||||
* @param[in] the_thread The thread needing help.
|
||||
* @param[in] node The scheduler node.
|
||||
*
|
||||
* @retval true Ask for help was successful.
|
||||
* @retval false Otherwise.
|
||||
*/
|
||||
bool ( *ask_for_help )(
|
||||
const Scheduler_Control *scheduler,
|
||||
Thread_Control *the_thread,
|
||||
Scheduler_Node *node
|
||||
);
|
||||
|
||||
/**
|
||||
* @brief Reconsider help operation.
|
||||
*
|
||||
* @param[in] scheduler The scheduler instance to reconsider the help
|
||||
* request.
|
||||
* @param[in] the_thread The thread reconsidering a help request.
|
||||
* @param[in] node The scheduler node.
|
||||
*/
|
||||
void ( *reconsider_help_request )(
|
||||
const Scheduler_Control *scheduler,
|
||||
Thread_Control *the_thread,
|
||||
Scheduler_Node *node
|
||||
);
|
||||
|
||||
/**
|
||||
* @brief Withdraw node operation.
|
||||
*
|
||||
* @param[in] scheduler The scheduler instance to withdraw the node.
|
||||
* @param[in] the_thread The thread using the node.
|
||||
* @param[in] node The scheduler node to withdraw.
|
||||
* @param[in] next_state The next thread scheduler state in case the node is
|
||||
* scheduled.
|
||||
*/
|
||||
void ( *withdraw_node )(
|
||||
const Scheduler_Control *scheduler,
|
||||
Thread_Control *the_thread,
|
||||
Scheduler_Node *node,
|
||||
Thread_Scheduler_state next_state
|
||||
);
|
||||
|
||||
/**
|
||||
* Ask for help operation.
|
||||
*
|
||||
@@ -318,6 +364,49 @@ Priority_Control _Scheduler_default_Map_priority(
|
||||
#define _Scheduler_default_Unmap_priority _Scheduler_default_Map_priority
|
||||
|
||||
#if defined(RTEMS_SMP)
|
||||
/**
|
||||
* @brief Does nothing.
|
||||
*
|
||||
* @param[in] scheduler Unused.
|
||||
* @param[in] the_thread Unused.
|
||||
* @param[in] node Unused.
|
||||
*
|
||||
* @retval false Always.
|
||||
*/
|
||||
bool _Scheduler_default_Ask_for_help(
|
||||
const Scheduler_Control *scheduler,
|
||||
Thread_Control *the_thread,
|
||||
Scheduler_Node *node
|
||||
);
|
||||
|
||||
/**
|
||||
* @brief Does nothing.
|
||||
*
|
||||
* @param[in] scheduler Unused.
|
||||
* @param[in] the_thread Unused.
|
||||
* @param[in] node Unused.
|
||||
*/
|
||||
void _Scheduler_default_Reconsider_help_request(
|
||||
const Scheduler_Control *scheduler,
|
||||
Thread_Control *the_thread,
|
||||
Scheduler_Node *node
|
||||
);
|
||||
|
||||
/**
|
||||
* @brief Does nothing.
|
||||
*
|
||||
* @param[in] scheduler Unused.
|
||||
* @param[in] the_thread Unused.
|
||||
* @param[in] node Unused.
|
||||
* @param[in] next_state Unused.
|
||||
*/
|
||||
void _Scheduler_default_Withdraw_node(
|
||||
const Scheduler_Control *scheduler,
|
||||
Thread_Control *the_thread,
|
||||
Scheduler_Node *node,
|
||||
Thread_Scheduler_state next_state
|
||||
);
|
||||
|
||||
/**
|
||||
* @brief Does nothing.
|
||||
*
|
||||
@@ -334,6 +423,9 @@ Priority_Control _Scheduler_default_Map_priority(
|
||||
);
|
||||
|
||||
#define SCHEDULER_OPERATION_DEFAULT_ASK_FOR_HELP \
|
||||
_Scheduler_default_Ask_for_help, \
|
||||
_Scheduler_default_Reconsider_help_request, \
|
||||
_Scheduler_default_Withdraw_node, \
|
||||
_Scheduler_default_Ask_for_help_X,
|
||||
#else
|
||||
#define SCHEDULER_OPERATION_DEFAULT_ASK_FOR_HELP
|
||||
|
||||
@@ -325,19 +325,54 @@ RTEMS_INLINE_ROUTINE void _Scheduler_Yield( Thread_Control *the_thread )
|
||||
*/
|
||||
RTEMS_INLINE_ROUTINE void _Scheduler_Block( Thread_Control *the_thread )
|
||||
{
|
||||
#if defined(RTEMS_SMP)
|
||||
Chain_Node *node;
|
||||
const Chain_Node *tail;
|
||||
Scheduler_Node *scheduler_node;
|
||||
const Scheduler_Control *scheduler;
|
||||
ISR_lock_Context lock_context;
|
||||
|
||||
scheduler = _Scheduler_Get( the_thread );
|
||||
_Scheduler_Acquire_critical( scheduler, &lock_context );
|
||||
node = _Chain_First( &the_thread->Scheduler.Scheduler_nodes );
|
||||
tail = _Chain_Immutable_tail( &the_thread->Scheduler.Scheduler_nodes );
|
||||
|
||||
scheduler_node = SCHEDULER_NODE_OF_THREAD_SCHEDULER_NODE( node );
|
||||
scheduler = _Scheduler_Node_get_scheduler( scheduler_node );
|
||||
|
||||
_Scheduler_Acquire_critical( scheduler, &lock_context );
|
||||
( *scheduler->Operations.block )(
|
||||
scheduler,
|
||||
the_thread,
|
||||
scheduler_node
|
||||
);
|
||||
_Scheduler_Release_critical( scheduler, &lock_context );
|
||||
|
||||
node = _Chain_Next( node );
|
||||
|
||||
while ( node != tail ) {
|
||||
scheduler_node = SCHEDULER_NODE_OF_THREAD_SCHEDULER_NODE( node );
|
||||
scheduler = _Scheduler_Node_get_scheduler( scheduler_node );
|
||||
|
||||
_Scheduler_Acquire_critical( scheduler, &lock_context );
|
||||
( *scheduler->Operations.withdraw_node )(
|
||||
scheduler,
|
||||
the_thread,
|
||||
scheduler_node,
|
||||
THREAD_SCHEDULER_BLOCKED
|
||||
);
|
||||
_Scheduler_Release_critical( scheduler, &lock_context );
|
||||
|
||||
node = _Chain_Next( node );
|
||||
}
|
||||
#else
|
||||
const Scheduler_Control *scheduler;
|
||||
|
||||
scheduler = _Scheduler_Get( the_thread );
|
||||
( *scheduler->Operations.block )(
|
||||
scheduler,
|
||||
the_thread,
|
||||
_Thread_Scheduler_get_home_node( the_thread )
|
||||
);
|
||||
|
||||
_Scheduler_Release_critical( scheduler, &lock_context );
|
||||
#endif
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -352,33 +387,65 @@ RTEMS_INLINE_ROUTINE void _Scheduler_Block( Thread_Control *the_thread )
|
||||
*/
|
||||
RTEMS_INLINE_ROUTINE void _Scheduler_Unblock( Thread_Control *the_thread )
|
||||
{
|
||||
#if defined(RTEMS_SMP)
|
||||
Chain_Node *node;
|
||||
const Chain_Node *tail;
|
||||
Scheduler_Node *scheduler_node;
|
||||
const Scheduler_Control *scheduler;
|
||||
ISR_lock_Context lock_context;
|
||||
#if defined(RTEMS_SMP)
|
||||
Thread_Control *needs_help;
|
||||
#endif
|
||||
|
||||
#if defined(RTEMS_SMP)
|
||||
_Thread_Scheduler_process_requests( the_thread );
|
||||
#endif
|
||||
node = _Chain_First( &the_thread->Scheduler.Scheduler_nodes );
|
||||
tail = _Chain_Immutable_tail( &the_thread->Scheduler.Scheduler_nodes );
|
||||
|
||||
scheduler_node = SCHEDULER_NODE_OF_THREAD_SCHEDULER_NODE( node );
|
||||
scheduler = _Scheduler_Node_get_scheduler( scheduler_node );
|
||||
|
||||
_Scheduler_Acquire_critical( scheduler, &lock_context );
|
||||
needs_help = ( *scheduler->Operations.unblock )(
|
||||
scheduler,
|
||||
the_thread,
|
||||
scheduler_node
|
||||
);
|
||||
_Scheduler_Ask_for_help_if_necessary( needs_help );
|
||||
_Scheduler_Release_critical( scheduler, &lock_context );
|
||||
|
||||
if ( needs_help != the_thread ) {
|
||||
return;
|
||||
}
|
||||
|
||||
node = _Chain_Next( node );
|
||||
|
||||
while ( node != tail ) {
|
||||
bool success;
|
||||
|
||||
scheduler_node = SCHEDULER_NODE_OF_THREAD_SCHEDULER_NODE( node );
|
||||
scheduler = _Scheduler_Node_get_scheduler( scheduler_node );
|
||||
|
||||
_Scheduler_Acquire_critical( scheduler, &lock_context );
|
||||
success = ( *scheduler->Operations.ask_for_help )(
|
||||
scheduler,
|
||||
the_thread,
|
||||
scheduler_node
|
||||
);
|
||||
_Scheduler_Release_critical( scheduler, &lock_context );
|
||||
|
||||
if ( success ) {
|
||||
break;
|
||||
}
|
||||
|
||||
node = _Chain_Next( node );
|
||||
}
|
||||
#else
|
||||
const Scheduler_Control *scheduler;
|
||||
|
||||
scheduler = _Scheduler_Get( the_thread );
|
||||
_Scheduler_Acquire_critical( scheduler, &lock_context );
|
||||
|
||||
#if defined(RTEMS_SMP)
|
||||
needs_help =
|
||||
#endif
|
||||
( *scheduler->Operations.unblock )(
|
||||
scheduler,
|
||||
the_thread,
|
||||
_Thread_Scheduler_get_home_node( the_thread )
|
||||
);
|
||||
|
||||
#if defined(RTEMS_SMP)
|
||||
_Scheduler_Ask_for_help_if_necessary( needs_help );
|
||||
#endif
|
||||
|
||||
_Scheduler_Release_critical( scheduler, &lock_context );
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -397,33 +464,45 @@ RTEMS_INLINE_ROUTINE void _Scheduler_Unblock( Thread_Control *the_thread )
|
||||
*/
|
||||
RTEMS_INLINE_ROUTINE void _Scheduler_Update_priority( Thread_Control *the_thread )
|
||||
{
|
||||
const Scheduler_Control *own_scheduler;
|
||||
ISR_lock_Context lock_context;
|
||||
#if defined(RTEMS_SMP)
|
||||
Thread_Control *needs_help;
|
||||
#endif
|
||||
Chain_Node *node;
|
||||
const Chain_Node *tail;
|
||||
|
||||
#if defined(RTEMS_SMP)
|
||||
_Thread_Scheduler_process_requests( the_thread );
|
||||
#endif
|
||||
|
||||
own_scheduler = _Scheduler_Get_own( the_thread );
|
||||
_Scheduler_Acquire_critical( own_scheduler, &lock_context );
|
||||
node = _Chain_First( &the_thread->Scheduler.Scheduler_nodes );
|
||||
tail = _Chain_Immutable_tail( &the_thread->Scheduler.Scheduler_nodes );
|
||||
|
||||
#if defined(RTEMS_SMP)
|
||||
needs_help =
|
||||
#endif
|
||||
( *own_scheduler->Operations.update_priority )(
|
||||
own_scheduler,
|
||||
do {
|
||||
Scheduler_Node *scheduler_node;
|
||||
const Scheduler_Control *scheduler;
|
||||
ISR_lock_Context lock_context;
|
||||
Thread_Control *needs_help;
|
||||
|
||||
scheduler_node = SCHEDULER_NODE_OF_THREAD_SCHEDULER_NODE( node );
|
||||
scheduler = _Scheduler_Node_get_scheduler( scheduler_node );
|
||||
|
||||
_Scheduler_Acquire_critical( scheduler, &lock_context );
|
||||
needs_help = ( *scheduler->Operations.update_priority )(
|
||||
scheduler,
|
||||
the_thread,
|
||||
scheduler_node
|
||||
);
|
||||
_Scheduler_Ask_for_help_if_necessary( needs_help );
|
||||
_Scheduler_Release_critical( scheduler, &lock_context );
|
||||
|
||||
node = _Chain_Next( node );
|
||||
} while ( node != tail );
|
||||
#else
|
||||
const Scheduler_Control *scheduler;
|
||||
|
||||
scheduler = _Scheduler_Get( the_thread );
|
||||
( *scheduler->Operations.update_priority )(
|
||||
scheduler,
|
||||
the_thread,
|
||||
_Thread_Scheduler_get_home_node( the_thread )
|
||||
);
|
||||
|
||||
#if defined(RTEMS_SMP)
|
||||
_Scheduler_Ask_for_help_if_necessary( needs_help );
|
||||
#endif
|
||||
|
||||
_Scheduler_Release_critical( own_scheduler, &lock_context );
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1008,7 +1087,13 @@ _Scheduler_Try_to_schedule_node(
|
||||
_Thread_Scheduler_acquire_critical( user, &lock_context );
|
||||
|
||||
if ( node->help_state == SCHEDULER_HELP_YOURSELF ) {
|
||||
_Scheduler_Thread_change_state( user, THREAD_SCHEDULER_SCHEDULED );
|
||||
if ( user->Scheduler.state == THREAD_SCHEDULER_READY ) {
|
||||
_Thread_Scheduler_cancel_need_for_help( user, _Thread_Get_CPU( user ) );
|
||||
_Scheduler_Thread_change_state( user, THREAD_SCHEDULER_SCHEDULED );
|
||||
} else {
|
||||
action = SCHEDULER_TRY_TO_SCHEDULE_DO_BLOCK;
|
||||
}
|
||||
|
||||
_Thread_Scheduler_release_critical( user, &lock_context );
|
||||
return action;
|
||||
}
|
||||
@@ -1129,6 +1214,7 @@ RTEMS_INLINE_ROUTINE Per_CPU_Control *_Scheduler_Block_node(
|
||||
|
||||
_Thread_Scheduler_acquire_critical( thread, &lock_context );
|
||||
thread_cpu = _Thread_Get_CPU( thread );
|
||||
_Thread_Scheduler_cancel_need_for_help( thread, thread_cpu );
|
||||
_Scheduler_Thread_change_state( thread, THREAD_SCHEDULER_BLOCKED );
|
||||
_Thread_Scheduler_release_critical( thread, &lock_context );
|
||||
|
||||
|
||||
@@ -57,6 +57,9 @@ extern "C" {
|
||||
_Scheduler_priority_affinity_SMP_Update_priority, \
|
||||
_Scheduler_default_Map_priority, \
|
||||
_Scheduler_default_Unmap_priority, \
|
||||
_Scheduler_priority_affinity_SMP_Ask_for_help, \
|
||||
_Scheduler_priority_affinity_SMP_Reconsider_help_request, \
|
||||
_Scheduler_priority_affinity_SMP_Withdraw_node, \
|
||||
_Scheduler_priority_affinity_SMP_Ask_for_help_X, \
|
||||
_Scheduler_priority_affinity_SMP_Node_initialize, \
|
||||
_Scheduler_default_Node_destroy, \
|
||||
@@ -128,6 +131,25 @@ Thread_Control *_Scheduler_priority_affinity_SMP_Update_priority(
|
||||
Scheduler_Node *node
|
||||
);
|
||||
|
||||
bool _Scheduler_priority_affinity_SMP_Ask_for_help(
|
||||
const Scheduler_Control *scheduler,
|
||||
Thread_Control *the_thread,
|
||||
Scheduler_Node *node
|
||||
);
|
||||
|
||||
void _Scheduler_priority_affinity_SMP_Reconsider_help_request(
|
||||
const Scheduler_Control *scheduler,
|
||||
Thread_Control *the_thread,
|
||||
Scheduler_Node *node
|
||||
);
|
||||
|
||||
void _Scheduler_priority_affinity_SMP_Withdraw_node(
|
||||
const Scheduler_Control *scheduler,
|
||||
Thread_Control *the_thread,
|
||||
Scheduler_Node *node,
|
||||
Thread_Scheduler_state next_state
|
||||
);
|
||||
|
||||
Thread_Control *_Scheduler_priority_affinity_SMP_Ask_for_help_X(
|
||||
const Scheduler_Control *scheduler,
|
||||
Thread_Control *offers_help,
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (c) 2013-2014 embedded brains GmbH. All rights reserved.
|
||||
* Copyright (c) 2013, 2016 embedded brains GmbH. All rights reserved.
|
||||
*
|
||||
* embedded brains GmbH
|
||||
* Dornierstr. 4
|
||||
@@ -86,6 +86,9 @@ typedef struct {
|
||||
_Scheduler_priority_SMP_Update_priority, \
|
||||
_Scheduler_default_Map_priority, \
|
||||
_Scheduler_default_Unmap_priority, \
|
||||
_Scheduler_priority_SMP_Ask_for_help, \
|
||||
_Scheduler_priority_SMP_Reconsider_help_request, \
|
||||
_Scheduler_priority_SMP_Withdraw_node, \
|
||||
_Scheduler_priority_SMP_Ask_for_help_X, \
|
||||
_Scheduler_priority_SMP_Node_initialize, \
|
||||
_Scheduler_default_Node_destroy, \
|
||||
@@ -123,6 +126,25 @@ Thread_Control *_Scheduler_priority_SMP_Update_priority(
|
||||
Scheduler_Node *node
|
||||
);
|
||||
|
||||
bool _Scheduler_priority_SMP_Ask_for_help(
|
||||
const Scheduler_Control *scheduler,
|
||||
Thread_Control *the_thread,
|
||||
Scheduler_Node *node
|
||||
);
|
||||
|
||||
void _Scheduler_priority_SMP_Reconsider_help_request(
|
||||
const Scheduler_Control *scheduler,
|
||||
Thread_Control *the_thread,
|
||||
Scheduler_Node *node
|
||||
);
|
||||
|
||||
void _Scheduler_priority_SMP_Withdraw_node(
|
||||
const Scheduler_Control *scheduler,
|
||||
Thread_Control *the_thread,
|
||||
Scheduler_Node *node,
|
||||
Thread_Scheduler_state next_state
|
||||
);
|
||||
|
||||
Thread_Control *_Scheduler_priority_SMP_Ask_for_help_X(
|
||||
const Scheduler_Control *scheduler,
|
||||
Thread_Control *needs_help,
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
/*
|
||||
* Copyright (C) 2011 On-Line Applications Research Corporation (OAR).
|
||||
*
|
||||
* Copyright (c) 2013 embedded brains GmbH.
|
||||
* 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
|
||||
@@ -69,6 +69,9 @@ typedef struct {
|
||||
_Scheduler_simple_SMP_Update_priority, \
|
||||
_Scheduler_default_Map_priority, \
|
||||
_Scheduler_default_Unmap_priority, \
|
||||
_Scheduler_simple_SMP_Ask_for_help, \
|
||||
_Scheduler_simple_SMP_Reconsider_help_request, \
|
||||
_Scheduler_simple_SMP_Withdraw_node, \
|
||||
_Scheduler_simple_SMP_Ask_for_help_X, \
|
||||
_Scheduler_simple_SMP_Node_initialize, \
|
||||
_Scheduler_default_Node_destroy, \
|
||||
@@ -106,6 +109,25 @@ Thread_Control *_Scheduler_simple_SMP_Update_priority(
|
||||
Scheduler_Node *node
|
||||
);
|
||||
|
||||
bool _Scheduler_simple_SMP_Ask_for_help(
|
||||
const Scheduler_Control *scheduler,
|
||||
Thread_Control *the_thread,
|
||||
Scheduler_Node *node
|
||||
);
|
||||
|
||||
void _Scheduler_simple_SMP_Reconsider_help_request(
|
||||
const Scheduler_Control *scheduler,
|
||||
Thread_Control *the_thread,
|
||||
Scheduler_Node *node
|
||||
);
|
||||
|
||||
void _Scheduler_simple_SMP_Withdraw_node(
|
||||
const Scheduler_Control *scheduler,
|
||||
Thread_Control *the_thread,
|
||||
Scheduler_Node *node,
|
||||
Thread_Scheduler_state next_state
|
||||
);
|
||||
|
||||
Thread_Control *_Scheduler_simple_SMP_Ask_for_help_X(
|
||||
const Scheduler_Control *scheduler,
|
||||
Thread_Control *offers_help,
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (c) 2013-2015 embedded brains GmbH. All rights reserved.
|
||||
* Copyright (c) 2013, 2016 embedded brains GmbH. All rights reserved.
|
||||
*
|
||||
* embedded brains GmbH
|
||||
* Dornierstr. 4
|
||||
@@ -27,6 +27,7 @@
|
||||
#include <rtems/score/assert.h>
|
||||
#include <rtems/score/chainimpl.h>
|
||||
#include <rtems/score/schedulersimpleimpl.h>
|
||||
#include <rtems/bspIo.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
@@ -300,6 +301,12 @@ typedef void ( *Scheduler_SMP_Move )(
|
||||
Scheduler_Node *node_to_move
|
||||
);
|
||||
|
||||
typedef bool ( *Scheduler_SMP_Ask_for_help )(
|
||||
Scheduler_Context *context,
|
||||
Thread_Control *thread,
|
||||
Scheduler_Node *node
|
||||
);
|
||||
|
||||
typedef void ( *Scheduler_SMP_Update )(
|
||||
Scheduler_Context *context,
|
||||
Scheduler_Node *node_to_update,
|
||||
@@ -559,8 +566,22 @@ static inline Thread_Control *_Scheduler_SMP_Preempt(
|
||||
_Scheduler_SMP_Node_change_state( victim, SCHEDULER_SMP_NODE_READY );
|
||||
|
||||
_Thread_Scheduler_acquire_critical( victim_thread, &lock_context );
|
||||
|
||||
victim_cpu = _Thread_Get_CPU( victim_thread );
|
||||
_Scheduler_Thread_change_state( victim_thread, THREAD_SCHEDULER_READY );
|
||||
|
||||
if ( victim_thread->Scheduler.state == THREAD_SCHEDULER_SCHEDULED ) {
|
||||
_Scheduler_Thread_change_state( victim_thread, THREAD_SCHEDULER_READY );
|
||||
|
||||
if ( victim_thread->Scheduler.helping_nodes > 0 ) {
|
||||
_Per_CPU_Acquire( victim_cpu );
|
||||
_Chain_Append_unprotected(
|
||||
&victim_cpu->Threads_in_need_for_help,
|
||||
&victim_thread->Scheduler.Help_node
|
||||
);
|
||||
_Per_CPU_Release( victim_cpu );
|
||||
}
|
||||
}
|
||||
|
||||
_Thread_Scheduler_release_critical( victim_thread, &lock_context );
|
||||
|
||||
_Scheduler_SMP_Allocate_processor(
|
||||
@@ -589,6 +610,9 @@ static inline Scheduler_Node *_Scheduler_SMP_Get_lowest_scheduled(
|
||||
(void) order;
|
||||
|
||||
_Assert( &lowest_scheduled->Node != _Chain_Tail( scheduled ) );
|
||||
_Assert(
|
||||
_Chain_Next( &lowest_scheduled->Node ) == _Chain_Tail( scheduled )
|
||||
);
|
||||
|
||||
return lowest_scheduled;
|
||||
}
|
||||
@@ -901,7 +925,6 @@ static inline void _Scheduler_SMP_Block(
|
||||
Per_CPU_Control *thread_cpu;
|
||||
|
||||
node_state = _Scheduler_SMP_Node_state( node );
|
||||
_Assert( node_state != SCHEDULER_SMP_NODE_BLOCKED );
|
||||
|
||||
thread_cpu = _Scheduler_Block_node(
|
||||
context,
|
||||
@@ -910,6 +933,7 @@ static inline void _Scheduler_SMP_Block(
|
||||
node_state == SCHEDULER_SMP_NODE_SCHEDULED,
|
||||
_Scheduler_SMP_Get_idle_thread
|
||||
);
|
||||
|
||||
if ( thread_cpu != NULL ) {
|
||||
_Scheduler_SMP_Node_change_state( node, SCHEDULER_SMP_NODE_BLOCKED );
|
||||
|
||||
@@ -924,7 +948,7 @@ static inline void _Scheduler_SMP_Block(
|
||||
move_from_ready_to_scheduled,
|
||||
allocate_processor
|
||||
);
|
||||
} else {
|
||||
} else if ( node_state == SCHEDULER_SMP_NODE_READY ) {
|
||||
( *extract_from_ready )( context, node );
|
||||
}
|
||||
}
|
||||
@@ -996,7 +1020,8 @@ static inline Thread_Control *_Scheduler_SMP_Update_priority(
|
||||
Scheduler_SMP_Enqueue enqueue_fifo,
|
||||
Scheduler_SMP_Enqueue enqueue_lifo,
|
||||
Scheduler_SMP_Enqueue_scheduled enqueue_scheduled_fifo,
|
||||
Scheduler_SMP_Enqueue_scheduled enqueue_scheduled_lifo
|
||||
Scheduler_SMP_Enqueue_scheduled enqueue_scheduled_lifo,
|
||||
Scheduler_SMP_Ask_for_help ask_for_help
|
||||
)
|
||||
{
|
||||
Thread_Control *needs_help;
|
||||
@@ -1007,7 +1032,10 @@ static inline Thread_Control *_Scheduler_SMP_Update_priority(
|
||||
new_priority = _Scheduler_Node_get_priority( node, &prepend_it );
|
||||
|
||||
if ( new_priority == _Scheduler_SMP_Node_priority( node ) ) {
|
||||
/* Nothing to do */
|
||||
if ( _Thread_Is_ready( thread ) ) {
|
||||
( *ask_for_help )( context, thread, node );
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@@ -1036,6 +1064,10 @@ static inline Thread_Control *_Scheduler_SMP_Update_priority(
|
||||
} else {
|
||||
( *update )( context, node, new_priority );
|
||||
|
||||
if ( _Thread_Is_ready( thread ) ) {
|
||||
( *ask_for_help )( context, thread, node );
|
||||
}
|
||||
|
||||
needs_help = NULL;
|
||||
}
|
||||
|
||||
@@ -1149,6 +1181,135 @@ static inline void _Scheduler_SMP_Insert_scheduled_fifo(
|
||||
);
|
||||
}
|
||||
|
||||
static inline bool _Scheduler_SMP_Ask_for_help(
|
||||
Scheduler_Context *context,
|
||||
Thread_Control *thread,
|
||||
Scheduler_Node *node,
|
||||
Chain_Node_order order,
|
||||
Scheduler_SMP_Insert insert_ready,
|
||||
Scheduler_SMP_Insert insert_scheduled,
|
||||
Scheduler_SMP_Move move_from_scheduled_to_ready,
|
||||
Scheduler_SMP_Get_lowest_scheduled get_lowest_scheduled,
|
||||
Scheduler_SMP_Allocate_processor allocate_processor
|
||||
)
|
||||
{
|
||||
Scheduler_Node *lowest_scheduled;
|
||||
ISR_lock_Context lock_context;
|
||||
bool success;
|
||||
|
||||
lowest_scheduled = ( *get_lowest_scheduled )( context, node, order );
|
||||
|
||||
_Thread_Scheduler_acquire_critical( thread, &lock_context );
|
||||
|
||||
if (
|
||||
thread->Scheduler.state == THREAD_SCHEDULER_READY
|
||||
&& _Scheduler_SMP_Node_state( node ) == SCHEDULER_SMP_NODE_BLOCKED
|
||||
) {
|
||||
if ( ( *order )( &node->Node, &lowest_scheduled->Node ) ) {
|
||||
_Thread_Scheduler_cancel_need_for_help(
|
||||
thread,
|
||||
_Thread_Get_CPU( thread )
|
||||
);
|
||||
_Scheduler_Thread_change_state( thread, THREAD_SCHEDULER_SCHEDULED );
|
||||
_Thread_Scheduler_release_critical( thread, &lock_context );
|
||||
|
||||
_Scheduler_SMP_Preempt(
|
||||
context,
|
||||
node,
|
||||
lowest_scheduled,
|
||||
allocate_processor
|
||||
);
|
||||
|
||||
( *insert_scheduled )( context, node );
|
||||
( *move_from_scheduled_to_ready )( context, lowest_scheduled );
|
||||
|
||||
_Scheduler_Release_idle_thread(
|
||||
context,
|
||||
lowest_scheduled,
|
||||
_Scheduler_SMP_Release_idle_thread
|
||||
);
|
||||
success = true;
|
||||
} else {
|
||||
_Thread_Scheduler_release_critical( thread, &lock_context );
|
||||
_Scheduler_SMP_Node_change_state( node, SCHEDULER_SMP_NODE_READY );
|
||||
( *insert_ready )( context, node );
|
||||
success = false;
|
||||
}
|
||||
} else {
|
||||
_Thread_Scheduler_release_critical( thread, &lock_context );
|
||||
success = false;
|
||||
}
|
||||
|
||||
return success;
|
||||
}
|
||||
|
||||
static inline void _Scheduler_SMP_Reconsider_help_request(
|
||||
Scheduler_Context *context,
|
||||
Thread_Control *thread,
|
||||
Scheduler_Node *node,
|
||||
Scheduler_SMP_Extract extract_from_ready
|
||||
)
|
||||
{
|
||||
ISR_lock_Context lock_context;
|
||||
|
||||
_Thread_Scheduler_acquire_critical( thread, &lock_context );
|
||||
|
||||
if (
|
||||
thread->Scheduler.state == THREAD_SCHEDULER_SCHEDULED
|
||||
&& _Scheduler_SMP_Node_state( node ) == SCHEDULER_SMP_NODE_READY
|
||||
) {
|
||||
_Scheduler_SMP_Node_change_state( node, SCHEDULER_SMP_NODE_BLOCKED );
|
||||
( *extract_from_ready )( context, node );
|
||||
}
|
||||
|
||||
_Thread_Scheduler_release_critical( thread, &lock_context );
|
||||
}
|
||||
|
||||
static inline void _Scheduler_SMP_Withdraw_node(
|
||||
Scheduler_Context *context,
|
||||
Thread_Control *thread,
|
||||
Scheduler_Node *node,
|
||||
Thread_Scheduler_state next_state,
|
||||
Scheduler_SMP_Extract extract_from_ready,
|
||||
Scheduler_SMP_Get_highest_ready get_highest_ready,
|
||||
Scheduler_SMP_Move move_from_ready_to_scheduled,
|
||||
Scheduler_SMP_Allocate_processor allocate_processor
|
||||
)
|
||||
{
|
||||
ISR_lock_Context lock_context;
|
||||
Scheduler_SMP_Node_state node_state;
|
||||
|
||||
_Thread_Scheduler_acquire_critical( thread, &lock_context );
|
||||
|
||||
node_state = _Scheduler_SMP_Node_state( node );
|
||||
_Scheduler_SMP_Node_change_state( node, SCHEDULER_SMP_NODE_BLOCKED );
|
||||
|
||||
if ( node_state == SCHEDULER_SMP_NODE_SCHEDULED ) {
|
||||
Per_CPU_Control *thread_cpu;
|
||||
|
||||
thread_cpu = _Thread_Get_CPU( thread );
|
||||
_Scheduler_Thread_change_state( thread, next_state );
|
||||
_Thread_Scheduler_release_critical( thread, &lock_context );
|
||||
|
||||
_Scheduler_SMP_Extract_from_scheduled( node );
|
||||
_Scheduler_SMP_Schedule_highest_ready(
|
||||
context,
|
||||
node,
|
||||
thread_cpu,
|
||||
extract_from_ready,
|
||||
get_highest_ready,
|
||||
move_from_ready_to_scheduled,
|
||||
allocate_processor
|
||||
);
|
||||
} else if ( node_state == SCHEDULER_SMP_NODE_READY ) {
|
||||
_Thread_Scheduler_release_critical( thread, &lock_context );
|
||||
( *extract_from_ready )( context, node );
|
||||
} else {
|
||||
_Assert( node_state == SCHEDULER_SMP_NODE_BLOCKED );
|
||||
_Thread_Scheduler_release_critical( thread, &lock_context );
|
||||
}
|
||||
}
|
||||
|
||||
/** @} */
|
||||
|
||||
#ifdef __cplusplus
|
||||
|
||||
@@ -86,6 +86,9 @@ typedef struct {
|
||||
_Scheduler_strong_APA_Update_priority, \
|
||||
_Scheduler_default_Map_priority, \
|
||||
_Scheduler_default_Unmap_priority, \
|
||||
_Scheduler_strong_APA_Ask_for_help, \
|
||||
_Scheduler_strong_APA_Reconsider_help_request, \
|
||||
_Scheduler_strong_APA_Withdraw_node, \
|
||||
_Scheduler_strong_APA_Ask_for_help_X, \
|
||||
_Scheduler_strong_APA_Node_initialize, \
|
||||
_Scheduler_default_Node_destroy, \
|
||||
@@ -123,6 +126,25 @@ Thread_Control *_Scheduler_strong_APA_Update_priority(
|
||||
Scheduler_Node *node
|
||||
);
|
||||
|
||||
bool _Scheduler_strong_APA_Ask_for_help(
|
||||
const Scheduler_Control *scheduler,
|
||||
Thread_Control *the_thread,
|
||||
Scheduler_Node *node
|
||||
);
|
||||
|
||||
void _Scheduler_strong_APA_Reconsider_help_request(
|
||||
const Scheduler_Control *scheduler,
|
||||
Thread_Control *the_thread,
|
||||
Scheduler_Node *node
|
||||
);
|
||||
|
||||
void _Scheduler_strong_APA_Withdraw_node(
|
||||
const Scheduler_Control *scheduler,
|
||||
Thread_Control *the_thread,
|
||||
Scheduler_Node *node,
|
||||
Thread_Scheduler_state next_state
|
||||
);
|
||||
|
||||
Thread_Control *_Scheduler_strong_APA_Ask_for_help_X(
|
||||
const Scheduler_Control *scheduler,
|
||||
Thread_Control *needs_help,
|
||||
|
||||
@@ -309,6 +309,21 @@ typedef struct {
|
||||
*/
|
||||
Chain_Control Scheduler_nodes;
|
||||
|
||||
/**
|
||||
* @brief Node for the Per_CPU_Control::Threads_in_need_for_help chain.
|
||||
*
|
||||
* This chain is protected by the Per_CPU_Control::Lock lock of the assigned
|
||||
* processor.
|
||||
*/
|
||||
Chain_Node Help_node;
|
||||
|
||||
/**
|
||||
* @brief Count of nodes scheduler nodes minus one.
|
||||
*
|
||||
* This chain is protected by the thread state lock.
|
||||
*/
|
||||
size_t helping_nodes;
|
||||
|
||||
/**
|
||||
* @brief List of pending scheduler node requests.
|
||||
*
|
||||
|
||||
@@ -81,6 +81,9 @@ extern Thread_Control *_Thread_Allocated_fp;
|
||||
#if defined(RTEMS_SMP)
|
||||
#define THREAD_RESOURCE_NODE_TO_THREAD( node ) \
|
||||
RTEMS_CONTAINER_OF( node, Thread_Control, Resource_node )
|
||||
|
||||
#define THREAD_OF_SCHEDULER_HELP_NODE( node ) \
|
||||
RTEMS_CONTAINER_OF( node, Thread_Control, Scheduler.Help_node )
|
||||
#endif
|
||||
|
||||
typedef bool ( *Thread_Visitor )( Thread_Control *the_thread, void *arg );
|
||||
@@ -993,6 +996,23 @@ RTEMS_INLINE_ROUTINE bool _Thread_Owns_resources(
|
||||
return owns_resources;
|
||||
}
|
||||
|
||||
#if defined(RTEMS_SMP)
|
||||
RTEMS_INLINE_ROUTINE void _Thread_Scheduler_cancel_need_for_help(
|
||||
Thread_Control *the_thread,
|
||||
Per_CPU_Control *cpu
|
||||
)
|
||||
{
|
||||
_Per_CPU_Acquire( cpu );
|
||||
|
||||
if ( !_Chain_Is_node_off_chain( &the_thread->Scheduler.Help_node ) ) {
|
||||
_Chain_Extract_unprotected( &the_thread->Scheduler.Help_node );
|
||||
_Chain_Set_off_chain( &the_thread->Scheduler.Help_node );
|
||||
}
|
||||
|
||||
_Per_CPU_Release( cpu );
|
||||
}
|
||||
#endif
|
||||
|
||||
RTEMS_INLINE_ROUTINE Scheduler_Node *_Thread_Scheduler_get_own_node(
|
||||
const Thread_Control *the_thread
|
||||
)
|
||||
@@ -1051,7 +1071,11 @@ RTEMS_INLINE_ROUTINE void _Thread_Scheduler_release_critical(
|
||||
_ISR_lock_Release( &the_thread->Scheduler.Lock, lock_context );
|
||||
}
|
||||
|
||||
#if defined(RTEMS_SMP)
|
||||
void _Thread_Scheduler_ask_for_help( Thread_Control *the_thread );
|
||||
|
||||
void _Thread_Scheduler_process_requests( Thread_Control *the_thread );
|
||||
#endif
|
||||
|
||||
RTEMS_INLINE_ROUTINE void _Thread_Scheduler_add_request(
|
||||
Thread_Control *the_thread,
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2014 embedded brains GmbH
|
||||
* Copyright (c) 2014, 2016 embedded brains GmbH
|
||||
*
|
||||
* The license and distribution terms for this file may be
|
||||
* found in the file LICENSE in this distribution or at
|
||||
@@ -12,6 +12,43 @@
|
||||
|
||||
#include <rtems/score/scheduler.h>
|
||||
|
||||
bool _Scheduler_default_Ask_for_help(
|
||||
const Scheduler_Control *scheduler,
|
||||
Thread_Control *the_thread,
|
||||
Scheduler_Node *node
|
||||
)
|
||||
{
|
||||
(void) scheduler;
|
||||
(void) the_thread;
|
||||
(void) node;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void _Scheduler_default_Reconsider_help_request(
|
||||
const Scheduler_Control *scheduler,
|
||||
Thread_Control *the_thread,
|
||||
Scheduler_Node *node
|
||||
)
|
||||
{
|
||||
(void) scheduler;
|
||||
(void) the_thread;
|
||||
(void) node;
|
||||
}
|
||||
|
||||
void _Scheduler_default_Withdraw_node(
|
||||
const Scheduler_Control *scheduler,
|
||||
Thread_Control *the_thread,
|
||||
Scheduler_Node *node,
|
||||
Thread_Scheduler_state next_state
|
||||
)
|
||||
{
|
||||
(void) scheduler;
|
||||
(void) the_thread;
|
||||
(void) node;
|
||||
(void) next_state;
|
||||
}
|
||||
|
||||
Thread_Control *_Scheduler_default_Ask_for_help_X(
|
||||
const Scheduler_Control *scheduler,
|
||||
Thread_Control *offers_help,
|
||||
|
||||
@@ -499,6 +499,25 @@ static Thread_Control *_Scheduler_priority_affinity_SMP_Enqueue_scheduled_fifo(
|
||||
);
|
||||
}
|
||||
|
||||
static bool _Scheduler_priority_affinity_SMP_Do_ask_for_help(
|
||||
Scheduler_Context *context,
|
||||
Thread_Control *the_thread,
|
||||
Scheduler_Node *node
|
||||
)
|
||||
{
|
||||
return _Scheduler_SMP_Ask_for_help(
|
||||
context,
|
||||
the_thread,
|
||||
node,
|
||||
_Scheduler_SMP_Insert_priority_lifo_order,
|
||||
_Scheduler_priority_SMP_Insert_ready_lifo,
|
||||
_Scheduler_SMP_Insert_scheduled_lifo,
|
||||
_Scheduler_priority_SMP_Move_from_scheduled_to_ready,
|
||||
_Scheduler_SMP_Get_lowest_scheduled,
|
||||
_Scheduler_SMP_Allocate_processor_lazy
|
||||
);
|
||||
}
|
||||
|
||||
/*
|
||||
* This is the public scheduler specific Change Priority operation.
|
||||
*/
|
||||
@@ -520,7 +539,8 @@ Thread_Control *_Scheduler_priority_affinity_SMP_Update_priority(
|
||||
_Scheduler_priority_affinity_SMP_Enqueue_fifo,
|
||||
_Scheduler_priority_affinity_SMP_Enqueue_lifo,
|
||||
_Scheduler_priority_affinity_SMP_Enqueue_scheduled_fifo,
|
||||
_Scheduler_priority_affinity_SMP_Enqueue_scheduled_lifo
|
||||
_Scheduler_priority_affinity_SMP_Enqueue_scheduled_lifo,
|
||||
_Scheduler_priority_affinity_SMP_Do_ask_for_help
|
||||
);
|
||||
|
||||
/*
|
||||
@@ -531,6 +551,54 @@ Thread_Control *_Scheduler_priority_affinity_SMP_Update_priority(
|
||||
return displaced;
|
||||
}
|
||||
|
||||
bool _Scheduler_priority_affinity_SMP_Ask_for_help(
|
||||
const Scheduler_Control *scheduler,
|
||||
Thread_Control *the_thread,
|
||||
Scheduler_Node *node
|
||||
)
|
||||
{
|
||||
Scheduler_Context *context = _Scheduler_Get_context( scheduler );
|
||||
|
||||
return _Scheduler_priority_affinity_SMP_Do_ask_for_help( context, the_thread, node );
|
||||
}
|
||||
|
||||
void _Scheduler_priority_affinity_SMP_Reconsider_help_request(
|
||||
const Scheduler_Control *scheduler,
|
||||
Thread_Control *the_thread,
|
||||
Scheduler_Node *node
|
||||
)
|
||||
{
|
||||
Scheduler_Context *context = _Scheduler_Get_context( scheduler );
|
||||
|
||||
_Scheduler_SMP_Reconsider_help_request(
|
||||
context,
|
||||
the_thread,
|
||||
node,
|
||||
_Scheduler_priority_SMP_Extract_from_ready
|
||||
);
|
||||
}
|
||||
|
||||
void _Scheduler_priority_affinity_SMP_Withdraw_node(
|
||||
const Scheduler_Control *scheduler,
|
||||
Thread_Control *the_thread,
|
||||
Scheduler_Node *node,
|
||||
Thread_Scheduler_state next_state
|
||||
)
|
||||
{
|
||||
Scheduler_Context *context = _Scheduler_Get_context( scheduler );
|
||||
|
||||
_Scheduler_SMP_Withdraw_node(
|
||||
context,
|
||||
the_thread,
|
||||
node,
|
||||
next_state,
|
||||
_Scheduler_priority_SMP_Extract_from_ready,
|
||||
_Scheduler_priority_affinity_SMP_Get_highest_ready,
|
||||
_Scheduler_priority_SMP_Move_from_ready_to_scheduled,
|
||||
_Scheduler_SMP_Allocate_processor_lazy
|
||||
);
|
||||
}
|
||||
|
||||
Thread_Control *_Scheduler_priority_affinity_SMP_Ask_for_help_X(
|
||||
const Scheduler_Control *scheduler,
|
||||
Thread_Control *offers_help,
|
||||
|
||||
@@ -229,6 +229,25 @@ Thread_Control *_Scheduler_priority_SMP_Unblock(
|
||||
);
|
||||
}
|
||||
|
||||
static bool _Scheduler_priority_SMP_Do_ask_for_help(
|
||||
Scheduler_Context *context,
|
||||
Thread_Control *the_thread,
|
||||
Scheduler_Node *node
|
||||
)
|
||||
{
|
||||
return _Scheduler_SMP_Ask_for_help(
|
||||
context,
|
||||
the_thread,
|
||||
node,
|
||||
_Scheduler_SMP_Insert_priority_lifo_order,
|
||||
_Scheduler_priority_SMP_Insert_ready_lifo,
|
||||
_Scheduler_SMP_Insert_scheduled_lifo,
|
||||
_Scheduler_priority_SMP_Move_from_scheduled_to_ready,
|
||||
_Scheduler_SMP_Get_lowest_scheduled,
|
||||
_Scheduler_SMP_Allocate_processor_lazy
|
||||
);
|
||||
}
|
||||
|
||||
Thread_Control *_Scheduler_priority_SMP_Update_priority(
|
||||
const Scheduler_Control *scheduler,
|
||||
Thread_Control *thread,
|
||||
@@ -246,7 +265,56 @@ Thread_Control *_Scheduler_priority_SMP_Update_priority(
|
||||
_Scheduler_priority_SMP_Enqueue_fifo,
|
||||
_Scheduler_priority_SMP_Enqueue_lifo,
|
||||
_Scheduler_priority_SMP_Enqueue_scheduled_fifo,
|
||||
_Scheduler_priority_SMP_Enqueue_scheduled_lifo
|
||||
_Scheduler_priority_SMP_Enqueue_scheduled_lifo,
|
||||
_Scheduler_priority_SMP_Do_ask_for_help
|
||||
);
|
||||
}
|
||||
|
||||
bool _Scheduler_priority_SMP_Ask_for_help(
|
||||
const Scheduler_Control *scheduler,
|
||||
Thread_Control *the_thread,
|
||||
Scheduler_Node *node
|
||||
)
|
||||
{
|
||||
Scheduler_Context *context = _Scheduler_Get_context( scheduler );
|
||||
|
||||
return _Scheduler_priority_SMP_Do_ask_for_help( context, the_thread, node );
|
||||
}
|
||||
|
||||
void _Scheduler_priority_SMP_Reconsider_help_request(
|
||||
const Scheduler_Control *scheduler,
|
||||
Thread_Control *the_thread,
|
||||
Scheduler_Node *node
|
||||
)
|
||||
{
|
||||
Scheduler_Context *context = _Scheduler_Get_context( scheduler );
|
||||
|
||||
_Scheduler_SMP_Reconsider_help_request(
|
||||
context,
|
||||
the_thread,
|
||||
node,
|
||||
_Scheduler_priority_SMP_Extract_from_ready
|
||||
);
|
||||
}
|
||||
|
||||
void _Scheduler_priority_SMP_Withdraw_node(
|
||||
const Scheduler_Control *scheduler,
|
||||
Thread_Control *the_thread,
|
||||
Scheduler_Node *node,
|
||||
Thread_Scheduler_state next_state
|
||||
)
|
||||
{
|
||||
Scheduler_Context *context = _Scheduler_Get_context( scheduler );
|
||||
|
||||
_Scheduler_SMP_Withdraw_node(
|
||||
context,
|
||||
the_thread,
|
||||
node,
|
||||
next_state,
|
||||
_Scheduler_priority_SMP_Extract_from_ready,
|
||||
_Scheduler_priority_SMP_Get_highest_ready,
|
||||
_Scheduler_priority_SMP_Move_from_ready_to_scheduled,
|
||||
_Scheduler_SMP_Allocate_processor_lazy
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (c) 2013-2014 embedded brains GmbH.
|
||||
* 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
|
||||
@@ -49,10 +49,10 @@ void _Scheduler_simple_SMP_Node_initialize(
|
||||
Priority_Control priority
|
||||
)
|
||||
{
|
||||
Scheduler_SMP_Node *the_node;
|
||||
Scheduler_SMP_Node *smp_node;
|
||||
|
||||
the_node = _Scheduler_SMP_Node_downcast( node );
|
||||
_Scheduler_SMP_Node_initialize( scheduler, the_node, the_thread, priority );
|
||||
smp_node = _Scheduler_SMP_Node_downcast( node );
|
||||
_Scheduler_SMP_Node_initialize( scheduler, smp_node, the_thread, priority );
|
||||
}
|
||||
|
||||
static void _Scheduler_simple_SMP_Do_update(
|
||||
@@ -61,12 +61,12 @@ static void _Scheduler_simple_SMP_Do_update(
|
||||
Priority_Control new_priority
|
||||
)
|
||||
{
|
||||
Scheduler_SMP_Node *the_node;
|
||||
Scheduler_SMP_Node *smp_node;
|
||||
|
||||
(void) context;
|
||||
|
||||
the_node = _Scheduler_SMP_Node_downcast( node );
|
||||
_Scheduler_SMP_Node_update_priority( the_node, new_priority );
|
||||
smp_node = _Scheduler_SMP_Node_downcast( node );
|
||||
_Scheduler_SMP_Node_update_priority( smp_node, new_priority );
|
||||
}
|
||||
|
||||
static Scheduler_Node *_Scheduler_simple_SMP_Get_highest_ready(
|
||||
@@ -296,6 +296,25 @@ Thread_Control *_Scheduler_simple_SMP_Unblock(
|
||||
);
|
||||
}
|
||||
|
||||
static bool _Scheduler_simple_SMP_Do_ask_for_help(
|
||||
Scheduler_Context *context,
|
||||
Thread_Control *the_thread,
|
||||
Scheduler_Node *node
|
||||
)
|
||||
{
|
||||
return _Scheduler_SMP_Ask_for_help(
|
||||
context,
|
||||
the_thread,
|
||||
node,
|
||||
_Scheduler_SMP_Insert_priority_lifo_order,
|
||||
_Scheduler_simple_SMP_Insert_ready_lifo,
|
||||
_Scheduler_SMP_Insert_scheduled_lifo,
|
||||
_Scheduler_simple_SMP_Move_from_scheduled_to_ready,
|
||||
_Scheduler_SMP_Get_lowest_scheduled,
|
||||
_Scheduler_SMP_Allocate_processor_lazy
|
||||
);
|
||||
}
|
||||
|
||||
Thread_Control *_Scheduler_simple_SMP_Update_priority(
|
||||
const Scheduler_Control *scheduler,
|
||||
Thread_Control *thread,
|
||||
@@ -313,7 +332,56 @@ Thread_Control *_Scheduler_simple_SMP_Update_priority(
|
||||
_Scheduler_simple_SMP_Enqueue_fifo,
|
||||
_Scheduler_simple_SMP_Enqueue_lifo,
|
||||
_Scheduler_simple_SMP_Enqueue_scheduled_fifo,
|
||||
_Scheduler_simple_SMP_Enqueue_scheduled_lifo
|
||||
_Scheduler_simple_SMP_Enqueue_scheduled_lifo,
|
||||
_Scheduler_simple_SMP_Do_ask_for_help
|
||||
);
|
||||
}
|
||||
|
||||
bool _Scheduler_simple_SMP_Ask_for_help(
|
||||
const Scheduler_Control *scheduler,
|
||||
Thread_Control *the_thread,
|
||||
Scheduler_Node *node
|
||||
)
|
||||
{
|
||||
Scheduler_Context *context = _Scheduler_Get_context( scheduler );
|
||||
|
||||
return _Scheduler_simple_SMP_Do_ask_for_help( context, the_thread, node );
|
||||
}
|
||||
|
||||
void _Scheduler_simple_SMP_Reconsider_help_request(
|
||||
const Scheduler_Control *scheduler,
|
||||
Thread_Control *the_thread,
|
||||
Scheduler_Node *node
|
||||
)
|
||||
{
|
||||
Scheduler_Context *context = _Scheduler_Get_context( scheduler );
|
||||
|
||||
_Scheduler_SMP_Reconsider_help_request(
|
||||
context,
|
||||
the_thread,
|
||||
node,
|
||||
_Scheduler_simple_SMP_Extract_from_ready
|
||||
);
|
||||
}
|
||||
|
||||
void _Scheduler_simple_SMP_Withdraw_node(
|
||||
const Scheduler_Control *scheduler,
|
||||
Thread_Control *the_thread,
|
||||
Scheduler_Node *node,
|
||||
Thread_Scheduler_state next_state
|
||||
)
|
||||
{
|
||||
Scheduler_Context *context = _Scheduler_Get_context( scheduler );
|
||||
|
||||
_Scheduler_SMP_Withdraw_node(
|
||||
context,
|
||||
the_thread,
|
||||
node,
|
||||
next_state,
|
||||
_Scheduler_simple_SMP_Extract_from_ready,
|
||||
_Scheduler_simple_SMP_Get_highest_ready,
|
||||
_Scheduler_simple_SMP_Move_from_ready_to_scheduled,
|
||||
_Scheduler_SMP_Allocate_processor_lazy
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@@ -35,8 +35,8 @@
|
||||
*/
|
||||
const bool _Scheduler_Thread_state_valid_state_changes[ 3 ][ 3 ] = {
|
||||
/* FROM / TO BLOCKED SCHEDULED READY */
|
||||
/* BLOCKED */ { false, true, true },
|
||||
/* SCHEDULED */ { true, false, true },
|
||||
/* BLOCKED */ { true, true, true },
|
||||
/* SCHEDULED */ { true, true, true },
|
||||
/* READY */ { true, true, true }
|
||||
};
|
||||
|
||||
@@ -46,7 +46,7 @@ const bool _Scheduler_Thread_state_valid_state_changes[ 3 ][ 3 ] = {
|
||||
*/
|
||||
const bool _Scheduler_SMP_Node_valid_state_changes[ 3 ][ 3 ] = {
|
||||
/* FROM / TO BLOCKED SCHEDULED READY */
|
||||
/* BLOCKED */ { false, true, true },
|
||||
/* BLOCKED */ { true, true, true },
|
||||
/* SCHEDULED */ { true, false, true },
|
||||
/* READY */ { true, true, false }
|
||||
};
|
||||
|
||||
@@ -355,6 +355,25 @@ Thread_Control *_Scheduler_strong_APA_Unblock(
|
||||
);
|
||||
}
|
||||
|
||||
static bool _Scheduler_strong_APA_Do_ask_for_help(
|
||||
Scheduler_Context *context,
|
||||
Thread_Control *the_thread,
|
||||
Scheduler_Node *node
|
||||
)
|
||||
{
|
||||
return _Scheduler_SMP_Ask_for_help(
|
||||
context,
|
||||
the_thread,
|
||||
node,
|
||||
_Scheduler_SMP_Insert_priority_lifo_order,
|
||||
_Scheduler_strong_APA_Insert_ready_lifo,
|
||||
_Scheduler_SMP_Insert_scheduled_lifo,
|
||||
_Scheduler_strong_APA_Move_from_scheduled_to_ready,
|
||||
_Scheduler_SMP_Get_lowest_scheduled,
|
||||
_Scheduler_SMP_Allocate_processor_lazy
|
||||
);
|
||||
}
|
||||
|
||||
Thread_Control *_Scheduler_strong_APA_Update_priority(
|
||||
const Scheduler_Control *scheduler,
|
||||
Thread_Control *the_thread,
|
||||
@@ -372,7 +391,56 @@ Thread_Control *_Scheduler_strong_APA_Update_priority(
|
||||
_Scheduler_strong_APA_Enqueue_fifo,
|
||||
_Scheduler_strong_APA_Enqueue_lifo,
|
||||
_Scheduler_strong_APA_Enqueue_scheduled_fifo,
|
||||
_Scheduler_strong_APA_Enqueue_scheduled_lifo
|
||||
_Scheduler_strong_APA_Enqueue_scheduled_lifo,
|
||||
_Scheduler_strong_APA_Do_ask_for_help
|
||||
);
|
||||
}
|
||||
|
||||
bool _Scheduler_strong_APA_Ask_for_help(
|
||||
const Scheduler_Control *scheduler,
|
||||
Thread_Control *the_thread,
|
||||
Scheduler_Node *node
|
||||
)
|
||||
{
|
||||
Scheduler_Context *context = _Scheduler_Get_context( scheduler );
|
||||
|
||||
return _Scheduler_strong_APA_Do_ask_for_help( context, the_thread, node );
|
||||
}
|
||||
|
||||
void _Scheduler_strong_APA_Reconsider_help_request(
|
||||
const Scheduler_Control *scheduler,
|
||||
Thread_Control *the_thread,
|
||||
Scheduler_Node *node
|
||||
)
|
||||
{
|
||||
Scheduler_Context *context = _Scheduler_Get_context( scheduler );
|
||||
|
||||
_Scheduler_SMP_Reconsider_help_request(
|
||||
context,
|
||||
the_thread,
|
||||
node,
|
||||
_Scheduler_strong_APA_Extract_from_ready
|
||||
);
|
||||
}
|
||||
|
||||
void _Scheduler_strong_APA_Withdraw_node(
|
||||
const Scheduler_Control *scheduler,
|
||||
Thread_Control *the_thread,
|
||||
Scheduler_Node *node,
|
||||
Thread_Scheduler_state next_state
|
||||
)
|
||||
{
|
||||
Scheduler_Context *context = _Scheduler_Get_context( scheduler );
|
||||
|
||||
_Scheduler_SMP_Withdraw_node(
|
||||
context,
|
||||
the_thread,
|
||||
node,
|
||||
next_state,
|
||||
_Scheduler_strong_APA_Extract_from_ready,
|
||||
_Scheduler_strong_APA_Get_highest_ready,
|
||||
_Scheduler_strong_APA_Move_from_ready_to_scheduled,
|
||||
_Scheduler_SMP_Allocate_processor_lazy
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@@ -89,6 +89,7 @@ void _SMP_Handler_initialize( void )
|
||||
_ISR_lock_Initialize( &cpu->Watchdog.Lock, "Watchdog" );
|
||||
_SMP_ticket_lock_Initialize( &cpu->Lock );
|
||||
_SMP_lock_Stats_initialize( &cpu->Lock_stats, "Per-CPU" );
|
||||
_Chain_Initialize_empty( &cpu->Threads_in_need_for_help );
|
||||
}
|
||||
|
||||
/*
|
||||
|
||||
@@ -23,6 +23,7 @@
|
||||
#include <rtems/score/threaddispatch.h>
|
||||
#include <rtems/score/assert.h>
|
||||
#include <rtems/score/isr.h>
|
||||
#include <rtems/score/schedulerimpl.h>
|
||||
#include <rtems/score/threadimpl.h>
|
||||
#include <rtems/score/todimpl.h>
|
||||
#include <rtems/score/userextimpl.h>
|
||||
@@ -39,6 +40,77 @@ Thread_Control *_Thread_Allocated_fp;
|
||||
|
||||
CHAIN_DEFINE_EMPTY( _User_extensions_Switches_list );
|
||||
|
||||
#if defined(RTEMS_SMP)
|
||||
static bool _Thread_Can_ask_for_help( const Thread_Control *executing )
|
||||
{
|
||||
return executing->Scheduler.helping_nodes > 0
|
||||
&& _Thread_Is_ready( executing );
|
||||
}
|
||||
#endif
|
||||
|
||||
static void _Thread_Preemption_intervention( Per_CPU_Control *cpu_self )
|
||||
{
|
||||
#if defined(RTEMS_SMP)
|
||||
_Per_CPU_Acquire( cpu_self );
|
||||
|
||||
while ( !_Chain_Is_empty( &cpu_self->Threads_in_need_for_help ) ) {
|
||||
Chain_Node *node;
|
||||
Thread_Control *the_thread;
|
||||
ISR_lock_Context lock_context;
|
||||
|
||||
node = _Chain_Get_first_unprotected( &cpu_self->Threads_in_need_for_help );
|
||||
_Chain_Set_off_chain( node );
|
||||
the_thread = THREAD_OF_SCHEDULER_HELP_NODE( node );
|
||||
|
||||
_Per_CPU_Release( cpu_self );
|
||||
_Thread_State_acquire( the_thread, &lock_context );
|
||||
_Thread_Scheduler_ask_for_help( the_thread );
|
||||
_Thread_State_release( the_thread, &lock_context );
|
||||
_Per_CPU_Acquire( cpu_self );
|
||||
}
|
||||
|
||||
_Per_CPU_Release( cpu_self );
|
||||
#else
|
||||
(void) cpu_self;
|
||||
#endif
|
||||
}
|
||||
|
||||
static void _Thread_Post_switch_cleanup( Thread_Control *executing )
|
||||
{
|
||||
#if defined(RTEMS_SMP)
|
||||
Chain_Node *node;
|
||||
const Chain_Node *tail;
|
||||
|
||||
if ( !_Thread_Can_ask_for_help( executing ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
node = _Chain_First( &executing->Scheduler.Scheduler_nodes );
|
||||
tail = _Chain_Immutable_tail( &executing->Scheduler.Scheduler_nodes );
|
||||
|
||||
do {
|
||||
Scheduler_Node *scheduler_node;
|
||||
const Scheduler_Control *scheduler;
|
||||
ISR_lock_Context lock_context;
|
||||
|
||||
scheduler_node = SCHEDULER_NODE_OF_THREAD_SCHEDULER_NODE( node );
|
||||
scheduler = _Scheduler_Node_get_scheduler( scheduler_node );
|
||||
|
||||
_Scheduler_Acquire_critical( scheduler, &lock_context );
|
||||
( *scheduler->Operations.reconsider_help_request )(
|
||||
scheduler,
|
||||
executing,
|
||||
scheduler_node
|
||||
);
|
||||
_Scheduler_Release_critical( scheduler, &lock_context );
|
||||
|
||||
node = _Chain_Next( node );
|
||||
} while ( node != tail );
|
||||
#else
|
||||
(void) executing;
|
||||
#endif
|
||||
}
|
||||
|
||||
static Thread_Action *_Thread_Get_post_switch_action(
|
||||
Thread_Control *executing
|
||||
)
|
||||
@@ -54,6 +126,7 @@ static void _Thread_Run_post_switch_actions( Thread_Control *executing )
|
||||
Thread_Action *action;
|
||||
|
||||
_Thread_State_acquire( executing, &lock_context );
|
||||
_Thread_Post_switch_cleanup( executing );
|
||||
action = _Thread_Get_post_switch_action( executing );
|
||||
|
||||
while ( action != NULL ) {
|
||||
@@ -77,7 +150,10 @@ void _Thread_Do_dispatch( Per_CPU_Control *cpu_self, ISR_Level level )
|
||||
executing = cpu_self->executing;
|
||||
|
||||
do {
|
||||
Thread_Control *heir = _Thread_Get_heir_and_make_it_executing( cpu_self );
|
||||
Thread_Control *heir;
|
||||
|
||||
_Thread_Preemption_intervention( cpu_self );
|
||||
heir = _Thread_Get_heir_and_make_it_executing( cpu_self );
|
||||
|
||||
/*
|
||||
* When the heir and executing are the same, then we are being
|
||||
|
||||
@@ -20,6 +20,39 @@
|
||||
#include <rtems/score/schedulerimpl.h>
|
||||
|
||||
#if defined(RTEMS_SMP)
|
||||
void _Thread_Scheduler_ask_for_help( Thread_Control *the_thread )
|
||||
{
|
||||
Chain_Node *node;
|
||||
const Chain_Node *tail;
|
||||
|
||||
node = _Chain_First( &the_thread->Scheduler.Scheduler_nodes );
|
||||
tail = _Chain_Immutable_tail( &the_thread->Scheduler.Scheduler_nodes );
|
||||
|
||||
do {
|
||||
Scheduler_Node *scheduler_node;
|
||||
const Scheduler_Control *scheduler;
|
||||
ISR_lock_Context lock_context;
|
||||
bool success;
|
||||
|
||||
scheduler_node = SCHEDULER_NODE_OF_THREAD_SCHEDULER_NODE( node );
|
||||
scheduler = _Scheduler_Node_get_scheduler( scheduler_node );
|
||||
|
||||
_Scheduler_Acquire_critical( scheduler, &lock_context );
|
||||
success = ( *scheduler->Operations.ask_for_help )(
|
||||
scheduler,
|
||||
the_thread,
|
||||
scheduler_node
|
||||
);
|
||||
_Scheduler_Release_critical( scheduler, &lock_context );
|
||||
|
||||
if ( success ) {
|
||||
break;
|
||||
}
|
||||
|
||||
node = _Chain_Next( node );
|
||||
} while ( node != tail );
|
||||
}
|
||||
|
||||
void _Thread_Scheduler_process_requests( Thread_Control *the_thread )
|
||||
{
|
||||
ISR_lock_Context lock_context;
|
||||
@@ -48,11 +81,13 @@ void _Thread_Scheduler_process_requests( Thread_Control *the_thread )
|
||||
#endif
|
||||
|
||||
if ( request == SCHEDULER_NODE_REQUEST_ADD ) {
|
||||
++the_thread->Scheduler.helping_nodes;
|
||||
_Chain_Append_unprotected(
|
||||
&the_thread->Scheduler.Scheduler_nodes,
|
||||
&scheduler_node->Thread.Scheduler_node.Chain
|
||||
);
|
||||
} else if ( request == SCHEDULER_NODE_REQUEST_REMOVE ) {
|
||||
--the_thread->Scheduler.helping_nodes;
|
||||
_Chain_Extract_unprotected(
|
||||
&scheduler_node->Thread.Scheduler_node.Chain
|
||||
);
|
||||
@@ -70,11 +105,25 @@ void _Thread_Scheduler_process_requests( Thread_Control *the_thread )
|
||||
scheduler_node = remove;
|
||||
|
||||
while ( scheduler_node != NULL ) {
|
||||
const Scheduler_Control *scheduler;
|
||||
ISR_lock_Context lock_context;
|
||||
|
||||
next = scheduler_node->Thread.Scheduler_node.next;
|
||||
#if defined(RTEMS_DEBUG)
|
||||
scheduler_node->Thread.Scheduler_node.next = NULL;
|
||||
#endif
|
||||
|
||||
scheduler = _Scheduler_Node_get_scheduler( scheduler_node );
|
||||
|
||||
_Scheduler_Acquire_critical( scheduler, &lock_context );
|
||||
( *scheduler->Operations.withdraw_node )(
|
||||
scheduler,
|
||||
the_thread,
|
||||
scheduler_node,
|
||||
THREAD_SCHEDULER_READY
|
||||
);
|
||||
_Scheduler_Release_critical( scheduler, &lock_context );
|
||||
|
||||
scheduler_node = next;
|
||||
}
|
||||
} else {
|
||||
|
||||
@@ -42,7 +42,11 @@ typedef enum {
|
||||
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
|
||||
REQ_SEM_RELEASE = RTEMS_EVENT_8,
|
||||
REQ_SET_DONE = RTEMS_EVENT_9,
|
||||
REQ_WAIT_FOR_DONE = RTEMS_EVENT_10,
|
||||
REQ_SEND_EVENT_2 = RTEMS_EVENT_11,
|
||||
REQ_SEND_EVENT_3 = RTEMS_EVENT_12
|
||||
} request_id;
|
||||
|
||||
typedef enum {
|
||||
@@ -63,12 +67,22 @@ typedef struct {
|
||||
rtems_id mtx_2;
|
||||
rtems_id sem;
|
||||
rtems_id tasks[TASK_COUNT];
|
||||
Atomic_Uint done;
|
||||
task_id id_2;
|
||||
rtems_event_set events_2;
|
||||
task_id id_3;
|
||||
rtems_event_set events_3;
|
||||
int generation[TASK_COUNT];
|
||||
int expected_generation[TASK_COUNT];
|
||||
} test_context;
|
||||
|
||||
static test_context test_instance;
|
||||
|
||||
static void assert_cpu(uint32_t expected_cpu)
|
||||
{
|
||||
rtems_test_assert(rtems_get_current_processor() == expected_cpu);
|
||||
}
|
||||
|
||||
static void test_task_get_priority_not_defined(test_context *ctx)
|
||||
{
|
||||
rtems_status_code sc;
|
||||
@@ -123,6 +137,55 @@ static void send_event(test_context *ctx, task_id id, rtems_event_set events)
|
||||
rtems_test_assert(sc == RTEMS_SUCCESSFUL);
|
||||
}
|
||||
|
||||
static void set_event_2(
|
||||
test_context *ctx,
|
||||
task_id id_2,
|
||||
rtems_event_set events_2
|
||||
)
|
||||
{
|
||||
ctx->id_2 = id_2;
|
||||
ctx->events_2 = events_2;
|
||||
}
|
||||
|
||||
static void set_event_3(
|
||||
test_context *ctx,
|
||||
task_id id_3,
|
||||
rtems_event_set events_3
|
||||
)
|
||||
{
|
||||
ctx->id_3 = id_3;
|
||||
ctx->events_3 = events_3;
|
||||
}
|
||||
|
||||
static void clear_done(test_context *ctx)
|
||||
{
|
||||
_Atomic_Store_uint(&ctx->done, 0, ATOMIC_ORDER_RELAXED);
|
||||
}
|
||||
|
||||
static void set_done(test_context *ctx)
|
||||
{
|
||||
_Atomic_Store_uint(&ctx->done, 1, ATOMIC_ORDER_RELEASE);
|
||||
}
|
||||
|
||||
static bool is_done(test_context *ctx)
|
||||
{
|
||||
return _Atomic_Load_uint(&ctx->done, ATOMIC_ORDER_ACQUIRE) != 0;
|
||||
}
|
||||
|
||||
static void wait_for_done(test_context *ctx)
|
||||
{
|
||||
while (!is_done(ctx)) {
|
||||
/* Wait */
|
||||
}
|
||||
}
|
||||
|
||||
static void request_pre_emption(test_context *ctx, task_id id)
|
||||
{
|
||||
clear_done(ctx);
|
||||
send_event(ctx, id, REQ_SET_DONE);
|
||||
wait_for_done(ctx);
|
||||
}
|
||||
|
||||
static rtems_event_set wait_for_events(void)
|
||||
{
|
||||
rtems_event_set events;
|
||||
@@ -157,7 +220,16 @@ static void sync_with_helper(test_context *ctx)
|
||||
static void request(test_context *ctx, task_id id, request_id req)
|
||||
{
|
||||
send_event(ctx, id, req);
|
||||
sync_with_helper(ctx);
|
||||
clear_done(ctx);
|
||||
|
||||
if (rtems_get_current_processor() == 0) {
|
||||
id = H_B;
|
||||
} else {
|
||||
id = H_A;
|
||||
}
|
||||
|
||||
send_event(ctx, id, REQ_SET_DONE);
|
||||
wait_for_done(ctx);
|
||||
}
|
||||
|
||||
static void obtain(test_context *ctx)
|
||||
@@ -241,6 +313,14 @@ static void check_generations(test_context *ctx, task_id a, task_id b)
|
||||
}
|
||||
}
|
||||
|
||||
static void set_prio(test_context *ctx, task_id id, rtems_task_priority prio)
|
||||
{
|
||||
rtems_status_code sc;
|
||||
|
||||
sc = rtems_task_set_priority(ctx->tasks[id], prio, &prio);
|
||||
rtems_test_assert(sc == RTEMS_SUCCESSFUL);
|
||||
}
|
||||
|
||||
static void assert_prio(
|
||||
test_context *ctx,
|
||||
task_id id,
|
||||
@@ -303,6 +383,10 @@ static void helper(rtems_task_argument arg)
|
||||
if ((events & REQ_SEM_RELEASE) != 0) {
|
||||
sem_release(ctx);
|
||||
}
|
||||
|
||||
if ((events & REQ_SET_DONE) != 0) {
|
||||
set_done(ctx);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -344,6 +428,22 @@ static void worker(rtems_task_argument arg)
|
||||
++ctx->generation[id];
|
||||
sem_release(ctx);
|
||||
}
|
||||
|
||||
if ((events & REQ_SEND_EVENT_2) != 0) {
|
||||
send_event(ctx, ctx->id_2, ctx->events_2);
|
||||
}
|
||||
|
||||
if ((events & REQ_SEND_EVENT_3) != 0) {
|
||||
send_event(ctx, ctx->id_3, ctx->events_3);
|
||||
}
|
||||
|
||||
if ((events & REQ_SET_DONE) != 0) {
|
||||
set_done(ctx);
|
||||
}
|
||||
|
||||
if ((events & REQ_WAIT_FOR_DONE) != 0) {
|
||||
wait_for_done(ctx);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -672,6 +772,92 @@ static void test_dequeue_order_two_scheduler_instances(test_context *ctx)
|
||||
check_generations(ctx, B_5_1, NONE);
|
||||
}
|
||||
|
||||
static void test_omip_pre_emption(test_context *ctx)
|
||||
{
|
||||
assert_cpu(0);
|
||||
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);
|
||||
check_generations(ctx, NONE, NONE);
|
||||
|
||||
request_pre_emption(ctx, A_1);
|
||||
assert_cpu(1);
|
||||
|
||||
request_pre_emption(ctx, B_4);
|
||||
assert_cpu(0);
|
||||
|
||||
request_pre_emption(ctx, A_1);
|
||||
assert_cpu(1);
|
||||
|
||||
release(ctx);
|
||||
assert_cpu(0);
|
||||
sync_with_helper(ctx);
|
||||
assert_prio_by_scheduler(ctx, M, SCHED_A, 3);
|
||||
assert_prio_by_scheduler(ctx, M, SCHED_B, PRIO_NONE);
|
||||
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_5_0, NONE);
|
||||
}
|
||||
|
||||
static void test_omip_rescue(test_context *ctx)
|
||||
{
|
||||
assert_cpu(0);
|
||||
obtain(ctx);
|
||||
assert_prio_by_scheduler(ctx, M, SCHED_A, 3);
|
||||
assert_prio_by_scheduler(ctx, M, SCHED_B, PRIO_NONE);
|
||||
|
||||
clear_done(ctx);
|
||||
set_event_3(ctx, H_B, REQ_SET_DONE);
|
||||
set_event_2(ctx, B_5_0, REQ_SEND_EVENT_3 | REQ_MTX_OBTAIN);
|
||||
send_event(ctx, A_1, REQ_SEND_EVENT_2 | REQ_WAIT_FOR_DONE);
|
||||
assert_prio_by_scheduler(ctx, M, SCHED_A, 3);
|
||||
assert_prio_by_scheduler(ctx, M, SCHED_B, 5);
|
||||
assert_cpu(1);
|
||||
|
||||
release(ctx);
|
||||
assert_cpu(0);
|
||||
sync_with_helper(ctx);
|
||||
assert_prio_by_scheduler(ctx, M, SCHED_A, 3);
|
||||
assert_prio_by_scheduler(ctx, M, SCHED_B, PRIO_NONE);
|
||||
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_5_0, NONE);
|
||||
}
|
||||
|
||||
static void test_omip_timeout(test_context *ctx)
|
||||
{
|
||||
assert_cpu(0);
|
||||
obtain(ctx);
|
||||
assert_prio_by_scheduler(ctx, M, SCHED_A, 3);
|
||||
assert_prio_by_scheduler(ctx, M, SCHED_B, PRIO_NONE);
|
||||
|
||||
clear_done(ctx);
|
||||
set_event_3(ctx, H_B, REQ_SET_DONE);
|
||||
set_event_2(ctx, B_5_0, REQ_SEND_EVENT_3 | REQ_MTX_OBTAIN_TIMEOUT);
|
||||
send_event(ctx, A_1, REQ_SEND_EVENT_2 | REQ_WAIT_FOR_DONE);
|
||||
assert_prio_by_scheduler(ctx, M, SCHED_A, 3);
|
||||
assert_prio_by_scheduler(ctx, M, SCHED_B, 5);
|
||||
assert_cpu(1);
|
||||
|
||||
wait();
|
||||
assert_prio_by_scheduler(ctx, M, SCHED_A, 3);
|
||||
assert_prio_by_scheduler(ctx, M, SCHED_B, PRIO_NONE);
|
||||
check_generations(ctx, B_5_0, NONE);
|
||||
assert_cpu(0);
|
||||
|
||||
release(ctx);
|
||||
}
|
||||
|
||||
static void test(void)
|
||||
{
|
||||
test_context *ctx = &test_instance;
|
||||
@@ -685,6 +871,9 @@ static void test(void)
|
||||
test_simple_inheritance_two_scheduler_instances(ctx);
|
||||
test_nested_inheritance_two_scheduler_instances(ctx);
|
||||
test_dequeue_order_two_scheduler_instances(ctx);
|
||||
test_omip_pre_emption(ctx);
|
||||
test_omip_rescue(ctx);
|
||||
test_omip_timeout(ctx);
|
||||
}
|
||||
|
||||
static void Init(rtems_task_argument arg)
|
||||
|
||||
Reference in New Issue
Block a user