mirror of
https://gitlab.rtems.org/rtems/rtos/rtems.git
synced 2026-08-27 15:46:16 +08:00
score: Fix scheduler helping protocol
Account for priority changes of threads executing in a foreign partition. Exchange idle threads in case a victim node uses an idle thread and the new scheduled node needs an idle thread.
This commit is contained in:
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2014 embedded brains GmbH. All rights reserved.
|
||||
* Copyright (c) 2014-2015 embedded brains GmbH. All rights reserved.
|
||||
*
|
||||
* embedded brains GmbH
|
||||
* Dornierstr. 4
|
||||
@@ -230,7 +230,7 @@ RTEMS_INLINE_ROUTINE MRSP_Status _MRSP_Obtain(
|
||||
)
|
||||
{
|
||||
MRSP_Status status;
|
||||
const Scheduler_Control *scheduler = _Scheduler_Get( executing );
|
||||
const Scheduler_Control *scheduler = _Scheduler_Get_own( executing );
|
||||
uint32_t scheduler_index = _Scheduler_Get_index( scheduler );
|
||||
Priority_Control initial_priority = executing->current_priority;
|
||||
Priority_Control ceiling_priority =
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
/*
|
||||
* Copyright (C) 2010 Gedare Bloom.
|
||||
* Copyright (C) 2011 On-Line Applications Research Corporation (OAR).
|
||||
* Copyright (c) 2014 embedded brains GmbH
|
||||
* Copyright (c) 2014-2015 embedded brains GmbH
|
||||
*
|
||||
* The license and distribution terms for this file may be
|
||||
* found in the file LICENSE in this distribution or at
|
||||
@@ -950,6 +950,26 @@ void _Scheduler_Thread_change_resource_root(
|
||||
Thread_Control *root
|
||||
);
|
||||
|
||||
RTEMS_INLINE_ROUTINE void _Scheduler_Set_idle_thread(
|
||||
Scheduler_Node *node,
|
||||
Thread_Control *idle
|
||||
)
|
||||
{
|
||||
_Assert(
|
||||
node->help_state == SCHEDULER_HELP_ACTIVE_OWNER
|
||||
|| node->help_state == SCHEDULER_HELP_ACTIVE_RIVAL
|
||||
);
|
||||
_Assert( _Scheduler_Node_get_idle( node ) == NULL );
|
||||
_Assert(
|
||||
_Scheduler_Node_get_owner( node ) == _Scheduler_Node_get_user( node )
|
||||
);
|
||||
|
||||
_Scheduler_Thread_set_node( idle, node );
|
||||
|
||||
_Scheduler_Node_set_user( node, idle );
|
||||
node->idle = idle;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Use an idle thread for this scheduler node.
|
||||
*
|
||||
@@ -970,45 +990,44 @@ RTEMS_INLINE_ROUTINE Thread_Control *_Scheduler_Use_idle_thread(
|
||||
{
|
||||
Thread_Control *idle = ( *get_idle_thread )( context );
|
||||
|
||||
_Assert(
|
||||
node->help_state == SCHEDULER_HELP_ACTIVE_OWNER
|
||||
|| node->help_state == SCHEDULER_HELP_ACTIVE_RIVAL
|
||||
);
|
||||
_Assert( _Scheduler_Node_get_idle( node ) == NULL );
|
||||
_Assert(
|
||||
_Scheduler_Node_get_owner( node ) == _Scheduler_Node_get_user( node )
|
||||
);
|
||||
|
||||
_Scheduler_Thread_set_node( idle, node );
|
||||
|
||||
_Scheduler_Node_set_user( node, idle );
|
||||
node->idle = idle;
|
||||
_Scheduler_Set_idle_thread( node, idle );
|
||||
|
||||
return idle;
|
||||
}
|
||||
|
||||
typedef enum {
|
||||
SCHEDULER_TRY_TO_SCHEDULE_DO_SCHEDULE,
|
||||
SCHEDULER_TRY_TO_SCHEDULE_DO_IDLE_EXCHANGE,
|
||||
SCHEDULER_TRY_TO_SCHEDULE_DO_BLOCK
|
||||
} Scheduler_Try_to_schedule_action;
|
||||
|
||||
/**
|
||||
* @brief Try to schedule this scheduler node.
|
||||
*
|
||||
* @param[in] context The scheduler instance context.
|
||||
* @param[in] node The node which wants to get scheduled.
|
||||
* @param[in] idle A potential idle thread used by a potential victim node.
|
||||
* @param[in] get_idle_thread Function to get an idle thread.
|
||||
*
|
||||
* @retval true This node can be scheduled.
|
||||
* @retval false Otherwise.
|
||||
*/
|
||||
RTEMS_INLINE_ROUTINE bool _Scheduler_Try_to_schedule_node(
|
||||
RTEMS_INLINE_ROUTINE Scheduler_Try_to_schedule_action
|
||||
_Scheduler_Try_to_schedule_node(
|
||||
Scheduler_Context *context,
|
||||
Scheduler_Node *node,
|
||||
Thread_Control *idle,
|
||||
Scheduler_Get_idle_thread get_idle_thread
|
||||
)
|
||||
{
|
||||
bool schedule;
|
||||
Scheduler_Try_to_schedule_action action;
|
||||
Thread_Control *owner;
|
||||
Thread_Control *user;
|
||||
|
||||
action = SCHEDULER_TRY_TO_SCHEDULE_DO_SCHEDULE;
|
||||
|
||||
if ( node->help_state == SCHEDULER_HELP_YOURSELF ) {
|
||||
return true;
|
||||
return action;
|
||||
}
|
||||
|
||||
owner = _Scheduler_Node_get_owner( node );
|
||||
@@ -1018,32 +1037,33 @@ RTEMS_INLINE_ROUTINE bool _Scheduler_Try_to_schedule_node(
|
||||
if ( user->Scheduler.state == THREAD_SCHEDULER_READY ) {
|
||||
_Scheduler_Thread_set_scheduler_and_node( user, node, owner );
|
||||
} else if ( owner->Scheduler.state == THREAD_SCHEDULER_BLOCKED ) {
|
||||
_Scheduler_Use_idle_thread( context, node, get_idle_thread );
|
||||
if ( idle != NULL ) {
|
||||
action = SCHEDULER_TRY_TO_SCHEDULE_DO_IDLE_EXCHANGE;
|
||||
} else {
|
||||
_Scheduler_Use_idle_thread( context, node, get_idle_thread );
|
||||
}
|
||||
} else {
|
||||
_Scheduler_Node_set_user( node, owner );
|
||||
}
|
||||
|
||||
schedule = true;
|
||||
} else if ( node->help_state == SCHEDULER_HELP_ACTIVE_OWNER ) {
|
||||
if ( user->Scheduler.state == THREAD_SCHEDULER_READY ) {
|
||||
_Scheduler_Thread_set_scheduler_and_node( user, node, owner );
|
||||
} else if ( idle != NULL ) {
|
||||
action = SCHEDULER_TRY_TO_SCHEDULE_DO_IDLE_EXCHANGE;
|
||||
} else {
|
||||
_Scheduler_Use_idle_thread( context, node, get_idle_thread );
|
||||
}
|
||||
|
||||
schedule = true;
|
||||
} else {
|
||||
_Assert( node->help_state == SCHEDULER_HELP_PASSIVE );
|
||||
|
||||
if ( user->Scheduler.state == THREAD_SCHEDULER_READY ) {
|
||||
_Scheduler_Thread_set_scheduler_and_node( user, node, owner );
|
||||
schedule = true;
|
||||
} else {
|
||||
schedule = false;
|
||||
action = SCHEDULER_TRY_TO_SCHEDULE_DO_BLOCK;
|
||||
}
|
||||
}
|
||||
|
||||
return schedule;
|
||||
return action;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1078,6 +1098,20 @@ RTEMS_INLINE_ROUTINE Thread_Control *_Scheduler_Release_idle_thread(
|
||||
return idle;
|
||||
}
|
||||
|
||||
RTEMS_INLINE_ROUTINE void _Scheduler_Exchange_idle_thread(
|
||||
Scheduler_Node *needs_idle,
|
||||
Scheduler_Node *uses_idle,
|
||||
Thread_Control *idle
|
||||
)
|
||||
{
|
||||
uses_idle->idle = NULL;
|
||||
_Scheduler_Node_set_user(
|
||||
uses_idle,
|
||||
_Scheduler_Node_get_owner( uses_idle )
|
||||
);
|
||||
_Scheduler_Set_idle_thread( needs_idle, idle );
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Block this scheduler node.
|
||||
*
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (c) 2013-2014 embedded brains GmbH. All rights reserved.
|
||||
* Copyright (c) 2013-2015 embedded brains GmbH. All rights reserved.
|
||||
*
|
||||
* embedded brains GmbH
|
||||
* Dornierstr. 4
|
||||
@@ -532,41 +532,76 @@ static inline Thread_Control *_Scheduler_SMP_Enqueue_to_scheduled(
|
||||
Scheduler_SMP_Allocate_processor allocate_processor
|
||||
)
|
||||
{
|
||||
Thread_Control *user = _Scheduler_Node_get_user( node );
|
||||
Thread_Control *lowest_scheduled_user =
|
||||
_Scheduler_Node_get_user( lowest_scheduled );
|
||||
Thread_Control *needs_help;
|
||||
Thread_Control *idle;
|
||||
Scheduler_Try_to_schedule_action action;
|
||||
|
||||
_Scheduler_SMP_Node_change_state(
|
||||
_Scheduler_SMP_Node_downcast( lowest_scheduled ),
|
||||
SCHEDULER_SMP_NODE_READY
|
||||
);
|
||||
_Scheduler_Thread_change_state(
|
||||
lowest_scheduled_user,
|
||||
THREAD_SCHEDULER_READY
|
||||
);
|
||||
|
||||
_Scheduler_Thread_set_node( user, node );
|
||||
|
||||
_Scheduler_SMP_Allocate_processor(
|
||||
action = _Scheduler_Try_to_schedule_node(
|
||||
context,
|
||||
node,
|
||||
lowest_scheduled,
|
||||
allocate_processor
|
||||
_Scheduler_Node_get_idle( lowest_scheduled ),
|
||||
_Scheduler_SMP_Get_idle_thread
|
||||
);
|
||||
|
||||
( *insert_scheduled )( context, node );
|
||||
( *move_from_scheduled_to_ready )( context, lowest_scheduled );
|
||||
if ( action == SCHEDULER_TRY_TO_SCHEDULE_DO_SCHEDULE ) {
|
||||
Thread_Control *lowest_scheduled_user =
|
||||
_Scheduler_Node_get_user( lowest_scheduled );
|
||||
Thread_Control *idle;
|
||||
|
||||
idle = _Scheduler_Release_idle_thread(
|
||||
context,
|
||||
lowest_scheduled,
|
||||
_Scheduler_SMP_Release_idle_thread
|
||||
);
|
||||
if ( idle == NULL ) {
|
||||
needs_help = lowest_scheduled_user;
|
||||
_Scheduler_SMP_Node_change_state(
|
||||
_Scheduler_SMP_Node_downcast( lowest_scheduled ),
|
||||
SCHEDULER_SMP_NODE_READY
|
||||
);
|
||||
_Scheduler_Thread_change_state(
|
||||
lowest_scheduled_user,
|
||||
THREAD_SCHEDULER_READY
|
||||
);
|
||||
|
||||
_Scheduler_SMP_Allocate_processor(
|
||||
context,
|
||||
node,
|
||||
lowest_scheduled,
|
||||
allocate_processor
|
||||
);
|
||||
|
||||
( *insert_scheduled )( context, node );
|
||||
( *move_from_scheduled_to_ready )( context, lowest_scheduled );
|
||||
|
||||
idle = _Scheduler_Release_idle_thread(
|
||||
context,
|
||||
lowest_scheduled,
|
||||
_Scheduler_SMP_Release_idle_thread
|
||||
);
|
||||
if ( idle == NULL ) {
|
||||
needs_help = lowest_scheduled_user;
|
||||
} else {
|
||||
needs_help = NULL;
|
||||
}
|
||||
} else if ( action == SCHEDULER_TRY_TO_SCHEDULE_DO_IDLE_EXCHANGE ) {
|
||||
_Scheduler_SMP_Node_change_state(
|
||||
_Scheduler_SMP_Node_downcast( lowest_scheduled ),
|
||||
SCHEDULER_SMP_NODE_READY
|
||||
);
|
||||
_Scheduler_SMP_Node_change_state(
|
||||
_Scheduler_SMP_Node_downcast( node ),
|
||||
SCHEDULER_SMP_NODE_SCHEDULED
|
||||
);
|
||||
|
||||
( *insert_scheduled )( context, node );
|
||||
( *move_from_scheduled_to_ready )( context, lowest_scheduled );
|
||||
|
||||
_Scheduler_Exchange_idle_thread(
|
||||
node,
|
||||
lowest_scheduled,
|
||||
_Scheduler_Node_get_idle( lowest_scheduled )
|
||||
);
|
||||
|
||||
needs_help = NULL;
|
||||
} else {
|
||||
_Assert( action == SCHEDULER_TRY_TO_SCHEDULE_DO_BLOCK );
|
||||
_Scheduler_SMP_Node_change_state(
|
||||
_Scheduler_SMP_Node_downcast( node ),
|
||||
SCHEDULER_SMP_NODE_BLOCKED
|
||||
);
|
||||
needs_help = NULL;
|
||||
}
|
||||
|
||||
@@ -660,7 +695,7 @@ static inline Thread_Control *_Scheduler_SMP_Enqueue_scheduled_ordered(
|
||||
{
|
||||
Thread_Control *needs_help;
|
||||
|
||||
while ( true ) {
|
||||
do {
|
||||
Scheduler_Node *highest_ready = ( *get_highest_ready )( context, node );
|
||||
|
||||
/*
|
||||
@@ -671,55 +706,80 @@ static inline Thread_Control *_Scheduler_SMP_Enqueue_scheduled_ordered(
|
||||
( *insert_scheduled )( context, node );
|
||||
|
||||
needs_help = NULL;
|
||||
|
||||
break;
|
||||
} else if (
|
||||
_Scheduler_Try_to_schedule_node(
|
||||
context,
|
||||
highest_ready,
|
||||
_Scheduler_SMP_Get_idle_thread
|
||||
)
|
||||
) {
|
||||
Thread_Control *user = _Scheduler_Node_get_user( node );
|
||||
Thread_Control *idle;
|
||||
|
||||
_Scheduler_SMP_Node_change_state(
|
||||
_Scheduler_SMP_Node_downcast( node ),
|
||||
SCHEDULER_SMP_NODE_READY
|
||||
);
|
||||
_Scheduler_Thread_change_state( user, THREAD_SCHEDULER_READY );
|
||||
|
||||
_Scheduler_SMP_Allocate_processor(
|
||||
context,
|
||||
highest_ready,
|
||||
node,
|
||||
allocate_processor
|
||||
);
|
||||
|
||||
( *insert_ready )( context, node );
|
||||
( *move_from_ready_to_scheduled )( context, highest_ready );
|
||||
|
||||
idle = _Scheduler_Release_idle_thread(
|
||||
context,
|
||||
node,
|
||||
_Scheduler_SMP_Release_idle_thread
|
||||
);
|
||||
if ( idle == NULL ) {
|
||||
needs_help = user;
|
||||
} else {
|
||||
needs_help = NULL;
|
||||
}
|
||||
|
||||
break;
|
||||
} else {
|
||||
_Scheduler_SMP_Node_change_state(
|
||||
_Scheduler_SMP_Node_downcast( highest_ready ),
|
||||
SCHEDULER_SMP_NODE_BLOCKED
|
||||
Scheduler_Try_to_schedule_action action;
|
||||
|
||||
action = _Scheduler_Try_to_schedule_node(
|
||||
context,
|
||||
highest_ready,
|
||||
_Scheduler_Node_get_idle( node ),
|
||||
_Scheduler_SMP_Get_idle_thread
|
||||
);
|
||||
|
||||
( *extract_from_ready )( context, highest_ready );
|
||||
if ( action == SCHEDULER_TRY_TO_SCHEDULE_DO_SCHEDULE ) {
|
||||
Thread_Control *user = _Scheduler_Node_get_user( node );
|
||||
Thread_Control *idle;
|
||||
|
||||
_Scheduler_SMP_Node_change_state(
|
||||
_Scheduler_SMP_Node_downcast( node ),
|
||||
SCHEDULER_SMP_NODE_READY
|
||||
);
|
||||
_Scheduler_Thread_change_state( user, THREAD_SCHEDULER_READY );
|
||||
|
||||
_Scheduler_SMP_Allocate_processor(
|
||||
context,
|
||||
highest_ready,
|
||||
node,
|
||||
allocate_processor
|
||||
);
|
||||
|
||||
( *insert_ready )( context, node );
|
||||
( *move_from_ready_to_scheduled )( context, highest_ready );
|
||||
|
||||
idle = _Scheduler_Release_idle_thread(
|
||||
context,
|
||||
node,
|
||||
_Scheduler_SMP_Release_idle_thread
|
||||
);
|
||||
if ( idle == NULL ) {
|
||||
needs_help = user;
|
||||
} else {
|
||||
needs_help = NULL;
|
||||
}
|
||||
} else if ( action == SCHEDULER_TRY_TO_SCHEDULE_DO_IDLE_EXCHANGE ) {
|
||||
_Scheduler_SMP_Node_change_state(
|
||||
_Scheduler_SMP_Node_downcast( node ),
|
||||
SCHEDULER_SMP_NODE_READY
|
||||
);
|
||||
_Scheduler_SMP_Node_change_state(
|
||||
_Scheduler_SMP_Node_downcast( highest_ready ),
|
||||
SCHEDULER_SMP_NODE_SCHEDULED
|
||||
);
|
||||
|
||||
( *insert_ready )( context, node );
|
||||
( *move_from_ready_to_scheduled )( context, highest_ready );
|
||||
|
||||
_Scheduler_Exchange_idle_thread(
|
||||
highest_ready,
|
||||
node,
|
||||
_Scheduler_Node_get_idle( node )
|
||||
);
|
||||
|
||||
needs_help = NULL;
|
||||
} else {
|
||||
_Assert( action == SCHEDULER_TRY_TO_SCHEDULE_DO_BLOCK );
|
||||
|
||||
_Scheduler_SMP_Node_change_state(
|
||||
_Scheduler_SMP_Node_downcast( highest_ready ),
|
||||
SCHEDULER_SMP_NODE_BLOCKED
|
||||
);
|
||||
|
||||
( *extract_from_ready )( context, highest_ready );
|
||||
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
} while ( false );
|
||||
|
||||
return needs_help;
|
||||
}
|
||||
@@ -740,16 +800,18 @@ static inline void _Scheduler_SMP_Schedule_highest_ready(
|
||||
Scheduler_SMP_Allocate_processor allocate_processor
|
||||
)
|
||||
{
|
||||
while ( true ) {
|
||||
do {
|
||||
Scheduler_Node *highest_ready = ( *get_highest_ready )( context, victim );
|
||||
Scheduler_Try_to_schedule_action action;
|
||||
|
||||
if (
|
||||
_Scheduler_Try_to_schedule_node(
|
||||
context,
|
||||
highest_ready,
|
||||
_Scheduler_SMP_Get_idle_thread
|
||||
)
|
||||
) {
|
||||
action = _Scheduler_Try_to_schedule_node(
|
||||
context,
|
||||
highest_ready,
|
||||
NULL,
|
||||
_Scheduler_SMP_Get_idle_thread
|
||||
);
|
||||
|
||||
if ( action == SCHEDULER_TRY_TO_SCHEDULE_DO_SCHEDULE ) {
|
||||
_Scheduler_SMP_Allocate_processor(
|
||||
context,
|
||||
highest_ready,
|
||||
@@ -758,17 +820,19 @@ static inline void _Scheduler_SMP_Schedule_highest_ready(
|
||||
);
|
||||
|
||||
( *move_from_ready_to_scheduled )( context, highest_ready );
|
||||
|
||||
break;
|
||||
} else {
|
||||
_Assert( action == SCHEDULER_TRY_TO_SCHEDULE_DO_BLOCK );
|
||||
|
||||
_Scheduler_SMP_Node_change_state(
|
||||
_Scheduler_SMP_Node_downcast( highest_ready ),
|
||||
SCHEDULER_SMP_NODE_BLOCKED
|
||||
);
|
||||
|
||||
( *extract_from_ready )( context, highest_ready );
|
||||
|
||||
continue;
|
||||
}
|
||||
}
|
||||
} while ( false );
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2014 embedded brains GmbH. All rights reserved.
|
||||
* Copyright (c) 2014-2015 embedded brains GmbH. All rights reserved.
|
||||
*
|
||||
* embedded brains GmbH
|
||||
* Dornierstr. 4
|
||||
@@ -74,7 +74,6 @@ typedef struct {
|
||||
} test_context;
|
||||
|
||||
static test_context test_instance = {
|
||||
.barrier = SMP_BARRIER_CONTROL_INITIALIZER,
|
||||
.switch_lock = SMP_LOCK_INITIALIZER("test instance switch lock")
|
||||
};
|
||||
|
||||
@@ -87,6 +86,11 @@ static void busy_wait(void)
|
||||
}
|
||||
}
|
||||
|
||||
static void barrier_init(test_context *ctx)
|
||||
{
|
||||
_SMP_barrier_Control_initialize(&ctx->barrier);
|
||||
}
|
||||
|
||||
static void barrier(test_context *ctx, SMP_barrier_State *bs)
|
||||
{
|
||||
_SMP_barrier_Wait(&ctx->barrier, bs, 2);
|
||||
@@ -291,6 +295,7 @@ static void test_mrsp_obtain_and_release(test_context *ctx)
|
||||
|
||||
change_prio(RTEMS_SELF, 3);
|
||||
|
||||
barrier_init(ctx);
|
||||
reset_switch_events(ctx);
|
||||
|
||||
ctx->high_run[0] = false;
|
||||
@@ -467,6 +472,219 @@ static void test_mrsp_obtain_and_release(test_context *ctx)
|
||||
rtems_test_assert(sc == RTEMS_SUCCESSFUL);
|
||||
}
|
||||
|
||||
static void obtain_after_migration_worker(rtems_task_argument arg)
|
||||
{
|
||||
test_context *ctx = &test_instance;
|
||||
rtems_status_code sc;
|
||||
SMP_barrier_State barrier_state = SMP_BARRIER_STATE_INITIALIZER;
|
||||
|
||||
assert_prio(RTEMS_SELF, 3);
|
||||
|
||||
sc = rtems_semaphore_obtain(ctx->mrsp_ids[0], RTEMS_WAIT, RTEMS_NO_TIMEOUT);
|
||||
rtems_test_assert(sc == RTEMS_SUCCESSFUL);
|
||||
|
||||
sc = rtems_semaphore_release(ctx->mrsp_ids[0]);
|
||||
rtems_test_assert(sc == RTEMS_SUCCESSFUL);
|
||||
|
||||
/* Worker done (K) */
|
||||
barrier(ctx, &barrier_state);
|
||||
|
||||
while (true) {
|
||||
/* Wait for termination */
|
||||
}
|
||||
}
|
||||
|
||||
static void obtain_after_migration_high(rtems_task_argument arg)
|
||||
{
|
||||
test_context *ctx = &test_instance;
|
||||
rtems_status_code sc;
|
||||
SMP_barrier_State barrier_state = SMP_BARRIER_STATE_INITIALIZER;
|
||||
|
||||
assert_prio(RTEMS_SELF, 2);
|
||||
|
||||
sc = rtems_semaphore_obtain(ctx->mrsp_ids[1], RTEMS_WAIT, RTEMS_NO_TIMEOUT);
|
||||
rtems_test_assert(sc == RTEMS_SUCCESSFUL);
|
||||
|
||||
/* Obtain done (I) */
|
||||
barrier(ctx, &barrier_state);
|
||||
|
||||
/* Ready to release (J) */
|
||||
barrier(ctx, &barrier_state);
|
||||
|
||||
sc = rtems_semaphore_release(ctx->mrsp_ids[1]);
|
||||
rtems_test_assert(sc == RTEMS_SUCCESSFUL);
|
||||
|
||||
rtems_task_suspend(RTEMS_SELF);
|
||||
rtems_test_assert(0);
|
||||
}
|
||||
|
||||
static void test_mrsp_obtain_after_migration(test_context *ctx)
|
||||
{
|
||||
rtems_status_code sc;
|
||||
rtems_task_priority prio;
|
||||
rtems_id scheduler_id;
|
||||
SMP_barrier_State barrier_state;
|
||||
|
||||
puts("test MrsP obtain after migration");
|
||||
|
||||
change_prio(RTEMS_SELF, 3);
|
||||
|
||||
barrier_init(ctx);
|
||||
reset_switch_events(ctx);
|
||||
|
||||
/* Create tasks */
|
||||
|
||||
sc = rtems_task_create(
|
||||
rtems_build_name('H', 'I', 'G', '0'),
|
||||
2,
|
||||
RTEMS_MINIMUM_STACK_SIZE,
|
||||
RTEMS_DEFAULT_MODES,
|
||||
RTEMS_DEFAULT_ATTRIBUTES,
|
||||
&ctx->high_task_id[0]
|
||||
);
|
||||
rtems_test_assert(sc == RTEMS_SUCCESSFUL);
|
||||
|
||||
sc = rtems_task_create(
|
||||
rtems_build_name('W', 'O', 'R', 'K'),
|
||||
3,
|
||||
RTEMS_MINIMUM_STACK_SIZE,
|
||||
RTEMS_DEFAULT_MODES,
|
||||
RTEMS_DEFAULT_ATTRIBUTES,
|
||||
&ctx->worker_ids[0]
|
||||
);
|
||||
rtems_test_assert(sc == RTEMS_SUCCESSFUL);
|
||||
|
||||
sc = rtems_task_set_scheduler(ctx->worker_ids[0], ctx->scheduler_ids[1]);
|
||||
rtems_test_assert(sc == RTEMS_SUCCESSFUL);
|
||||
|
||||
/* Create a MrsP semaphore objects */
|
||||
|
||||
sc = rtems_semaphore_create(
|
||||
rtems_build_name('M', 'R', 'S', 'P'),
|
||||
1,
|
||||
RTEMS_MULTIPROCESSOR_RESOURCE_SHARING
|
||||
| RTEMS_BINARY_SEMAPHORE,
|
||||
3,
|
||||
&ctx->mrsp_ids[0]
|
||||
);
|
||||
rtems_test_assert(sc == RTEMS_SUCCESSFUL);
|
||||
|
||||
sc = rtems_semaphore_create(
|
||||
rtems_build_name('M', 'R', 'S', 'P'),
|
||||
1,
|
||||
RTEMS_MULTIPROCESSOR_RESOURCE_SHARING
|
||||
| RTEMS_BINARY_SEMAPHORE,
|
||||
2,
|
||||
&ctx->mrsp_ids[1]
|
||||
);
|
||||
rtems_test_assert(sc == RTEMS_SUCCESSFUL);
|
||||
|
||||
sc = rtems_semaphore_create(
|
||||
rtems_build_name('M', 'R', 'S', 'P'),
|
||||
1,
|
||||
RTEMS_MULTIPROCESSOR_RESOURCE_SHARING
|
||||
| RTEMS_BINARY_SEMAPHORE,
|
||||
1,
|
||||
&ctx->mrsp_ids[2]
|
||||
);
|
||||
rtems_test_assert(sc == RTEMS_SUCCESSFUL);
|
||||
|
||||
prio = 4;
|
||||
sc = rtems_semaphore_set_priority(
|
||||
ctx->mrsp_ids[2],
|
||||
ctx->scheduler_ids[1],
|
||||
prio,
|
||||
&prio
|
||||
);
|
||||
rtems_test_assert(sc == RTEMS_SUCCESSFUL);
|
||||
rtems_test_assert(prio == 1);
|
||||
|
||||
/* Check executing task parameters */
|
||||
|
||||
sc = rtems_task_get_scheduler(RTEMS_SELF, &scheduler_id);
|
||||
rtems_test_assert(sc == RTEMS_SUCCESSFUL);
|
||||
|
||||
rtems_test_assert(ctx->scheduler_ids[0] == scheduler_id);
|
||||
|
||||
assert_prio(RTEMS_SELF, 3);
|
||||
|
||||
sc = rtems_semaphore_obtain(ctx->mrsp_ids[0], RTEMS_WAIT, RTEMS_NO_TIMEOUT);
|
||||
rtems_test_assert(sc == RTEMS_SUCCESSFUL);
|
||||
|
||||
assert_prio(RTEMS_SELF, 3);
|
||||
|
||||
/* Start other tasks */
|
||||
|
||||
sc = rtems_task_start(ctx->worker_ids[0], obtain_after_migration_worker, 0);
|
||||
rtems_test_assert(sc == RTEMS_SUCCESSFUL);
|
||||
|
||||
sc = rtems_task_start(ctx->high_task_id[0], obtain_after_migration_high, 0);
|
||||
rtems_test_assert(sc == RTEMS_SUCCESSFUL);
|
||||
|
||||
rtems_test_assert(rtems_get_current_processor() == 1);
|
||||
|
||||
/* Obtain done (I) */
|
||||
_SMP_barrier_State_initialize(&barrier_state);
|
||||
barrier(ctx, &barrier_state);
|
||||
|
||||
sc = rtems_task_suspend(ctx->high_task_id[0]);
|
||||
rtems_test_assert(sc == RTEMS_SUCCESSFUL);
|
||||
|
||||
rtems_test_assert(rtems_get_current_processor() == 1);
|
||||
|
||||
/*
|
||||
* Obtain second MrsP semaphore and ensure that we change the priority of our
|
||||
* own scheduler node and not the one we are currently using.
|
||||
*/
|
||||
|
||||
sc = rtems_semaphore_obtain(ctx->mrsp_ids[2], RTEMS_WAIT, RTEMS_NO_TIMEOUT);
|
||||
rtems_test_assert(sc == RTEMS_SUCCESSFUL);
|
||||
|
||||
assert_prio(RTEMS_SELF, 1);
|
||||
|
||||
rtems_test_assert(rtems_get_current_processor() == 1);
|
||||
|
||||
sc = rtems_semaphore_release(ctx->mrsp_ids[2]);
|
||||
rtems_test_assert(sc == RTEMS_SUCCESSFUL);
|
||||
|
||||
sc = rtems_task_resume(ctx->high_task_id[0]);
|
||||
rtems_test_assert(sc == RTEMS_SUCCESSFUL);
|
||||
|
||||
/* Ready to release (J) */
|
||||
barrier(ctx, &barrier_state);
|
||||
|
||||
rtems_test_assert(rtems_get_current_processor() == 1);
|
||||
|
||||
/* Prepare barrier for worker */
|
||||
barrier_init(ctx);
|
||||
_SMP_barrier_State_initialize(&barrier_state);
|
||||
|
||||
sc = rtems_semaphore_release(ctx->mrsp_ids[0]);
|
||||
rtems_test_assert(sc == RTEMS_SUCCESSFUL);
|
||||
|
||||
rtems_test_assert(rtems_get_current_processor() == 0);
|
||||
|
||||
print_switch_events(ctx);
|
||||
|
||||
/* Worker done (K) */
|
||||
barrier(ctx, &barrier_state);
|
||||
|
||||
sc = rtems_task_delete(ctx->worker_ids[0]);
|
||||
rtems_test_assert(sc == RTEMS_SUCCESSFUL);
|
||||
|
||||
sc = rtems_task_delete(ctx->high_task_id[0]);
|
||||
rtems_test_assert(sc == RTEMS_SUCCESSFUL);
|
||||
|
||||
sc = rtems_semaphore_delete(ctx->mrsp_ids[0]);
|
||||
rtems_test_assert(sc == RTEMS_SUCCESSFUL);
|
||||
|
||||
sc = rtems_semaphore_delete(ctx->mrsp_ids[1]);
|
||||
rtems_test_assert(sc == RTEMS_SUCCESSFUL);
|
||||
|
||||
sc = rtems_semaphore_delete(ctx->mrsp_ids[2]);
|
||||
rtems_test_assert(sc == RTEMS_SUCCESSFUL);
|
||||
}
|
||||
|
||||
static void test_mrsp_flush_error(void)
|
||||
{
|
||||
rtems_status_code sc;
|
||||
@@ -1034,6 +1252,7 @@ static void test_mrsp_various_block_and_unblock(test_context *ctx)
|
||||
|
||||
change_prio(RTEMS_SELF, 4);
|
||||
|
||||
barrier_init(ctx);
|
||||
reset_switch_events(ctx);
|
||||
|
||||
ctx->low_run[0] = false;
|
||||
@@ -1637,6 +1856,7 @@ static void Init(rtems_task_argument arg)
|
||||
test_mrsp_deadlock_error(ctx);
|
||||
test_mrsp_multiple_obtain();
|
||||
test_mrsp_various_block_and_unblock(ctx);
|
||||
test_mrsp_obtain_after_migration(ctx);
|
||||
test_mrsp_obtain_and_sleep_and_release(ctx);
|
||||
test_mrsp_obtain_and_release_with_help(ctx);
|
||||
test_mrsp_obtain_and_release(ctx);
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user