summaryrefslogtreecommitdiffstats
path: root/testsuites/validation/tc-sched-smp.c
diff options
context:
space:
mode:
Diffstat (limited to 'testsuites/validation/tc-sched-smp.c')
-rw-r--r--testsuites/validation/tc-sched-smp.c175
1 files changed, 158 insertions, 17 deletions
diff --git a/testsuites/validation/tc-sched-smp.c b/testsuites/validation/tc-sched-smp.c
index 957a978980..3e8e3fe1a2 100644
--- a/testsuites/validation/tc-sched-smp.c
+++ b/testsuites/validation/tc-sched-smp.c
@@ -3,11 +3,11 @@
/**
* @file
*
- * @ingroup RTEMSTestCaseScoreSchedSmpValSmp
+ * @ingroup ScoreSchedSmpValSmp
*/
/*
- * Copyright (C) 2021 embedded brains GmbH (http://www.embedded-brains.de)
+ * Copyright (C) 2021, 2022 embedded brains GmbH & Co. KG
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -55,6 +55,7 @@
#include <rtems.h>
#include <rtems/test-scheduler.h>
#include <rtems/score/percpu.h>
+#include <rtems/score/schedulersmp.h>
#include <rtems/score/threadimpl.h>
#include "tx-support.h"
@@ -62,9 +63,9 @@
#include <rtems/test.h>
/**
- * @defgroup RTEMSTestCaseScoreSchedSmpValSmp spec:/score/sched/smp/val/smp
+ * @defgroup ScoreSchedSmpValSmp spec:/score/sched/smp/val/smp
*
- * @ingroup RTEMSTestSuiteTestsuitesValidationSmpOnly0
+ * @ingroup TestsuitesValidationSmpOnly0
*
* @brief Tests SMP-specific scheduler behaviour.
*
@@ -213,6 +214,24 @@
*
* - Clean up all used resources.
*
+ * - Create three worker threads and a mutex. Use the mutex and the worker to
+ * check that a not scheduled thread does not get removed from the set of
+ * ready threads of a scheduler when a help request is reconsidered.
+ *
+ * - Prevent that worker B can perform a post-switch cleanup.
+ *
+ * - Give worker C a lower priority than worker B. Worker B will try to
+ * finish the thread dispatch by doing a post-switch cleanup. The
+ * post-switch cleanup cannot progress since the runner owns the thread
+ * state lock. Wait until the other processor waits on the thread state
+ * lock of worker B.
+ *
+ * - Give worker C a higher priority than worker B. Let worker B do its
+ * post-switch cleanup which will carry out the reconsider help requests
+ * for a not scheduled thread.
+ *
+ * - Clean up all used resources.
+ *
* @{
*/
@@ -250,12 +269,22 @@ typedef struct {
/**
* @brief This member contains the worker busy status.
*/
- volatile bool busy[ WORKER_COUNT ];;
+ volatile bool busy[ WORKER_COUNT ];
+
+ /**
+ * @brief This member contains an ISR lock context.
+ */
+ ISR_lock_Context lock_context;
+
+ /**
+ * @brief This member contains a counter.
+ */
+ uint32_t counter;
/**
* @brief If this member is true, then the worker shall be in the busy loop.
*/
- volatile bool is_busy[ WORKER_COUNT ];;
+ volatile bool is_busy[ WORKER_COUNT ];
/**
* @brief This member contains the per-CPU jobs.
@@ -270,24 +299,31 @@ typedef struct {
/**
* @brief This member contains the call within ISR request.
*/
- CallWithinISRRequest request;;
+ CallWithinISRRequest request;
} ScoreSchedSmpValSmp_Context;
static ScoreSchedSmpValSmp_Context
ScoreSchedSmpValSmp_Instance;
+#define EVENT_OBTAIN RTEMS_EVENT_0
+
+#define EVENT_RELEASE RTEMS_EVENT_1
+
+#define EVENT_STICKY_OBTAIN RTEMS_EVENT_2
+
+#define EVENT_STICKY_RELEASE RTEMS_EVENT_3
+
+#define EVENT_SYNC_RUNNER RTEMS_EVENT_4
+
+#define EVENT_BUSY RTEMS_EVENT_5
+
typedef ScoreSchedSmpValSmp_Context Context;
-typedef enum {
- EVENT_OBTAIN = RTEMS_EVENT_0,
- EVENT_RELEASE = RTEMS_EVENT_1,
- EVENT_STICKY_OBTAIN = RTEMS_EVENT_2,
- EVENT_STICKY_RELEASE = RTEMS_EVENT_3,
- EVENT_SYNC_RUNNER = RTEMS_EVENT_4,
- EVENT_BUSY = RTEMS_EVENT_5
-} Event;
-
-static void SendAndSync( Context *ctx, WorkerIndex worker, Event event )
+static void SendAndSync(
+ Context *ctx,
+ WorkerIndex worker,
+ rtems_event_set event
+)
{
SendEvents( ctx->worker_id[ worker ], EVENT_SYNC_RUNNER | event );
ReceiveAllEvents( EVENT_SYNC_RUNNER );
@@ -649,6 +685,7 @@ static void PrepareOwnerScheduled( Context *ctx )
SetScheduler( ctx->worker_id[ WORKER_C ], SCHEDULER_B_ID, PRIO_HIGH );
SetPriority( ctx->worker_id[ WORKER_A ], PRIO_NORMAL );
MakeBusy( ctx, WORKER_C );
+ WaitForBusy( ctx, WORKER_C );
MakeBusy( ctx, WORKER_A );
}
@@ -686,6 +723,51 @@ static void CleanupOwnerBlocked( Context *ctx )
SetScheduler( ctx->worker_id[ WORKER_C ], SCHEDULER_A_ID, PRIO_HIGH );
}
+static void ReconsiderHelpRequestB(
+ void *arg,
+ const T_scheduler_event *event,
+ T_scheduler_when when
+)
+{
+ Context *ctx;
+
+ (void) when;
+ ctx = arg;
+
+ if ( event->operation == T_SCHEDULER_RECONSIDER_HELP_REQUEST ) {
+ Scheduler_SMP_Node *node;
+
+ node = (Scheduler_SMP_Node *) event->node;
+ T_eq_int( node->state, SCHEDULER_SMP_NODE_READY );
+ ++ctx->counter;
+ }
+}
+
+static void ReleaseThreadLockB(
+ void *arg,
+ const T_scheduler_event *event,
+ T_scheduler_when when
+)
+{
+ Context *ctx;
+
+ ctx = arg;
+
+ if (
+ when == T_SCHEDULER_AFTER &&
+ event->operation == T_SCHEDULER_UPDATE_PRIORITY
+ ) {
+ Thread_Control *worker_b;
+
+ T_scheduler_set_event_handler( ReconsiderHelpRequestB, ctx );
+
+ worker_b = GetThread( ctx->worker_id[ WORKER_B ] );
+ T_eq_int( worker_b->Scheduler.state, THREAD_SCHEDULER_READY );
+
+ _Thread_State_release_critical( worker_b, &ctx->lock_context );
+ }
+}
+
static void Worker( rtems_task_argument arg, WorkerIndex worker )
{
Context *ctx;
@@ -1233,6 +1315,64 @@ static void ScoreSchedSmpValSmp_Action_16( ScoreSchedSmpValSmp_Context *ctx )
}
/**
+ * @brief Create three worker threads and a mutex. Use the mutex and the
+ * worker to check that a not scheduled thread does not get removed from the
+ * set of ready threads of a scheduler when a help request is reconsidered.
+ */
+static void ScoreSchedSmpValSmp_Action_17( ScoreSchedSmpValSmp_Context *ctx )
+{
+ Thread_Control *worker_b;
+
+ SetScheduler( ctx->worker_id[ WORKER_B ], SCHEDULER_B_ID, PRIO_NORMAL );
+ SetScheduler( ctx->worker_id[ WORKER_C ], SCHEDULER_B_ID, PRIO_HIGH );
+ SendAndSync( ctx, WORKER_B, EVENT_OBTAIN );
+ SendEvents( ctx->worker_id[ WORKER_A ], EVENT_OBTAIN );
+ SetPriority( ctx->worker_id[ WORKER_A ], PRIO_LOW );
+ MakeBusy( ctx, WORKER_B );
+ WaitForBusy( ctx, WORKER_B );
+ MakeBusy( ctx, WORKER_C );
+ WaitForBusy( ctx, WORKER_C );
+
+ /*
+ * Prevent that worker B can perform a post-switch cleanup.
+ */
+ worker_b = GetThread( ctx->worker_id[ WORKER_B ] );
+ _Thread_State_acquire( worker_b, &ctx->lock_context );
+ _ISR_lock_ISR_enable( &ctx->lock_context );
+
+ /*
+ * Give worker C a lower priority than worker B. Worker B will try to finish
+ * the thread dispatch by doing a post-switch cleanup. The post-switch
+ * cleanup cannot progress since the runner owns the thread state lock. Wait
+ * until the other processor waits on the thread state lock of worker B.
+ */
+ SetPriority( ctx->worker_id[ WORKER_C ], PRIO_LOW );
+ TicketLockWaitForOthers( &worker_b->Join_queue.Queue.Lock, 1 );
+
+ /*
+ * Give worker C a higher priority than worker B. Let worker B do its
+ * post-switch cleanup which will carry out the reconsider help requests for
+ * a not scheduled thread.
+ */
+ ctx->counter = 0;
+ T_scheduler_set_event_handler( ReleaseThreadLockB, ctx );
+ SetPriority( ctx->worker_id[ WORKER_C ], PRIO_HIGH );
+ T_scheduler_set_event_handler( NULL, NULL );
+ T_eq_u32( ctx->counter, 4 );
+
+ /*
+ * Clean up all used resources.
+ */
+ StopBusy( ctx, WORKER_B );
+ StopBusy( ctx, WORKER_C );
+ SendAndSync( ctx, WORKER_B, EVENT_RELEASE );
+ SetPriority( ctx->worker_id[ WORKER_A ], PRIO_HIGH );
+ SendEvents( ctx->worker_id[ WORKER_A ], EVENT_RELEASE );
+ SetScheduler( ctx->worker_id[ WORKER_B ], SCHEDULER_A_ID, PRIO_HIGH );
+ SetScheduler( ctx->worker_id[ WORKER_C ], SCHEDULER_A_ID, PRIO_HIGH );
+}
+
+/**
* @fn void T_case_body_ScoreSchedSmpValSmp( void )
*/
T_TEST_CASE_FIXTURE( ScoreSchedSmpValSmp, &ScoreSchedSmpValSmp_Fixture )
@@ -1258,6 +1398,7 @@ T_TEST_CASE_FIXTURE( ScoreSchedSmpValSmp, &ScoreSchedSmpValSmp_Fixture )
ScoreSchedSmpValSmp_Action_14( ctx );
ScoreSchedSmpValSmp_Action_15( ctx );
ScoreSchedSmpValSmp_Action_16( ctx );
+ ScoreSchedSmpValSmp_Action_17( ctx );
}
/** @} */