score: Fine grained locking for MrsP

Update #2273.
This commit is contained in:
Sebastian Huber
2015-05-07 14:02:46 +02:00
parent 80f376db6c
commit a816f08478
5 changed files with 124 additions and 61 deletions

View File

@@ -59,16 +59,13 @@ rtems_status_code rtems_semaphore_obtain(
if ( _Attributes_Is_multiprocessor_resource_sharing( attribute_set ) ) {
MRSP_Status mrsp_status;
_Thread_Disable_dispatch();
_ISR_lock_ISR_enable( &lock_context );
mrsp_status = _MRSP_Obtain(
&the_semaphore->Core_control.mrsp,
executing,
wait,
timeout
timeout,
&lock_context
);
_Thread_Enable_dispatch();
_Objects_Put_for_get_isr_disable( &the_semaphore->Object );
return _Semaphore_Translate_MRSP_status_code( mrsp_status );
} else
#endif

View File

@@ -75,13 +75,13 @@ rtems_status_code rtems_semaphore_release(
attribute_set = the_semaphore->attribute_set;
#if defined(RTEMS_SMP)
if ( _Attributes_Is_multiprocessor_resource_sharing( attribute_set ) ) {
_Thread_Disable_dispatch();
_ISR_lock_ISR_enable( &lock_context );
MRSP_Status mrsp_status = _MRSP_Release(
MRSP_Status mrsp_status;
mrsp_status = _MRSP_Release(
&the_semaphore->Core_control.mrsp,
_Thread_Get_executing()
_Thread_Executing,
&lock_context
);
_Thread_Enable_dispatch();
return _Semaphore_Translate_MRSP_status_code( mrsp_status );
} else
#endif

View File

@@ -20,6 +20,7 @@
#if defined(RTEMS_SMP)
#include <rtems/score/chain.h>
#include <rtems/score/isrlock.h>
#include <rtems/score/scheduler.h>
#include <rtems/score/thread.h>
@@ -75,23 +76,29 @@ typedef enum {
MRSP_WAIT_FOR_OWNERSHIP = 255
} MRSP_Status;
typedef struct MRSP_Control MRSP_Control;
/**
* @brief MrsP rival.
*
* The rivals are used by threads waiting for resource ownership. They are
* registered in the MRSP control block.
* registered in the MrsP control block.
*/
typedef struct {
/**
* @brief The node for registration in the MRSP rival chain.
* @brief The node for registration in the MrsP rival chain.
*
* The chain operations are protected by the Giant lock and disabled
* interrupts.
* The chain operations are protected by the MrsP control lock.
*
* @see MRSP_Control::Rivals.
*/
Chain_Node Node;
/**
* @brief The corresponding MrsP control block.
*/
MRSP_Control *resource;
/**
* @brief Identification of the rival thread.
*/
@@ -118,8 +125,7 @@ typedef struct {
*
* Initially the status is set to MRSP_WAIT_FOR_OWNERSHIP. The rival will
* busy wait until a status change happens. This can be MRSP_SUCCESSFUL or
* MRSP_TIMEOUT. State changes are protected by the Giant lock and disabled
* interrupts.
* MRSP_TIMEOUT. State changes are protected by the MrsP control lock.
*/
volatile MRSP_Status status;
} MRSP_Rival;
@@ -127,7 +133,7 @@ typedef struct {
/**
* @brief MrsP control block.
*/
typedef struct {
struct MRSP_Control {
/**
* @brief Basic resource control.
*/
@@ -140,6 +146,11 @@ typedef struct {
*/
Chain_Control Rivals;
/**
* @brief Lock to protect the resource dependency tree.
*/
ISR_LOCK_MEMBER( Lock )
/**
* @brief The initial priority of the owner before it was elevated to the
* ceiling priority.
@@ -150,7 +161,7 @@ typedef struct {
* @brief One ceiling priority per scheduler instance.
*/
Priority_Control *ceiling_priorities;
} MRSP_Control;
};
/** @} */

View File

@@ -36,6 +36,23 @@ extern "C" {
* @{
*/
/*
* FIXME: Operations with the resource dependency tree are protected by the
* global scheduler lock. Since the scheduler lock should be scheduler
* instance specific in the future this will only work temporarily. A more
* sophisticated locking strategy is necessary.
*/
RTEMS_INLINE_ROUTINE void _MRSP_Giant_acquire( ISR_lock_Context *lock_context )
{
_ISR_lock_Acquire( &_Scheduler_Lock, lock_context );
}
RTEMS_INLINE_ROUTINE void _MRSP_Giant_release( ISR_lock_Context *lock_context )
{
_ISR_lock_Release( &_Scheduler_Lock, lock_context );
}
RTEMS_INLINE_ROUTINE bool _MRSP_Restore_priority_filter(
Thread_Control *thread,
Priority_Control *new_priority,
@@ -74,14 +91,23 @@ RTEMS_INLINE_ROUTINE void _MRSP_Claim_ownership(
MRSP_Control *mrsp,
Thread_Control *new_owner,
Priority_Control initial_priority,
Priority_Control ceiling_priority
Priority_Control ceiling_priority,
ISR_lock_Context *lock_context
)
{
Per_CPU_Control *cpu_self;
_Resource_Node_add_resource( &new_owner->Resource_node, &mrsp->Resource );
_Resource_Set_owner( &mrsp->Resource, &new_owner->Resource_node );
mrsp->initial_priority_of_owner = initial_priority;
_Thread_Raise_priority( new_owner, ceiling_priority );
_Scheduler_Thread_change_help_state( new_owner, SCHEDULER_HELP_ACTIVE_OWNER );
cpu_self = _Thread_Dispatch_disable_critical();
_ISR_lock_Release_and_ISR_enable( &mrsp->Lock, lock_context );
_Thread_Raise_priority( new_owner, ceiling_priority );
_Thread_Dispatch_enable( cpu_self );
}
RTEMS_INLINE_ROUTINE MRSP_Status _MRSP_Initialize(
@@ -111,6 +137,7 @@ RTEMS_INLINE_ROUTINE MRSP_Status _MRSP_Initialize(
_Resource_Initialize( &mrsp->Resource );
_Chain_Initialize_empty( &mrsp->Rivals );
_ISR_lock_Initialize( &mrsp->Lock, "MrsP" );
return MRSP_SUCCESSFUL;
}
@@ -138,27 +165,32 @@ RTEMS_INLINE_ROUTINE void _MRSP_Timeout(
)
{
MRSP_Rival *rival = arg;
MRSP_Control *mrsp = rival->resource;
Thread_Control *thread = rival->thread;
ISR_Level level;
ISR_lock_Context lock_context;
(void) id;
_ISR_Disable( level );
_ISR_lock_ISR_disable_and_acquire( &mrsp->Lock, &lock_context );
if ( rival->status == MRSP_WAIT_FOR_OWNERSHIP ) {
rival->status = MRSP_TIMEOUT;
ISR_lock_Context giant_lock_context;
_MRSP_Giant_acquire( &giant_lock_context );
_Chain_Extract_unprotected( &rival->Node );
_Resource_Node_extract( &thread->Resource_node );
_Resource_Node_set_dependency( &thread->Resource_node, NULL );
_ISR_Enable( level );
_Scheduler_Thread_change_help_state( thread, rival->initial_help_state );
_Scheduler_Thread_change_resource_root( thread, thread );
_MRSP_Restore_priority( thread, rival->initial_priority );
_MRSP_Giant_release( &giant_lock_context );
rival->status = MRSP_TIMEOUT;
_ISR_lock_Release_and_ISR_enable( &mrsp->Lock, &lock_context );
} else {
_ISR_Enable( level );
_ISR_lock_Release_and_ISR_enable( &mrsp->Lock, &lock_context );
}
}
@@ -168,35 +200,41 @@ RTEMS_INLINE_ROUTINE MRSP_Status _MRSP_Wait_for_ownership(
Thread_Control *executing,
Priority_Control initial_priority,
Priority_Control ceiling_priority,
Watchdog_Interval timeout
Watchdog_Interval timeout,
ISR_lock_Context *lock_context
)
{
MRSP_Status status;
MRSP_Rival rival;
bool initial_life_protection;
ISR_Level level;
Per_CPU_Control *cpu_self;
ISR_lock_Context giant_lock_context;
rival.thread = executing;
rival.resource = mrsp;
rival.initial_priority = initial_priority;
_MRSP_Giant_acquire( &giant_lock_context );
rival.initial_help_state =
_Scheduler_Thread_change_help_state( executing, SCHEDULER_HELP_ACTIVE_RIVAL );
rival.status = MRSP_WAIT_FOR_OWNERSHIP;
_Thread_Raise_priority( executing, ceiling_priority );
_ISR_Disable( level );
_Chain_Append_unprotected( &mrsp->Rivals, &rival.Node );
_Resource_Add_rival( &mrsp->Resource, &executing->Resource_node );
_Resource_Node_set_dependency( &executing->Resource_node, &mrsp->Resource );
_ISR_Enable( level );
_Scheduler_Thread_change_resource_root(
executing,
THREAD_RESOURCE_NODE_TO_THREAD( _Resource_Node_get_root( owner ) )
);
_MRSP_Giant_release( &giant_lock_context );
cpu_self = _Thread_Dispatch_disable_critical();
_ISR_lock_Release_and_ISR_enable( &mrsp->Lock, lock_context );
_Thread_Raise_priority( executing, ceiling_priority );
if ( timeout > 0 ) {
_Watchdog_Initialize(
&executing->Timer,
@@ -208,7 +246,7 @@ RTEMS_INLINE_ROUTINE MRSP_Status _MRSP_Wait_for_ownership(
}
initial_life_protection = _Thread_Set_life_protection( true );
_Thread_Enable_dispatch();
_Thread_Dispatch_enable( cpu_self );
_Assert( _Debug_Is_thread_dispatching_allowed() );
@@ -217,11 +255,14 @@ RTEMS_INLINE_ROUTINE MRSP_Status _MRSP_Wait_for_ownership(
status = rival.status;
} while ( status == MRSP_WAIT_FOR_OWNERSHIP );
_Thread_Disable_dispatch();
_Thread_Set_life_protection( initial_life_protection );
if ( timeout > 0 ) {
_Watchdog_Remove_ticks( &executing->Timer );
if ( status == MRSP_TIMEOUT ) {
_MRSP_Restore_priority( executing, initial_priority );
}
}
return status;
@@ -231,7 +272,8 @@ RTEMS_INLINE_ROUTINE MRSP_Status _MRSP_Obtain(
MRSP_Control *mrsp,
Thread_Control *executing,
bool wait,
Watchdog_Interval timeout
Watchdog_Interval timeout,
ISR_lock_Context *lock_context
)
{
MRSP_Status status;
@@ -247,31 +289,37 @@ RTEMS_INLINE_ROUTINE MRSP_Status _MRSP_Obtain(
Resource_Node *owner;
if ( !priority_ok) {
_ISR_lock_ISR_enable( lock_context );
return MRSP_INVALID_PRIORITY;
}
_ISR_lock_Acquire( &mrsp->Lock, lock_context );
owner = _Resource_Get_owner( &mrsp->Resource );
if ( owner == NULL ) {
_MRSP_Claim_ownership(
mrsp,
executing,
initial_priority,
ceiling_priority
ceiling_priority,
lock_context
);
status = MRSP_SUCCESSFUL;
} else if ( _Resource_Node_get_root( owner ) == &executing->Resource_node ) {
/* Nested access or deadlock */
status = MRSP_UNSATISFIED;
} else if ( wait ) {
} else if (
wait
&& _Resource_Node_get_root( owner ) != &executing->Resource_node
) {
status = _MRSP_Wait_for_ownership(
mrsp,
owner,
executing,
initial_priority,
ceiling_priority,
timeout
timeout,
lock_context
);
} else {
_ISR_lock_Release_and_ISR_enable( &mrsp->Lock, lock_context );
/* Not available, nested access or deadlock */
status = MRSP_UNSATISFIED;
}
@@ -279,13 +327,17 @@ RTEMS_INLINE_ROUTINE MRSP_Status _MRSP_Obtain(
}
RTEMS_INLINE_ROUTINE MRSP_Status _MRSP_Release(
MRSP_Control *mrsp,
Thread_Control *executing
MRSP_Control *mrsp,
Thread_Control *executing,
ISR_lock_Context *lock_context
)
{
ISR_Level level;
Priority_Control initial_priority;
Per_CPU_Control *cpu_self;
ISR_lock_Context giant_lock_context;
if ( _Resource_Get_owner( &mrsp->Resource ) != &executing->Resource_node ) {
_ISR_lock_ISR_enable( lock_context );
return MRSP_NOT_OWNER_OF_RESOURCE;
}
@@ -295,18 +347,19 @@ RTEMS_INLINE_ROUTINE MRSP_Status _MRSP_Release(
&executing->Resource_node
)
) {
_ISR_lock_ISR_enable( lock_context );
return MRSP_INCORRECT_STATE;
}
_MRSP_Restore_priority( executing, mrsp->initial_priority_of_owner );
initial_priority = mrsp->initial_priority_of_owner;
_ISR_Disable( level );
_ISR_lock_Acquire( &mrsp->Lock, lock_context );
_MRSP_Giant_acquire( &giant_lock_context );
_Resource_Extract( &mrsp->Resource );
if ( _Chain_Is_empty( &mrsp->Rivals ) ) {
_ISR_Enable( level );
_Resource_Set_owner( &mrsp->Resource, NULL );
} else {
MRSP_Rival *rival = (MRSP_Rival *)
@@ -325,9 +378,6 @@ RTEMS_INLINE_ROUTINE MRSP_Status _MRSP_Release(
_Resource_Node_set_dependency( &new_owner->Resource_node, NULL );
_Resource_Node_add_resource( &new_owner->Resource_node, &mrsp->Resource );
_Resource_Set_owner( &mrsp->Resource, &new_owner->Resource_node );
_ISR_Enable( level );
_Scheduler_Thread_change_help_state( new_owner, SCHEDULER_HELP_ACTIVE_OWNER );
_Scheduler_Thread_change_resource_root( new_owner, new_owner );
}
@@ -336,6 +386,15 @@ RTEMS_INLINE_ROUTINE MRSP_Status _MRSP_Release(
_Scheduler_Thread_change_help_state( executing, SCHEDULER_HELP_YOURSELF );
}
_MRSP_Giant_release( &giant_lock_context );
cpu_self = _Thread_Dispatch_disable_critical();
_ISR_lock_Release_and_ISR_enable( &mrsp->Lock, lock_context );
_MRSP_Restore_priority( executing, initial_priority );
_Thread_Dispatch_enable( cpu_self );
return MRSP_SUCCESSFUL;
}
@@ -345,6 +404,7 @@ RTEMS_INLINE_ROUTINE MRSP_Status _MRSP_Destroy( MRSP_Control *mrsp )
return MRSP_RESOUCE_IN_USE;
}
_ISR_lock_Destroy( &mrsp->Lock );
_Workspace_Free( mrsp->ceiling_priorities );
return MRSP_SUCCESSFUL;

View File

@@ -61,9 +61,6 @@ void _Scheduler_Thread_change_resource_root(
Thread_Control *offers_help = top;
Scheduler_Node *offers_help_node;
Thread_Control *offers_help_too;
ISR_Level level;
_ISR_Disable( level );
offers_help_node = _Scheduler_Thread_get_node( offers_help );
offers_help_too = _Scheduler_Node_get_owner( offers_help_node );
@@ -80,6 +77,4 @@ void _Scheduler_Thread_change_resource_root(
if ( ctx.needs_help != NULL ) {
_Scheduler_Ask_for_help( ctx.needs_help );
}
_ISR_Enable( level );
}